<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Paige Niedringhaus RSS feed</title><description>Paige Niedringhaus is a full stack software engineer with a focus on frontend development.</description><link>https://www.paigeniedringhaus.com/</link><language>en-us</language><item><title>Getting the Most out of Claude Code</title><link>https://www.paigeniedringhaus.com/blog/getting-the-most-out-of-claude-code/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/getting-the-most-out-of-claude-code/</guid><description>After 6+ months with Claude as my coding copilot, I&apos;ve learned some helpful things.</description><pubDate>Sat, 06 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/claude-code-hero.png&quot; alt=&quot;Claude Code and coding monitor displayed on side by side computer monitors on a desk&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;When AI coding assistants first emerged a few years ago they were less than impressive for doing much beyond basic autocomplete tasks.&lt;/p&gt;
&lt;p&gt;But then things started to pick up in late 2023 and 2024 when GitHub Copilot Chat hit the scene, Devin AI caused a stir, and finally, Claude and Claude Code began to really win the hearts and minds of web developers and software engineers of all stripes.&lt;/p&gt;
&lt;p&gt;Like many of you, I was skeptical of the AI agents at first. GitHub Copilot Chat many times, failed to grasp the basic context or even understand simple code patterns within the file it was told to modify, Devin was eager but again, was ham fisted in its actual code implementation (and difficult to guide via Slack conversation threads), and my initial attempts with Claude resulted in lost time, tokens, and unwieldy amounts of spaghetti code that I ultimately threw away to start over.&lt;/p&gt;
&lt;p&gt;Over the past 6+ months, however, I&apos;ve been working with Claude Code, Anthropic&apos;s terminal-based AI coding assistant (and believe me, I&apos;ve never been a terminal dev, IDEs like VS Code are my coding happy place), and learned how to be much more effective when dealing with Claude.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article I&apos;m going to share with you the techniques I&apos;ve learned to get the most out of Claude Code and deliver high quality code and features in shorter amounts of time, because like it or not, AI-assisted coding is the future for us all.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Claude Code&lt;/h2&gt;
&lt;p&gt;The terminal has never been my favorite. I know enough bash to be dangerous and have my go to git commands memorized by heart, but give me a feature-rich, extension-packed IDE like VS Code any day, and I&apos;m off to the races (which probably makes sense since the parts of web development I enjoy most are frontend-focused features).&lt;/p&gt;
&lt;p&gt;But &lt;a href=&quot;https://www.claude.com/product/claude-code&quot;&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/a&gt; began life as a terminal-only CLI, and I have to say I&apos;ve gotten quite used to having it open and doing its thing in one terminal window (I use &lt;a href=&quot;https://www.warp.dev/&quot;&gt;Warp&lt;/a&gt; as my preferred terminal), and VS Code open at the same time so I can follow along with the file changes taking place, run the dev server or tests myself, and point out linting and TypeScript errors that Claude might be ignoring or glossing over in an attempt to always be right the first time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Since Claude Code debuted, the team at Anthropic have also released &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=anthropic.claude-code&quot;&gt;native extensions&lt;/a&gt; for Claude Code so it can run inside your preferred IDE of choice, but I have to say, after trying the VS Code extension of Claude, I didn&apos;t like it as much as I like having Claude in a totally separate terminal window.&lt;/p&gt;
&lt;p&gt;The extension was a bit buggy for me (unusual crashes or getting stuck in thinking loops until I quit the IDE and restarted), and while I&apos;m sure its reliability has improved, it seemed like the responses weren&apos;t quite as good as what I was coming to expect while working with Claude Code in the terminal. That&apos;s just my opinion though, I have no verifiable proof to back up this impression.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Below, I&apos;ve tried to group the things I&apos;ve learned about getting the most out of Claude Code into broad categories. This isn&apos;t an exhaustive list, but a combination of some (or all) of these tips helps me enjoy the productivity boost Claude can provide for my code, while still feeling in control of the final code outcome. I hope it helps you to dial in your own use of Claude as well, because it really can be quite the coding boost when used effectively.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Throughout this article I&apos;ll interchangeably use the terms &quot;Claude&quot; and &quot;Claude Code&quot;, but know that with each I am referring to the same thing: the Claude Code CLI that runs in a terminal, not the Claude Desktop program that also exists.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Context matters: give Claude plenty of it&lt;/h3&gt;
&lt;p&gt;Let&apos;s start with &lt;strong&gt;context&lt;/strong&gt;, because when Claude Code has context of the problem it&apos;s trying to solve, and the existing codebase it&apos;s working within, its solutions will almost guaranteed be better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Add CLAUDE.md files to your project&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; files are special files you can add to a project that Claude will automatically pull into its context when starting a conversation.&lt;/p&gt;
&lt;p&gt;Good things to include in this file are things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;General project overview, architecture, and tech stack&lt;/li&gt;
&lt;li&gt;Common development/bash commands and development workflows&lt;/li&gt;
&lt;li&gt;Code style guidelines&lt;/li&gt;
&lt;li&gt;Testing instructions&lt;/li&gt;
&lt;li&gt;Other info you want Claude to remember or be aware of&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Providing all of this inside a markdown file for Claude, makes it easy to review, revise, and update as needed, and by checking it in as part of your repo, it means your whole team can give their Claude Code agents the same basic starting point whenever they begin a new session with Claude&apos;s help.&lt;/p&gt;
&lt;p&gt;These files can live in the root of a repo, inside specific folders within a repo (like if you have a monorepo), or even in your machine&apos;s home folder (which means it will apply to &lt;em&gt;all&lt;/em&gt; Claude sessions everywhere).&lt;/p&gt;
&lt;p&gt;To make a new &lt;code&gt;CLAUDE.md&lt;/code&gt; file for a project run the &lt;code&gt;/init&lt;/code&gt; command inside of Claude Code and it will generate a &lt;code&gt;CLAUDE.md&lt;/code&gt; file for you that you can then refine over time.&lt;/p&gt;
&lt;p&gt;For example, in one of my projects, there&apos;s a &lt;code&gt;CLAUDE.md&lt;/code&gt; file at the root of the project explaining the basic overview of the app and what it does, and &lt;code&gt;CLAUDE.md&lt;/code&gt; files inside both the &lt;code&gt;backend/&lt;/code&gt; and &lt;code&gt;frontend/&lt;/code&gt; folders explaining the tech stacks, important npm commands, testing practices, code organization, and PR etiquette among other things.&lt;/p&gt;
&lt;p&gt;When you&apos;re writing these files just keep them succinct and easily human-readable, and you should be starting from a good place.&lt;/p&gt;
&lt;p&gt;Don&apos;t be afraid to have Claude re-review this file from time to time either, and update it as the project continues to evolve - it&apos;s meant to be a living document.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Copy paste all the things to Claude&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;They say a picture is worth a thousand words and once I learned I could simply paste all sorts of things into Claude Code&apos;s terminal, I began using it liberally to give Claude more context.&lt;/p&gt;
&lt;p&gt;I regularly take screenshots of what I&apos;m seeing while manually testing Claude&apos;s implementation in the browser to show Claude weird styling and layout issues, console feedback and errors, or code that&apos;s just not behaving the way it&apos;s supposed to, and paste it into Claude&apos;s terminal (there&apos;s a better way to debug this sort of thing with Claude Code that I&apos;ll cover later in the article). Likewise, if VS Code is lighting up like a Christmas tree with TypeScript or linting errors or my GitHub Action workflows are failing in GitHub, I&apos;ll copy the text from those and paste that into Claude. Or if there&apos;s a web page that I want Claude to read for additional info or examples of what I&apos;m trying to achieve, I&apos;ll paste that in and instruct Claude to visit it.&lt;/p&gt;
&lt;p&gt;Claude has proven pretty adept at being able to deduce possible issues and solutions just from screenshots, so it&apos;s definitely worth your time to feed some images to Claude with a short comment about where the screenshot came from or what it pertains to to see if Claude can pinpoint the problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use the /resume slash command to rehydrate previous conversations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Oftentimes, I&apos;ll finish a new feature, open a pull request, and get it reviewed and merged in, only to pick up another feature that builds off the one I was working on previously. When this happens, using Claude&apos;s &lt;code&gt;/resume&lt;/code&gt; command allows me to go back through previous conversations I&apos;ve had with Claude and continue one of those conversations.&lt;/p&gt;
&lt;p&gt;In this way (assuming the context window isn&apos;t already full and the conversation has to be compacted immediately), Claude already has prior context to draw from as I instruct it in how to extend the new feature I want.&lt;/p&gt;
&lt;p&gt;When you use the &lt;code&gt;/resume&lt;/code&gt; command after starting up Claude Code in the terminal, Claude will present a list of previous sessions to choose from that happened within that repo, along with details like when the conversation happened, how many messages were in the conversation, and even the name of the feature branch the conversation took place in, which makes finding the right conversation to resume from easier.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/resume-conversation.png&quot; alt=&quot;A list of options available when resuming a conversation in Claude Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This can be extra helpful when you may have worked on other things in between related features and need to reacquaint yourself with the code. Claude can give you a quick summary of a conversation after choosing to resume it to help get you back in the right mental model faster.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep Claude&apos;s sessions focused&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I know I just said &quot;give Claude lots of context,&quot; but at the same time, keep sessions (and context) focused. What I mean when I say this is don&apos;t use the same session with Claude for working on different tickets or features.&lt;/p&gt;
&lt;p&gt;Claude has enough trouble staying on track with one feature, especially when you start to factor in things like writing or updating unit tests, fixing TypeScript or linting errors, adhering to the project&apos;s style guide lines or documentation requirements, etc. Throwing Claude a curveball in the middle of a session is as disruptive to it as when someone sends you an email or pings you on Slack when you&apos;re in the middle of deep thinking and your mental model is locked in.&lt;/p&gt;
&lt;p&gt;Also, previous conversations in the same session just serve to distract Claude from the new task you&apos;re setting for it and fill its context window with (now irrelevant) details.&lt;/p&gt;
&lt;p&gt;If you&apos;ve finished up a task with Claude and are ready to start on something new, either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open a new terminal window and start a fresh Claude Code session&lt;/li&gt;
&lt;li&gt;Use the slash command &lt;code&gt;/clear&lt;/code&gt; inside of your current Claude Code session. &lt;code&gt;/clear&lt;/code&gt; clears the previous conversation history and frees up context so you can begin again.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Targeted conversations help keep Claude on task and less prone to wander or touch files not related to what it&apos;s currently working on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you like GUIs, try the Claude Code VS Code extension&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re a diehard IDE fan like me, you may really dig the Claude Code native extension you can install inside of VS Code (or your IDE of choice). The extension got a big upgrade since the release of Sonnet 4.5 and Claude Code v2 a few weeks back, and it has many of the slash command features in Claude Code built in as drop downs and selection menus. Plus, if you&apos;ve already got the relevant code open in one window of your IDE and Claude open in another, it&apos;s pretty easy to direct Claude to where you want it to focus on in the codebase.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/claude-extension.png&quot; alt=&quot;The Claude Code native extension open in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Personally, I&apos;ve gotten so used to working with Claude Code in the terminal that I probably won&apos;t switch over to this workflow anytime soon, but if you&apos;re newer to using Claude and you like the experience of having your AI agent and your editor all in one, it&apos;s definitely worth trying out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claude does better with code examples to guide it&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another thing I&apos;ve noticed about working with Claude Code is that it tends to do better when it has already existing coding conventions within a repo to look to for guidance. This goes beyond what you&apos;d typically include in a &lt;code&gt;CLAUDE.md&lt;/code&gt; file though.&lt;/p&gt;
&lt;p&gt;For instance, if you have a particular way of handling errors, logging requests, or writing tests, pointing Claude towards these files and asking it to write code that&apos;s similar for some new feature you&apos;re implementing usually works out pretty well. Don&apos;t expect Claude to be aware of helper functions or to recognize when it&apos;s writing redundant code for multiple functions - you&apos;ll still have to point that out and tell Claude to DRY it up or use the helper function instead of writing a new one, but if there is code that Claude can look to for preferred code syntax or styling, it will help.&lt;/p&gt;
&lt;p&gt;On a greenfield project where everything is new, it will be more up to you to make good architectural decisions about your codebase up front and establish code patterns that you like, then to lean on Claude for designing a robust, scalable, maintainable codebase.&lt;/p&gt;
&lt;h3&gt;Use Claude&apos;s planning capabilities&lt;/h3&gt;
&lt;p&gt;Just like a typical developer, Claude&apos;s final code tends to be better when it has planned ahead.&lt;/p&gt;
&lt;p&gt;This advice really goes hand in hand with the above tips about giving Claude more context so it can be more effective, but beyond telling Claude to look at particular files, read its &lt;code&gt;CLAUDE.md&lt;/code&gt; file, and visit those URLs, there&apos;s specific commands  and techniques you can use to nudge Claude in the right direction and help it stay on track (and hopefully result in less rewrites when reviewing Claude&apos;s work).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Engage Claude&apos;s extended thinking modes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I only learned about this trick relatively recently, but Claude actually has what it calls &quot;extended thinking mode&quot;, which gives Claude additional computation time to evaluate alternatives more thoroughly (i.e. think through a problem and solution more carefully).&lt;/p&gt;
&lt;p&gt;To trigger these increasing levels of thinking, you&apos;ll instruct Claude Code to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;Think&quot;&lt;/li&gt;
&lt;li&gt;&quot;Think hard&quot;&lt;/li&gt;
&lt;li&gt;&quot;Think harder&quot;&lt;/li&gt;
&lt;li&gt;Or &quot;Ultrathink&quot; (the name of this thinking level cracks me up)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/thinking-modes.jpg&quot; alt=&quot;Claude&apos;s many thinking modes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Claude&apos;s different thinking modes&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Frequently, I&apos;m less than impressed with Claude&apos;s quickest responses when I tell it about a bug I&apos;m encountering while testing a new feature it&apos;s helped implement, because Claude tends towards the simplest solution that fails to take into account the nuances of this bug (or the impact that the solution might have on other parts of the system that also use the same helper function, reusable component, API endpoint, etc.).&lt;/p&gt;
&lt;p&gt;In these instances, usually after Claude&apos;s first attempt to fix it has failed, I&apos;ll tell it the same bug is still there and to &quot;think&quot; or &quot;think hard&quot; about how to solve this. This will trigger Claude to spend more time on the solution: it will read and search the repo for files related to the bug (if you&apos;ve provided a screenshot or pointed to a specific file that might be the culprit), maybe run a bash command or two, then eventually provide a better solution to solve the problem in a more thoughtful manner.&lt;/p&gt;
&lt;p&gt;If you want to see what Claude is thinking to itself, in the terminal, you can expand a condensed thinking block with CTRL + O. Here&apos;s an example of the kind of thoughts you might see when you open a detailed transcript of what Claude Code is thinking as it&apos;s going about its tasks.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/claude-thinking.png&quot; alt=&quot;Detailed look at Claude thinking about how to update a Markdown file at a user&apos;s request&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The kinds of detailed notes you&apos;ll see when you expand one of Claude Code&apos;s condensed thinking text blocks&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I don&apos;t believe I&apos;ve ever invoked Claude&apos;s Ultrathink thinking mode, but I&apos;ve had good luck with its lower levels of thinking. If you&apos;ve used Ultrathink I&apos;d love to know if you thought its output was worth the extra tokens and processing time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tell Claude to make a plan&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One tip that helped immensely with Claude, is telling it to formulate a plan at the start of a fresh session or new feature.&lt;/p&gt;
&lt;p&gt;Typically, I&apos;ll start a new session, tell Claude what I&apos;m trying to build a new feature for, and point it towards any existing relevant code, docs already written about the topic, or any other helpful info I can think of, and then I&apos;ll ask Claude to think about how it would tackle this feature and make a plan.&lt;/p&gt;
&lt;p&gt;This serves two purposes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It makes Claude use one of its extended thinking modes, which almost always guarantees a better end-result.&lt;/li&gt;
&lt;li&gt;Claude comes up with a discrete set of tasks or todos to accomplish this that I can review ahead of time and approve (or tell it to revise) before it starts actually touching code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once I&apos;m satisfied with the plan, I&apos;ll tell Claude to write the plan as a Markdown file inside the project so that it can come back to the plan for reference whenever it needs to (like say, if its current context window fills up and it needs to compact the conversation before resuming work), and I also have a refresher document for future me if I need to refamiliarize myself with that feature again. Once I have verified the final code looks good, I&apos;ll tell Claude to review the plan document again and make sure it did everything agreed upon up front, as well as update any changes that occurred as the feature work progressed.&lt;/p&gt;
&lt;p&gt;At first, I thought about tossing these docs after Claude had completed the work, but lately I&apos;ve been thinking of keeping them in the project in a &lt;code&gt;/docs/&lt;/code&gt; folder that I can look to (or point Claude towards) in the future. It can serve as another way to keep useful project context close at hand that can be referenced only when needed instead of plugging it all into &lt;code&gt;CLAUDE.md&lt;/code&gt; files that Claude will see every time a new session is begun.&lt;/p&gt;
&lt;p&gt;These docs are also helpful when submitting PRs in GitHub, because I can reference them for which files were changed, what work was done, and so on, easily.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Anthropic introduced a specific Claude Code Plan Mode back in June of 2025 for this very thing. Plan Mode is a special operating mode that allows Claude Code to research, analyze, and create implementation plans without making any actual code changes. To activate it manually in a Claude Code session press Shift + Tab twice.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/claude-plan-mode.png&quot; alt=&quot;Selection of Claude Plan mode inside Claude Code terminal options&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I&apos;ve used it a few times now, and haven&apos;t seen a tremendous difference between Plan Mode and when I just tell Claude to plan, but I&apos;d like to know how you think it stacks up if you&apos;ve tested the two modes as well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Help Claude help itself with MCP tools&lt;/h3&gt;
&lt;p&gt;Similar to how devs are constantly opening browser tabs to research, test, read docs, and figure things out, you can give Claude similar powers to help itself through the use of &lt;a href=&quot;https://docs.claude.com/en/docs/claude-code/mcp&quot;&gt;&lt;strong&gt;model context protocol (MCP) tools&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;MCP is an open-source standard for AI-tool integrations, which allows Claude Code (and other AI agents like Cursor) to connect to hundreds of external tools and data sources so that it can be more useful and effective while doing its work.&lt;/p&gt;
&lt;p&gt;There&apos;s truly no shortage of MCP servers out there already (many of which are for specific SaaS tools and services), but a couple of more generic MCP servers I&apos;ve gotten benefit from so far are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/upstash/context7&quot;&gt;context7 MCP&lt;/a&gt; - This MCP provides up-to-date, version-specific documentation and code examples for LLMs and AI code editors. This means that if you&apos;re using the latest version of Svelte, but Claude&apos;s training data is with the previous version, you can tell Claude to &quot;use context7&quot; to look up the latest docs and use those to guide it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/playwright-mcp&quot;&gt;Playwright MCP&lt;/a&gt; - This MCP provides the browser automation capabilities of Playwright so LLMs can open their own web pages, take snapshots, and examine browser output the same way a developer would. This reduces the need to copy paste screenshots of browsers into Claude Code manually.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ChromeDevTools/chrome-devtools-mcp&quot;&gt;Chrome DevTools MCP&lt;/a&gt; - This MCP lets Claude control and inspect a live Chrome browser. It goes a few steps beyond Playwright by giving Claude access to the DevTools console, network tab, and even things like Lighthouse for perf testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adding any of these MCP servers to Claude&apos;s arsenal is easy to do. They all have documentation in their GitHub &lt;code&gt;README.md&lt;/code&gt; files showing how to install them in all of the popular AI coding agents, and it&apos;s usually something as simple as running a command like this inside of an open Claude session:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;claude mcp add playwright npx @playwright/mcp@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the server is installed, you may need to restart the terminal and resume the session for it to take effect, but going forward, you&apos;ll be able to use the slash command &lt;code&gt;/mcp&lt;/code&gt; and see all the currently active MCP servers that Claude has access to.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/mcp-servers.png&quot; alt=&quot;List of MCP servers available to Claude Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Then, when you want Claude Code to use any of these MCP servers, you&apos;ll simply instruct it to &quot;use context7 to look up docs for XYZ&quot; or &quot;use Playwright to check what the browser is rendering to the user&quot;. You&apos;re helping Claude Code to help itself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: The first time Claude uses Playwright to pop open a new browser and navigate to some page of a locally running application on its own is a pretty surreal experience. It was for me anyway.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Lean on Claude&apos;s expertise in unfamiliar territory&lt;/h3&gt;
&lt;p&gt;Although Claude&apos;s not the best at starting a project from ground zero, it can be very useful for updating files, explaining code, or using programming languages you may be less familiar with because it has been well trained on a large variety of programming languages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pair program with Claude to learn while you go&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Claude can be helpful as a guide for codebases you&apos;re new to, or even just parts of the code you haven&apos;t touched before but need to work on now.&lt;/p&gt;
&lt;p&gt;For instance, recently I had to update the Terraform infrastructure files in a project I work on, but Terraform is not something I&apos;m well versed in. Other folks on my team are the devops go-to people and I&apos;m happy to let them handle it, but in this case, the task fell to me. I told Claude what I needed to accomplish (update these files to point to a new set of URLs in production), and as it helped me update the files I asked questions along the way to make sure I was getting a better understanding of how the Terraform setup works, and which files should or shouldn&apos;t be touched to make sure things kept running smoothly in production.&lt;/p&gt;
&lt;p&gt;Now, I hope I don&apos;t need to use that newfound Terraform knowledge much in the future, but when I encounter unfamiliar code or a programming language I don&apos;t know much about, I feel fairly confident with Claude Code by my side that we can figure it out together.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let Claude write your [fill-in-the-blank] scripts for you&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Shell scripting can be a powerful tool for developers, but it&apos;s also one of those syntaxes that, if you don&apos;t use it for a while, quickly starts to slip from working memory (at least for me). So in the case when I need a one-off bash script, a regex function, a new GitHub Action workflow, or [fill-in-the-thing-you-always-forget-the-syntax-for-here], Claude can really come in handy.&lt;/p&gt;
&lt;p&gt;The trick here though (and I&apos;ll go in-depth more on this in the next section), is that you need to be able to quickly test and verify that whatever Claude has given you actually works.&lt;/p&gt;
&lt;p&gt;Run that shell script, test that regex, watch that GH Action workflow progress, and check the output. Because Claude may produce something that looks sensible (especially in a programming language you don&apos;t use often or at all), and it will be just as confident in its code that doesn&apos;t work as its code that does work until you call it on it. Then you&apos;ll get the standard &quot;You&apos;re absolutely right!&quot;-response and Claude will try again.&lt;/p&gt;
&lt;p&gt;Also, ask Claude to explain how the script works if it&apos;s having trouble getting it right. Sometimes, Claude checking its own code helps it find and fix bugs in them as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Think outside the box: use Claude for tasks beyond coding&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Maybe this isn&apos;t news to anyone else, but I&apos;ve just begun using Claude Code for non-programming related tasks.&lt;/p&gt;
&lt;p&gt;Here&apos;s a couple of examples off the top of my head:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I had Claude Code draft up a PowerPoint presentation outline (and even a couple of diagrams for the presentation itself courtesy of Mermaid diagrams).&lt;/li&gt;
&lt;li&gt;My friend had Claude Code use some family photos and design a nice scrapbook layout to showcase them, that converted to a perfect 8.5&quot; x 11&quot; PDF for printing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Claude has become synonymous with coding in particular, but it can do a solid job at other things. It can also be quite creative in how it solves a problem since it&apos;s limited to the terminal and can&apos;t actually generate traditional images. So even if you&apos;re tasked with something not directly programming-focused, Claude may be a good sounding board or have some skills that can help you get the job done quicker or in a different way than you may have imagined before.&lt;/p&gt;
&lt;h3&gt;Don&apos;t trust Claude: review and verify&lt;/h3&gt;
&lt;p&gt;Ok, this is probably the best thing you can do to get the most value out of Claude Code (and have the least amount of refactoring after the fact to bring Claude&apos;s code in line with your standards and expectations): &lt;strong&gt;review and verify everything Claude does&lt;/strong&gt;. Claude Code is a useful tool, but it must be watched like a hawk (and its code tested often and thoroughly) to keep it on task and making progress towards the goal you want.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Follow along with Claude&apos;s changes in VS Code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the first version of Claude Code, it would show the code changes it wanted to make to a file inside the terminal itself with the name of the file at the top so devs could see which file it intended to touch. For some devs this may be enough, but for me, I also have VS Code open at the same time to watch the changes being made as Claude goes.&lt;/p&gt;
&lt;p&gt;In the current version of Claude Code, there&apos;s a setting you can enable in the &lt;code&gt;/config&lt;/code&gt; called &quot;Auto-connect to IDE&quot; that lets Claude show the changes it wants to make to the file in VS Code, which is great. It still waits for permission to make the changes or tell it to do something different, but at least this way you can see the other code in the file along with the changes Claude wants to make.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/config-ide-settings.png&quot; alt=&quot;Claude Code settings where users can enable &amp;quot;Auto Connect to IDE&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;How to enable Claude Code&apos;s &quot;Auto Connect to IDE&quot; feature in its config settings&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;When the feature is enabled and the VS Code repo is open on your local machine, Claude will show in its terminal &quot;Opened changes in Visual Studio Code&quot; and pop open the file and display the code changes it wants to make inside the file, very similar to how you see diffs in GitHub PRs. Here&apos;s a screenshot of the Claude Code terminal instance and the file in VS Code Claude wants to modify.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/updates-in-vs-code.png&quot; alt=&quot;How it looks when Claude Code shows a code change it wants to make in the open VS Code repo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Following along with the changes in the repo and having my own server running (or automated tests, etc.) to frequently test the changes Claude is making and ensure code is working correctly tends to lead to better outcomes and a shorter feedback cycle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not let Claude YOLO (aka &quot;Allow all edits in a session&quot;). Course correct early and often&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This may be an unpopular opinion, but I &lt;em&gt;never&lt;/em&gt; let Claude make any code changes without my permission. For best results, you cannot &quot;set it and forget it.&quot;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/claude-code/claude-permissions.png&quot; alt=&quot;Claude Code asking permission to edit a file&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I will never choose option 2: &quot;Yes, allow all edits during this session.&quot; Claude needs constant supervision.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I have learned through trial and error that allowing Claude to autonomously make decisions without oversight is a recipe for throwing away a bunch of useless code because it took a wrong turn and started going down a bad path and no one stopped it until it was too late.&lt;/p&gt;
&lt;p&gt;Yes, it is a bit annoying when Claude asks you for permission to visit a URL you&apos;ve just given it, or view an image you&apos;ve pasted into its terminal, but when it makes a code suggestion and you realize it forgot to account for an edge case or it&apos;s making an assumption that&apos;s false, or it just plain forgot to include something you wanted it to, being able to review the changes, select Option 3 from the dropdown &quot;No, and tell Claude what to do differently&quot;, and get it back on the right track is worth the extra time, in my opinion.&lt;/p&gt;
&lt;p&gt;It&apos;s much easier to course correct earlier on in the process than when the PR is complete and waiting for review, so keep a tight leash on Claude.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Make Claude test its own code changes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the best ways I&apos;ve found to get Claude to catch bugs in the code it&apos;s generated is by having it write unit tests for said code. I know that plenty of folks expound on the benefits of Test Driven Development (TDD), but I&apos;m not one of them. I agree with it in theory, but don&apos;t actually do it in practice.&lt;/p&gt;
&lt;p&gt;So after I&apos;ve followed Claude&apos;s code implementation and done manual testing via the API or the UI (depending on the feature), I&apos;ll ask Claude to write unit tests, integration tests, end to end tests - whatever is most appropriate for the situation. Test writing is not something I enjoy doing (all the data setup, the mocks, the spies, the particular testing framework syntax whether you&apos;re using Mocha, Jest, Vitest, Cypress, Selenium, etc., etc.), but I know the value it provides, and the speed with which Claude can produce new test files or update existing test files (especially when pointed towards an existing test file that shows the preferred testing libraries and syntax) is great.&lt;/p&gt;
&lt;p&gt;By and large, Claude&apos;s tests (at least in JavaScript and TypeScript) are good. And they have actually caught bugs in the code that Claude wrote. One example that springs to mind, is a timing function where Claude forgot to add a set of times together for the final value in the actual code, but it did correctly calculate what the final time should be in the test. The unit test revealed the bug and with a little prompting from me to review the actual code implementation, Claude found and fixed its error.&lt;/p&gt;
&lt;p&gt;Be warned though, even though Claude will happily run test suites for you all day long, it will sometimes say that failing unit tests aren&apos;t due to code changes it made (even though they are) and won&apos;t offer to fix them proactively. In this case, I just tell Claude to fix them anyway - I don&apos;t really care whose fault Claude thinks it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claude can refactor well&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another thing Claude Code can do pretty well is refactor already existing code, although again, it won&apos;t suggest this to you. You must suggest it to Claude.&lt;/p&gt;
&lt;p&gt;This might occur when I&apos;ve had Claude implement a more complex feature: functions get big and unruly and try to do too many things, there&apos;s duplicate code for functions that do similar things, or there&apos;s just too much code to look at in one file and it needs to be broken down into smaller, easier-to-understand chunks of code.&lt;/p&gt;
&lt;p&gt;Many times I&apos;ve pointed Claude towards a file that&apos;s getting out of hand and told it to either simplify the file by breaking down the big functions into smaller ones, search for duplicate code that can be handled with a reusable helper function, or even refactor out code into separate files altogether. Those files can get pretty gnarly at times, and letting Claude sort out what props need to be passed into newly created functions or UI components saves time and makes the code more readable in the future.&lt;/p&gt;
&lt;p&gt;Again, test the refactors after they&apos;re done to make sure everything still works, but I&apos;ve had pretty good success with this in TypeScript-based projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Have the AI agents review each other&apos;s work&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Like any true developer, the Claude Code session adding new code to a repo is proud of its own output. Bringing in another, more impartial set of eyes, like that of GitHub Copilot doing a PR review or even another Claude instance reviewing the new code, helps keep Claude more honest.&lt;/p&gt;
&lt;p&gt;Typically, I will tag GitHub Copilot as a reviewer when I open a new PR in GitHub, and then I&apos;ll take any relevant comments it makes (some comments are irrelevant, so be sure to screen those out using your own good judgement first), and feed them back to Claude Code. Almost always the comments I share with Claude to review and revise end up making the code better and more robust than it was before.&lt;/p&gt;
&lt;p&gt;Depending on what GitHub Copilot or Claude Code plans you have, it may make sense for you to have one or the other (or if you really want to go all out, both) review the new code with a critical eye: that&apos;s why we have code reviews after all, and if Claude can write code, it can certainly review it as well.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I don&apos;t believe, based on what I&apos;ve seen, that AI agents are going to replace flesh and blood software engineers anytime soon, but they can be pretty helpful in doing a lot of the day-to-day coding we used to have to do by hand.&lt;/p&gt;
&lt;p&gt;By far, my favorite tool to help me code faster is Anthropic&apos;s Claude Code. There was a learning curve to get over: learning what context to provide it, how to engage its different thinking modes for more complex tasks, and to always manually test new features it&apos;s implemented to make sure it&apos;s accounted for everything, but overall, I&apos;m happy with the results I get.&lt;/p&gt;
&lt;p&gt;I&apos;m sure I&apos;m not using Claude to the extent that some power users may be, but I feel like the things I&apos;ve picked up about working with Claude Code in the past 6 months or so, have helped me to write good quality code at a faster clip than I would have otherwise (and even improve the DX in existing codebases with nice little, one-off features Claude can whip up in no time).&lt;/p&gt;
&lt;p&gt;Thanks for reading, hopefully, if you haven&apos;t given Claude Code a try yet, this will inspire you to do so, and if you have, I hope you learned some new helpful tips to get even better results from it.&lt;/p&gt;
&lt;p&gt;So what do you think? Did I miss any tips and tricks you&apos;ve found particularly helpful when using Claude Code? I&apos;d love to hear them.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.claude.com/product/claude-code&quot;&gt;Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/engineering/claude-code-best-practices&quot;&gt;Claude Code best practices article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.claude.com/en/docs/claude-code/mcp&quot;&gt;MCP tools with Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>advice</category><category>programming</category><category>ai</category><category>claude</category></item><item><title>Run Multiple npm Publishing Scripts with Trusted Publishing (OIDC) via GitHub Reusable Workflows</title><link>https://www.paigeniedringhaus.com/blog/run-multiple-npm-publishing-scripts-with-trusted-publishing-oidc-via-github-reusable-workflows/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/run-multiple-npm-publishing-scripts-with-trusted-publishing-oidc-via-github-reusable-workflows/</guid><description>npm only allows one GitHub Actions workflow script, but that script can dynamically call different publishing workflows.</description><pubDate>Tue, 18 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-reusable-workflow-npm/flowchart-hero.png&quot; alt=&quot;Digital flowchart diagram interpretation&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the last few months, the npm ecosystem has been plagued by supply chain attacks where OSS maintainers of widely used packages have been phished and versions of these packages containing malicious code have been published to npm for download. Luckily, the broader software community has noticed the compromised libraries early and removed the bad package versions quickly, but it is an ongoing problem.&lt;/p&gt;
&lt;p&gt;To try and curb these attacks, &lt;a href=&quot;https://github.blog/changelog/2025-09-29-strengthening-npm-security-important-changes-to-authentication-and-token-management/&quot;&gt;GitHub announced changes&lt;/a&gt; to strengthen the security around the npm ecosystem in the form of deprecating long-lived publishing tokens stored in GitHub projects and strongly encouraging everyone to begin using trusted publishing (OIDC) workflows, which use temporary, job-specific credentials to publish to npm. These changes were to take effect in November of 2025.&lt;/p&gt;
&lt;p&gt;I&apos;ve previously written about how I &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;created and maintain a JavaScript SDK for my company&apos;s API with the help of GitHub Action workflows&lt;/a&gt;, and since I first built that repo a couple of years ago, its use has expanded such that it now has two separate npm publishing workflows that run at different times. One workflow publishes new stable versions of the SDK for public use, and one workflow publishes beta versions of the SDK that the dev team can use for internal testing.&lt;/p&gt;
&lt;p&gt;When I tried to follow the instructions for &lt;a href=&quot;https://docs.npmjs.com/trusted-publishers&quot;&gt;setting up trusted publishing in npm&lt;/a&gt;, I was dismayed to learn that currently npm only allows for &lt;em&gt;one&lt;/em&gt; workflow file to be declared as a trusted publisher.&lt;/p&gt;
&lt;p&gt;So what&apos;s an npm library to do that has more than one publishing workflow? Trust the production deploy script and relegate the other scripts to using expiring tokens that will have to be manually updated on a regular basis? 🫠&lt;/p&gt;
&lt;p&gt;But fear not! All hope is not yet lost.&lt;/p&gt;
&lt;p&gt;After turning to the &lt;a href=&quot;https://github.com/orgs/community/discussions/174507&quot;&gt;GitHub Discussion thread&lt;/a&gt; where people could ask questions and &lt;s&gt;rage&lt;/s&gt; express their feelings about the changes, I wrote about my own use case (2 different workflow files that both need to publish to npm regularly) and someone suggested a solution I&apos;d never come across before: &lt;a href=&quot;https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows#using-inputs-and-secrets-in-a-reusable-workflow&quot;&gt;&lt;strong&gt;GitHub Reusable Workflows&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After a couple of false starts and a little more &lt;a href=&quot;https://github.com/orgs/community/discussions/174507#discussioncomment-14716618&quot;&gt;assistance from the dev community&lt;/a&gt;, I had trusted publishing working for both npm publishing workflows and my crisis was averted! 🙌&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to use trusted publishing (OIDC) on npm with multiple GitHub Actions workflow scripts thanks to GitHub Actions reusable workflows.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Full disclosure, before I turned to other actual devs, I tried to tackle this problem with just the help of Claude Code and it was useless.&lt;/p&gt;
&lt;p&gt;It had zero ideas of how to fix this seemingly intractable problem of two publishing scripts with only one trusted publishing input in npm, which just goes to show that as soon as the coding problem gets less common, the assistance of AI agents starts to fail.&lt;/p&gt;
&lt;p&gt;In this case, humans FTW!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;GitHub Actions reusable workflows&lt;/h2&gt;
&lt;p&gt;Before we dive into the solution, let&apos;s talk about &lt;em&gt;what even are&lt;/em&gt; GitHub Actions reusable workflows, because as I said, I&apos;d never even heard of them before now.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows&quot;&gt;&lt;strong&gt;GitHub Actions reusable workflows&lt;/strong&gt;&lt;/a&gt; are YAML-formatted files like any other GitHub Actions workflow file, but they allow for the encapsulation of common CI/CD actions that can be called by &lt;em&gt;other workflows&lt;/em&gt;, eliminating the need to copy and paste the same workflow logic across different projects, orgs, or even public repos.&lt;/p&gt;
&lt;p&gt;For instance, if you deploy multiple web apps to the same cloud environment, a reusable workflow could encapsulate the entire deployment logic, or a reusable workflow could automatically fix code styling issues to ensure consistent code formatting across projects, &lt;em&gt;or&lt;/em&gt; (in my case) a reusable workflow can build and publish different versions of an SDK to npm.&lt;/p&gt;
&lt;p&gt;As I learned, the key to successfully using a GitHub Actions reusable workflow for trusted publishing with npm is that &lt;strong&gt;npm validates the entry point workflow, not the workflow that actually runs the npm publish command&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What I&apos;ll cover next, is how to create a single entry point workflow file that will be designated as the Trusted Publisher in npm, and that file will then call the appropriate GH Actions workflow file to do the actual publishing steps.&lt;/p&gt;
&lt;h3&gt;Create a &lt;code&gt;publish-switch.yml&lt;/code&gt; file in the &lt;code&gt;.github/workflows/&lt;/code&gt; folder&lt;/h3&gt;
&lt;p&gt;So first things first: create a new single entry point workflow file inside of the project repo&apos;s &lt;code&gt;.github/workflows/&lt;/code&gt; folder where the other GH Actions publishing workflow files already live.&lt;/p&gt;
&lt;p&gt;For convenience, I named this new file &lt;code&gt;publish-switch.yml&lt;/code&gt;. This is the file name that will be set in the npm project&apos;s Settings tab as the Trusted Publisher, which I&apos;ll get to shortly.&lt;/p&gt;
&lt;p&gt;Inside of this new &lt;code&gt;publish-switch.yml&lt;/code&gt; file, there are two lines of permissions required to activate the OIDC trusted publishing. The permissions for OIDC need to be in this reusable workflows file (and not the files it will call to publish to npm) because &lt;code&gt;publish-switch.yml&lt;/code&gt; is the file that npm validates against when doing the actual publishing.&lt;/p&gt;
&lt;p&gt;The lines you&apos;ll need to include are:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;permissions:
  id-token: write # required for OIDC to request ID token to authenticate workflow
  contents: read # switch this to &apos;write&apos; too if the workflow also needs to push back content to repo (like if you automatically increment an SDK version before publishing)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The full &lt;code&gt;publish-switch.yml&lt;/code&gt; may look something like the following. I&apos;ll explain what&apos;s going on beneath it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/.github/workflows/publish-switch.yml&quot;&gt;&lt;strong&gt;&lt;code&gt;publish-switch.yml&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Publish switch

on:
  release:
    types: [created]
  push:
    branches:
      - &quot;test-release-**&quot;
    paths:
      - &quot;openapi.yaml&quot;

permissions:
  id-token: write # Required for OIDC
  contents: write # Required for npm beta version updates

jobs:
  publish-prod:
    if: github.event_name == &apos;release&apos;
    uses: ./.github/workflows/publish-prod-npm.yml
    permissions:
      id-token: write
      contents: read

  publish-beta:
    if: github.event_name == &apos;push&apos;
    uses: ./.github/workflows/publish-beta-npm.yml
    permissions:
      id-token: write
      contents: write
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the SDK that I publish to npm, there&apos;s two ways the different publishing workflows are triggered.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When a &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release&quot;&gt;new release is created&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;This event triggers a production release to npm after I review the changes to the SDK, bump the package version, and manually create a new release in GitHub.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When a &lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onpushbranchestagsbranches-ignoretags-ignore&quot;&gt;new branch is created whose name begins with &lt;code&gt;test-release-**&lt;/code&gt;&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;This event triggers an automated release to npm where a new version of the SDK is built, tagged with a &lt;code&gt;-beta.XX&lt;/code&gt; at the end of the current latest version, and published as the latest beta release on npm.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In my reusable workflow file above, I:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Designate event triggers for each type of GH Actions workflow, and specify those same triggers in this file,&lt;/li&gt;
&lt;li&gt;Add the required &lt;code&gt;permissions&lt;/code&gt; for OIDC trusted publishing,&lt;/li&gt;
&lt;li&gt;And then, based on which GitHub &lt;a href=&quot;https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onevent_nametypes&quot;&gt;&lt;code&gt;event_name&lt;/code&gt;&lt;/a&gt; triggered the release, determine which workflow publishing file to run (prod publishing or beta publishing).&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I&apos;ve omitted the particulars of the actual GitHub Actions publishing files themselves, because they&apos;re outside the scope of this article, but if you&apos;d like to see them in their entirety,  the &lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/.github/workflows/publish-prod-npm.yml&quot;&gt;production publishing workflow file is here&lt;/a&gt;, and the &lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/.github/workflows/publish-beta-npm.yml&quot;&gt;beta publishing workflow file is here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Configure the npm repo&apos;s Trusted Publisher to point towards the &lt;code&gt;publish-switch.yml&lt;/code&gt; file&lt;/h3&gt;
&lt;p&gt;Now that the GH Actions reusable workflow file is created, it must be set as the Trusted Publisher file inside of the npm repo&apos;s settings.&lt;/p&gt;
&lt;p&gt;To do that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the npm project&apos;s &quot;Settings&quot; tab (I believe you&apos;ll need at least Maintainer level access to the repo to be able to get there),&lt;/li&gt;
&lt;li&gt;Select the button for your publisher (at the time of writing this only GitHub and GitLab are available),&lt;/li&gt;
&lt;li&gt;Configure the following fields:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Organization or user&lt;/strong&gt;: GitHub username or organization name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repository&lt;/strong&gt;: Repository name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workflow filename&lt;/strong&gt;: The filename of the GH Action workflow inside the repo doing the deployment to npm. (In my case it is &lt;code&gt;publish-switch.yml&lt;/code&gt;.)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Then click the Save Changes button, and it&apos;s done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-reusable-workflow-npm/npm-trusted-publisher.png&quot; alt=&quot;Screenshot of how to fill out Trusted Publisher section inside npm project&apos;s settings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Voilà! OIDC trusted publishing to npm&lt;/h3&gt;
&lt;p&gt;All that&apos;s left to do at this point is check that the &lt;code&gt;publish-switch.yml&lt;/code&gt; workflow is working correctly.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-reusable-workflow-npm/publish-switch-runs.png&quot; alt=&quot;Screenshot of the two different GH Action workflows successfully running via the same reusable workflow file&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here&apos;s a screenshot in my SDK repo that shows both prod and beta publishes to npm are relying on the Publish Switch workflow and succeeding, back to back.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test npm beta publishing workflow&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For me, I tested the npm beta publishing workflow by creating a new test branch in my repo with the name &lt;code&gt;test-release-oidc-publish&lt;/code&gt;, and watched the &lt;code&gt;publish-switch.yml&lt;/code&gt; file correctly select the &lt;code&gt;publish-beta-npm.yml&lt;/code&gt; workflow file to run.&lt;/p&gt;
&lt;p&gt;To verify it correctly deployed, I checked the GH Actions workflow logs, and at the bottom of the &quot;Publish Beta Version to npm&quot; step, I can see the text, &quot;npm notice publish Signed provenance statement with source and build information from GitHub Actions&quot;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-reusable-workflow-npm/publish-beta.png&quot; alt=&quot;Screenshot of success of Publish Beta Version to npm in GH Action Workflow&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test npm production publishing workflow&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Then, to test the npm production publishing workflow, I created a new release of the SDK code, and once more, watched the &lt;code&gt;publish-switch.yml&lt;/code&gt; file correctly identify that this event should run the &lt;code&gt;publish-prod-npm.yml&lt;/code&gt; workflow file.&lt;/p&gt;
&lt;p&gt;Once again, I checked the GH Actions workflow logs, saw the successful publish message at the bottom of the &quot;Publish to npm&quot; step, &quot;npm notice publish Signed provenance statement with source and build information from GitHub Actions.&quot;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-reusable-workflow-npm/publish-prod.png&quot; alt=&quot;Screenshot of success of Publish Prod Version to npm in GH Action Workflow&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; For one more gut check, I could also visit the npm website and make sure the new beta or production versions are available for download there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The democratization of coding over the last couple of years has made it much easier for people without backgrounds in computer science to bring their ideas to life online, but it&apos;s also made it easier for bad actors to add hard-to-detect malware in popular, previously innocuous software libraries with hundreds of thousands or millions of downloads per week.&lt;/p&gt;
&lt;p&gt;GitHub stepped up by quickly introducing new, more secure ways of controlling JavaScript libraries published to the npm package registry and swiftly deprecating older methods more prone to potential hacking. And while this is a good move in theory, since it&apos;s been rolled out so quickly, it&apos;s left many open source maintainers in a tough spot if they manage many npm packages or have multiple, legitimate publishing scripts they use to publish to npm, because currently projects can only designate one script as a project&apos;s Trusted Publishing script.&lt;/p&gt;
&lt;p&gt;This one script issue was the problem I encountered with the npm package I maintain. There&apos;s two separate workflows with very different steps depending on whether I&apos;m publishing a new production version of the library for public use, or a beta version of the library for the dev team to test against as they build new features.&lt;/p&gt;
&lt;p&gt;I thought I would be stuck manually refreshing deprecated publishing tokens regularly to keep both workflows going, but lo and behold, the smart developers in the GitHub community clued me in to a feature I wasn&apos;t aware of in GitHub: GitHub Actions reusable workflows.&lt;/p&gt;
&lt;p&gt;Through the power of reusable workflows, multiple GitHub Actions workflow scripts can be triggered to handle the different types of package publishing, while the reusable workflow file carries the necessary permissions to satisfy npm&apos;s trusted publishing (OIDC) requirements. Just what I needed.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, AI, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, GitHub Action reusable workflows are not well documented as an option for those of us who have multiple GitHub Action workflow publishing files to publish to npm, but I hope this solution may work for you like it worked for me.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows&quot;&gt;GitHub reusable workflows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/trusted-publishers&quot;&gt;npm trusted publishing docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/community/discussions/174507#discussioncomment-14716618&quot;&gt;GitHub Discussion thread solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/.github/workflows/publish-switch.yml&quot;&gt;Notehub JS &lt;code&gt;publish-switch.yml&lt;/code&gt; file&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>github</category><category>git</category><category>npm</category><category>devops</category></item><item><title>Reviewing the BenQ RD Series Monitor for Developers</title><link>https://www.paigeniedringhaus.com/blog/reviewing-the-benq-rd-series-monitor-for-developers/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/reviewing-the-benq-rd-series-monitor-for-developers/</guid><description>I didn&apos;t think developers needed a special monitor, until I tried the BenQ RD280U.</description><pubDate>Mon, 08 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/wfh-desk-hero.jpg&quot; alt=&quot;Photo of current work from home setup with new BenQ RD280U Programming monitor on right hand side&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Like many developers, I began working from home full time when the pandemic hit and the office I commuted to every day was forced to close. My initial WFH setup was at the dining room table with my 16&quot; MacBook Pro, a leftover 18&quot; Dell monitor as my second screen, and an old Microsoft wireless keyboard.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/wfh-v0.jpg&quot; alt=&quot;Photo of initial, humble, work from home setup at the dining room table&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;v0 of the work from setup. It came from humble beginnings.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As the weeks turned into months and it became apparent no one would be going back to an office anytime soon, I began to slowly but steadily build a solid work from home station: laptop stand to raise my laptop to eye level, adjustable desk, extra office chair that was stored in the garage.&lt;/p&gt;
&lt;p&gt;Then mid-pandemic, I joined the fully remote tech startup I work for now, Blues, and it was game on: upgraded Logitech wireless keyboard, dual 27&quot; HP monitors, upgraded office chair (with aftermarket rollerblade wheels, I might add), Thunderbolt docking station, external microphone, key light, and Elgato mini prompter (for the &lt;a href=&quot;https://front-end-fire.com/&quot;&gt;weekly web dev podcast&lt;/a&gt; I started with my friends). For quite a while now I&apos;ve felt very dialed in at this command station each day. After 5 years of incremental upgrades, you&apos;d hope that would be the case.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/wfh-v1.jpg&quot; alt=&quot;Photo of upgraded work from home setup: adjustable desk, dual monitors, external microphone, key light, prompters&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The v1 wfh command station I&apos;ve been perfecting for years now.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;About two months ago, out of the blue, the folks at tech product company BenQ reached out to me asking if I&apos;d be interested in trying out one of its &lt;a href=&quot;https://www.benq.com/en-us/monitor/programming.html&quot;&gt;&lt;strong&gt;RD series programming monitors&lt;/strong&gt;&lt;/a&gt;: a product line designed with developers&apos; needs in mind. Having heard good things about BenQ, but never actually trying their products, I said &quot;Sure!&quot;, and received a &lt;a href=&quot;https://benqurl.biz/4oHVx4E&quot;&gt;&lt;strong&gt;28&quot;, 4K RD280U monitor&lt;/strong&gt;&lt;/a&gt; shipped to my front door about a week later.&lt;/p&gt;
&lt;p&gt;I was a little dubious some of the monitor&apos;s claims like coding-optimized color modes and auto dimming features for low-light environments were just marketing fluff, but once I tried it out, boy was I wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;m going to review the &lt;a href=&quot;https://benqurl.biz/4oHVx4E&quot;&gt;BenQ RD280U 28&quot; 3:2 Monitor for Programming&lt;/a&gt;, and tell you how it&apos;s improved my day-to-day coding workflow in ways I never anticipated.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Initial assembly and setup of the RD280U was a breeze&lt;/h2&gt;
&lt;p&gt;The RD280U ships in a what seems like large box, even for a 28&quot; monitor, but all the pieces are well organized and protected, and my assembly of the monitor was done within minutes following the detailed illustrations in the Quick Start guide included in the box.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The box is quite large even though it&apos;s not actually that heavy. Based on its bulk, I would recommend you find a second person to help you get it inside and near to where you plan to assemble and use it, if possible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The screen itself can tilt between -5˚ - 20˚  up and down, swivel right and left 15˚ , and adjust the height on its stand by 4.3&quot; (110mm).&lt;/p&gt;
&lt;p&gt;It comes packaged with HDMI, USB-C, and USB-B cords for connecting to your laptop, and also has a display port as well, if that&apos;s your preferred connection method. One pleasant surprise for me was the lack of an external power pack that I&apos;d have to secure somewhere behind my desk. Instead there&apos;s simply a power cord that runs from the monitor to an outlet.&lt;/p&gt;
&lt;p&gt;Additionally, there&apos;s a &lt;a href=&quot;https://www.benq.com/en-us/monitor/programming/rd280ua.html&quot;&gt;flexible arm version of the monitor (the RD280UA)&lt;/a&gt; you can choose instead of the stand the RD280U comes with if you want to clamp it to your desk instead.&lt;/p&gt;
&lt;h2&gt;Noteworthy RD280U features for devs&lt;/h2&gt;
&lt;p&gt;Ok, let&apos;s talk about the things that developers care most about: the monitor&apos;s features! The RD280U has a lot of them.&lt;/p&gt;
&lt;h3&gt;&quot;Coding Mode&quot;&lt;/h3&gt;
&lt;p&gt;The BenQ RD series monitors have a feature called &quot;Coding Mode&quot;, which is a series of specialized display settings aimed at providing the best possible text clarity for programmers. Coding Mode adjusts settings to sharpen text and reduce eye strain, and has both Dark and Light themes depending on devs&apos; user preferences.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;m Team Dark Mode all day, by the way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Below are more specifics on how Coding Mode enhances a typical coding session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Higher text clarity&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This RD monitor has a max resolution of 4K+ UHD, which means four times more pixels and detail than a 1080p display. What this translates to in practice, is less eye strain when looking at code for hours on end. Coding Mode takes this a step further by fine-tuning the contrast, brightness, sharpness, saturation, and gamma settings levels for text, enhancing the overall sharpness and readability of code, even during long working sessions.&lt;/p&gt;
&lt;p&gt;Personally, I can see a difference when I compare two IDE windows side-by-side on my existing HP monitor vs the new BenQ monitor: the BenQ monitor &lt;em&gt;does&lt;/em&gt; make the code sharper and easier to read.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anti-reflection screen properties&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Until recently (when I was traveling for work and working from coffee shops and hotel cafes), I didn&apos;t think too much about screen glare and light reflection. It must just be where my office is set up at home, but it wasn&apos;t really an issue for me.&lt;/p&gt;
&lt;p&gt;Working remotely, however, screen glare was an issue I had to contend with and the BenQ Nano Matte Panel technology that actively minimizes contrast glare on the screen would have been most welcome.&lt;/p&gt;
&lt;p&gt;If you have lights set up behind you that cause reflections on your monitor or even just windows that let the sunlight in during a typical day, you&apos;ll probably really appreciate this feature as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Function Bar&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An addition the RD monitors include that is very geared towards developers is the addition of a Function Bar at the bottom center of the monitor.&lt;/p&gt;
&lt;p&gt;It has a &quot;Coding HotKey&quot; on the front of the bar that looks like a closing HTML tag &amp;lt;/&amp;gt;, and when touched, it provides quick access to features like coding modes, screen brightness and contrast, and a customizable &quot;Function Key&quot; button on the bottom righthand side of the bar that can be set to different options you might want quick access to like Color Mode or input source.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/coding-hotkey.jpg&quot; alt=&quot;Photo of the display panel when the Coding HotKey on the Function Bar is tapped&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here&apos;s a shot of the settings the Coding HotKey displays when tapped on the front of the Function Bar.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In addition to the Function Key on the far right of the Function Bar, there&apos;s also a power button for the monitor and a center button that displays &lt;em&gt;all&lt;/em&gt; the RD monitor&apos;s settings (there&apos;s a lot of them). The settings are easy to navigate through as the buttons allow for left/right toggling through menus and the naming is also pretty intuitive.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/settings.jpg&quot; alt=&quot;Photo of the full settings panel when the center button on the bottom of the Function Bar is pressed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The full settings panel is accessed by pressing the center button on the bottom of the Function Bar.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The bar also has some LED indicators on the front next to the Coding HotKey to show which settings are currently on.&lt;/p&gt;
&lt;p&gt;It has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Night Hours Protection indicator&lt;/strong&gt; (an owl head), which adjusts the screen to minimum brightness for coding in low light or at night,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brightness Intelligence Gen2&lt;/strong&gt; (a polygon-esque lightbulb), that auto detects ambient light and adjusts the screen&apos;s brightness accordingly,&lt;/li&gt;
&lt;li&gt;And &lt;strong&gt;Low Blue Light Plus&lt;/strong&gt; (a lightbulb), which reduces blue light while preserving color quality.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For me, after toggling through my screen&apos;s settings on initial setup and ensuring my Color Mode theme was set to &quot;Coding - Dark Theme&quot;, I haven&apos;t needed to use the Function Bar or Coding HotKey much since.&lt;/p&gt;
&lt;p&gt;I don&apos;t have multiple different computers I want to use this monitor with and switch between (although it supports that!), nor do I feel the need to change my Color Mode theme frequently, but for some devs this may be of greater value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MoonHalo backlight&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another interesting feature I hadn&apos;t consciously considered but really like, is the backlight &quot;MoonHalo&quot; built into the RD280U.&lt;/p&gt;
&lt;p&gt;It&apos;s essentially a ring light built into the back of the monitor that can be set to turn on and provide ambient light while working. It can also auto dim to ultra low brightness with color-balance based on how dark your work surroundings are, which is influenced by the sensor in the Function Bar mentioned above that automatically detects and adjusts the display brightness based on the ambient brightness throughout the day.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The auto dimming feature, I appreciate a lot. It makes me feel less like I&apos;m working in a cave at my desk after dark..&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/moonhalo.jpg&quot; alt=&quot;An angled shot of the MoonHalo light on the back of the RD280U monitor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here&apos;s an angled shot of what the MoonHalo looks like on the back of the RD280U monitor. At this time of day, it&apos;s at a low brightness level.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;While the MoonHalo certainly doesn&apos;t take the place of a key light if you do any video recording or streaming, it is nice for providing some extra ambient light and offering adjustable color temperature without needing a separate lamp, and doesn&apos;t do the &quot;blinding white screen at night scenario&quot; when the monitor screen is set for daytime brightness conditions by default.&lt;/p&gt;
&lt;h3&gt;Additional monitor features&lt;/h3&gt;
&lt;p&gt;Those are some of the technologies and thoughtful additions that the RD series monitors offer specifically for programmers via Coding Mode, but there&apos;s some additional things worth pointing out in this review as well, that may just sell you on the BenQ RD monitor otherwise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Display Pilot 2 software&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The BenQ line of monitors comes with its own software control app called &lt;a href=&quot;https://www.benq.com/en-us/monitor/software/display-pilot-2.html#RD%20models&quot;&gt;Display Pilot 2&lt;/a&gt;, to let users efficiently control their display settings on their computer.&lt;/p&gt;
&lt;p&gt;The app offers a software interface for adjusting many of the settings I outlined above: audio levels, color mode, screen brightness, MoonHalo, switching screen orientation, and so on.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/display-pilot-2.png&quot; alt=&quot;Screenshot of Display Pilot 2 software interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Honestly, until I was writing this review, I hadn&apos;t even bothered to download the Display Pilot 2 software to my Mac, and while it provides a nice looking interface to control all the bells and whistles from my computer, I don&apos;t see myself using it often after I&apos;ve dialed in my initial settings.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I should also note that while I was messing with the settings via Display Pilot 2, the software crashed a couple of times and caused my BenQ RD monitor to blink on and off more than once, so your mileage may vary when using it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Multi-source support for seamless source switching&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A lot of developers have different rigs for different purposes: a gaming PC, a MacBook work, a personal laptop, or some other combination of devices.&lt;/p&gt;
&lt;p&gt;In the past, it&apos;s always been kind of a a pain to switch one machine for another to use the same peripherals (keyboard, external monitor, mouse, headphones, etc.).&lt;/p&gt;
&lt;p&gt;Well, the BenQ RD monitor can support more than one machine at a time. It has an HDMI port, display port, two USB-C ports, 1 USB-B port, 1 USB-A port, and a headphone jack. It also has a built-in KVM (keyboard, video, mouse) switch to make shifting from one machine to another easy.&lt;/p&gt;
&lt;p&gt;Simply connect Computer 1 and Computer 2 to the RD monitor, and both will be identified. Once both are recognized, you can switch the input video source from Computer 1 to Computer 2, and the monitor will also switch the USB signal to computer 2 as well. No muss, no fuss.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have not tested this feature out myself, as I do not use multiple laptops with my current setup, but I trust the &lt;a href=&quot;https://www.benq.com/en-us/support/downloads-faq/faq/pre-sales/technologies/kvm-swich-to-work-with-one-keyboard-mouse-set.html&quot;&gt;documentation the BenQ website provides about the KVM switch&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;My favorite monitor feature (I didn&apos;t see this one coming tbh)&lt;/h3&gt;
&lt;p&gt;By far my favorite feature of this new RD monitor is (and I&apos;m as shocked about this as anyone else considering all the cool tech I&apos;ve covered up to now): its 3:2 aspect ratio design!&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/aspect-ratio.jpg&quot; alt=&quot;Photo of 3:2 screen aspect ratio of BenQ RD280U monitor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Aspect ratio? Really?? That&apos;s what you&apos;re most jazzed about???&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The 3:2 screen aspect ratio&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My friends, it is.&lt;/p&gt;
&lt;p&gt;I (apparently) am so used to the more standard 16:9 aspect ratio most monitors come with, that after a few days of adjusting to this new, bigger screen where I can see more lines of code or more info in my browser&apos;s dev tools &lt;em&gt;without having to scroll&lt;/em&gt;, I&apos;m surprised no one really talks about how much of a difference it can make when evaluating external monitors.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://www.benq.com/en-us/knowledge-center/knowledge/boosting-programming-productivity-with-benq-right-aspect-ratio.html&quot;&gt;BenQ website&lt;/a&gt;, this RD280U screen shows 7 more lines of code, but I tell you that for me it is quite a bit more than 7 lines, and I absolutely love it. And all this without me even flipping the monitor into a vertical orientation!&lt;/p&gt;
&lt;p&gt;I am very seriously considering getting another RD280U just so I can have this much extra screen real estate for both my external displays at home.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/benq-monitor-review/side-by-side.png&quot; alt=&quot;Screenshot of amount of code visible on my old HP monitor vs amount of code visible on new RD monitor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Just look at the amount of code visible on my old HP monitor (right side) vs the amount of code visible on the new RD monitor (left side). It&apos;s like night and day.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As humans, we adapt quickly to our current conditions until we get so used to it that they become &quot;normal&quot; to us. Another term for this is habituation.&lt;/p&gt;
&lt;p&gt;Over the years, I&apos;ve developed what I consider a very effective and comfortable work from home setup: laptop stand, external monitors, keyboard and mouse, ergonomic desk chair, and even a small teleprompter screen, and I was quite content with it.&lt;/p&gt;
&lt;p&gt;Then, BenQ reached out to me with the chance to try one of its RD programming series monitors, and my eyes were opened to features I hadn&apos;t even considered I needed as a developer, but made the daily process of writing and reviewing code for hours so much nicer.&lt;/p&gt;
&lt;p&gt;A dedicated &quot;Coding Mode&quot; (with both dark and light modes) that enhances text clarity and contrast, anti-reflective screen, a backlight built in to the monitor itself, auto dimming software measuring ambient light, and a 3:2 aspect ratio that dramatically increased my screen real estate.&lt;/p&gt;
&lt;p&gt;None of these features were things even on my radar before the &lt;a href=&quot;https://benqurl.biz/4oHVx4E&quot;&gt;BenQ RD280U&lt;/a&gt;, but now, I have a hard time imagining working without them.&lt;/p&gt;
&lt;p&gt;If you&apos;re considering an external monitor to enhance or upgrade your own coding practice, I would strongly encourage you to consider the BenQ RD280U or its other RD series monitors built specifically with developers and programmers in mind. I was skeptical at first that a monitor could really improve my day-to-day workflow, but I was wrong.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll check out the BenQ RD line of monitors the next time you need a new monitor. BenQ took the time to understand what improves the developer quality of life, and built a monitor with that really raises the bar with a ton of useful features.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.benq.com/en-us/monitor/programming.html&quot;&gt;BenQ RD series programming monitors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benqurl.biz/4oHVx4E&quot;&gt;BenQ RD280U 28&quot; 3:2 Monitor for Programming&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>advice</category><category>programming</category><category>review</category><category>benq</category></item><item><title>Persist Zoom and Bounds in a React Plotly.js Map</title><link>https://www.paigeniedringhaus.com/blog/persist-zoom-and-bounds-in-a-react-plotlyjs-map/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/persist-zoom-and-bounds-in-a-react-plotlyjs-map/</guid><description>Avoid the reset: keep your map&apos;s zoom level and coordinates stable across re-renders.</description><pubDate>Tue, 20 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import CodeSandbox from &apos;../../src/components/CodeSandbox.astro&apos;;
import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-plotlyjs-maps/react-plotlyjs-map-hero.png&quot; alt=&quot;React Plotly.js map hero image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;There are a fair number of data visualization, charting, and mapping libraries out there for web developers to choose from. A popular, and flexible, set of such libraries goes by the name of &lt;a href=&quot;https://plotly.com/&quot;&gt;&lt;strong&gt;Plotly&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Plotly is used by companies like Intuit and Grafana, which is a pretty good endorsement by itself, so when I needed to build a data visualization dashboard complete with maps and charts for a project at work, I reached for Plotly to help with those parts.&lt;/p&gt;
&lt;p&gt;A nice bonus for me is that Plotly not only has a &lt;a href=&quot;https://www.npmjs.com/package/plotly.js/v/1.47.4&quot;&gt;JavaScript version of its library&lt;/a&gt;, but it also has a &lt;a href=&quot;https://www.npmjs.com/package/react-plotly.js&quot;&gt;React-specific implementation&lt;/a&gt;, and planned to build my web app with the React meta framework Next.js.&lt;/p&gt;
&lt;p&gt;The documentation for the JavaScript implementation of Plotly is decent, but the &lt;a href=&quot;https://plotly.com/javascript/react/&quot;&gt;React Plotly docs&lt;/a&gt;... not so much. While the React docs mention certain code quirks that are unique to the React way of doing things, there is a distinct lack of code samples to help illustrate &lt;em&gt;how to&lt;/em&gt; handle these quirks.&lt;/p&gt;
&lt;p&gt;One such quirk I ran into is around controls within a map: typical interactions like zooming in and out, grabbing and scrolling with mouse clicks, and including useful information in map marker tooltips on hover. For me, after I zoomed or scrolled around the map just a bit, when the React app would re-render (as React apps are wont to do) it would reset to its original map coordinates and zoom level like the page had just been loaded.&lt;/p&gt;
&lt;p&gt;Not one to be beaten by code, I experimented, read code on GitHub, checked the docs, and eventually found my way to how to persist the map&apos;s current state in between re-renders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this blog, I&apos;ll show you how to avoid your Plotly.js map resetting its zoom level and map bounds during a React re-render, and instead persist the user&apos;s last settings so they can keep interacting as if nothing has changed with some simple state handling in the map&apos;s parent component.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here is a working &lt;a href=&quot;https://codesandbox.io/p/devbox/resize-plotlyjs-react-maps-dpzl6y&quot;&gt;demo in CodeSandbox&lt;/a&gt; where you can interact with a map to your heart&apos;s content and never have it reset to its original coordinates as you do so.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=BToSDJTCIDA&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Install Plotly.js and React-Plotly.js&lt;/h2&gt;
&lt;p&gt;In order to use Plotly&apos;s maps and charts inside of a React-based application, the first thing you&apos;ll need to do is install the &lt;a href=&quot;https://plotly.com/javascript/&quot;&gt;&lt;strong&gt;Plotly.js&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://plotly.com/javascript/react/&quot;&gt;&lt;strong&gt;React-Plotly.js libraries&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Run this command in the terminal in the root of your project to add them both.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install react-plotly.js plotly.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other JavaScript projects in the past, I&apos;ve most often reached for the &lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox&lt;/a&gt; library for my mapping needs, but since I also needed data visualizations with a high degree of customization, instead of having to install two different libraries (one for maps, one for charts), I went with Plotly, which offers both.&lt;/p&gt;
&lt;h3&gt;Create a Reusable Map Component&lt;/h3&gt;
&lt;p&gt;Once the Plotly libraries were installed, I created a reusable map component that could simply be passed the data it needs to display.&lt;/p&gt;
&lt;p&gt;Mapbox is a mapping library I&apos;m fairly familiar with so I opted for a &lt;a href=&quot;https://plotly.com/javascript/scatter-tile-maps/#basic-example-(mapbox)&quot;&gt;Plotly Mapbox-style scatter plot map&lt;/a&gt;, but I believe a similar solution will work for the other &lt;a href=&quot;https://plotly.com/javascript/maps/&quot;&gt;Plotly mapping options&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;Here is the full code for my &lt;code&gt;&amp;lt;PlotlyMap/&amp;gt;&lt;/code&gt; component, I&apos;ll explain its contents below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; All of my JavaScript-related code is actually written in TypeScript, so if you prefer to use JavaScript, just know that it can be fairly easily adapted to plain JS by removing things like types from the components and variable declarations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;import dynamic from &quot;next/dynamic&quot;;
import {
  getMarkerColor,
  findMostRecentWithAqiLevel,
  getAverageValue,
  formatTooltipText,
} from &quot;./utils/mapHelpers&quot;;
const Plot = dynamic(() =&amp;gt; import(&quot;react-plotly.js&quot;), { ssr: false });

const PlotlyMap = ({
  data,
  onBoundsChange,
  mapBounds,
}: {
  data: any;
  onBoundsChange;
  mapBounds: any;
}) =&amp;gt; {
  const mapLayout = {
    font: {
      color: &quot;white&quot;,
    },
    dragmode: &quot;zoom&quot;,
    mapbox: {
      center: mapBounds.center,
      zoom: mapBounds.zoom,
      style: &quot;dark&quot;,
    },
    margin: {
      r: 20,
      t: 40,
      b: 20,
      l: 20,
      pad: 0,
    },
    paper_bgcolor: &quot;#191A1A&quot;,
  };

  const config = {
    mapboxAccessToken: process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN,
    scrollZoom: true,
  };

  const preparePlotlyMapData = (data) =&amp;gt; {
    const devicePoints = data.map((row) =&amp;gt; ({
      deviceId: row.at(-1).device,
      lat: getAverageValue(row, &quot;best_lat&quot;),
      lon: getAverageValue(row, &quot;best_lon&quot;),
      location: row.at(-1).best_location,
      aqiLevel: findMostRecentWithAqiLevel(row),
      timestamp: new Date(row.at(-1).when * 1000).getTime(),
    }));

    const mapData = {
      type: &quot;scattermapbox&quot;,
      lat: devicePoints.map((point) =&amp;gt; point.lat),
      lon: devicePoints.map((point) =&amp;gt; point.lon),
      mode: &quot;markers&quot;,
      marker: {
        size: 8,
        color: devicePoints.map((point) =&amp;gt; getMarkerColor(point.aqiLevel)),
      },
      text: formatTooltipText(devicePoints),
    };

    return [mapData];
  };

  return (
      &amp;lt;Plot
        data={preparePlotlyMapData(data)}
        layout={mapLayout}
        config={config}
        onRelayout={onBoundsChange}
        style={{ width: &quot;100%&quot;, height: &quot;100%&quot; }}
        useResizeHandler
      /&amp;gt;
  );
};

export default PlotlyMap;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s talk about the props getting passed to the &lt;code&gt;&amp;lt;PlotlyMap/&amp;gt;&lt;/code&gt; first.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt; - the list of objects with latitude and longitude coordinates to display their positions on the map (plus any other interesting data about the objects that you want to display in a tooltip)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onBoundsChange()&lt;/code&gt; - a function to update the &lt;code&gt;mapBounds&lt;/code&gt; variables (more on this later)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mapBounds&lt;/code&gt; - an object of the map&apos;s current latitude and longitude coordinates: map center, map corners, and the current zoom level&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After these props is the &lt;code&gt;mapLayout&lt;/code&gt; variable that is mostly boilerplate for the Plotly map component setup. The layout sets the background color (&lt;code&gt;paper_bgcolor&lt;/code&gt;), font color, and margins for the map container, the map&apos;s current &lt;code&gt;center&lt;/code&gt; coordinates, &lt;code&gt;zoom&lt;/code&gt;, and map &lt;code&gt;style&lt;/code&gt; (&lt;code&gt;&quot;dark&quot;&lt;/code&gt;), and the ability for a user to click and drag inside the map (&lt;code&gt;dragmode: &quot;zoom&quot;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The next variable is the &lt;code&gt;config&lt;/code&gt; variable which includes a Mapbox API token needed to render the Mapbox tile style in the map container (one of the reasons I like Mapbox is because of the variety of nice map styles they have to choose from), and the &lt;code&gt;scrollZoom&lt;/code&gt; boolean which allows users to zoom in and out of maps using the scroll wheel on their mouse and/or a two-finger scroll.&lt;/p&gt;
&lt;p&gt;Then there is the &lt;code&gt;preparePlotlyMapData()&lt;/code&gt; function that takes in the array of objects from the parent component and loops over them to get the object&apos;s ID, its location coordinates, and the time that device last reported in. Once the &lt;code&gt;devicePoints&lt;/code&gt; are created, the latitude and longitude for each device are fed into the &lt;code&gt;mapData&lt;/code&gt; object which renders each point on the map.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; There are a couple of helper functions inside of the &lt;code&gt;preparePlotlyMapData()&lt;/code&gt; function that I did not cover because they&apos;re not relevant to this blog post.&lt;/p&gt;
&lt;p&gt;The data being displayed in the map is devices that are measuring local air quality, so I&apos;m using the device&apos;s recorded air quality to determine the color of the map marker and add relevant air quality data to the marker&apos;s tooltip.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, all these variables and functions are used in the &lt;code&gt;&amp;lt;Plot/&amp;gt;&lt;/code&gt; component. The data is prepared according to the map&apos;s requirements, the &lt;code&gt;mapLayout&lt;/code&gt; variable tells the map container how to style itself on render, the &lt;code&gt;config&lt;/code&gt; has the Mapbox access token and enables zoom scrolling behavior, the &lt;code&gt;useResizeHandler&lt;/code&gt; property enables automatic resizing of Plotly charts when the browser window size changes, and the &lt;code&gt;onRelayout()&lt;/code&gt; function accepts the &lt;code&gt;onBoundsChange()&lt;/code&gt; function passed by the parent component.&lt;/p&gt;
&lt;p&gt;In the next section, I&apos;ll talk in detail about what the &lt;code&gt;onBoundsChange()&lt;/code&gt; function looks like, but &lt;code&gt;onRelayout()&lt;/code&gt; is used to modify the layout of an existing plot (it works for both charts and maps), and allows for dynamic updates to the plot&apos;s appearance and configuration without redrawing the entire chart.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;onRelayout()&lt;/code&gt; is one of the keys to successfully tracking and persisting the state changes in the map across React component re-renders.&lt;/strong&gt; More details follow in the next section.&lt;/p&gt;
&lt;h3&gt;Leverage React&apos;s useState() to track map state and visible devices in the map container&lt;/h3&gt;
&lt;p&gt;The other key to ensuring the map&apos;s current coordinates, zoom level, and markers persist across component re-renders leverages React &lt;code&gt;useState()&lt;/code&gt; hooks in the parent component. There are two pieces of state that need to be tracked: &lt;code&gt;mapBounds&lt;/code&gt; and &lt;code&gt;mapDataPoints&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;PlotlyMap/&amp;gt;&lt;/code&gt; component is imported directly into a Next.js app&apos;s &lt;code&gt;pages/index.tsx&lt;/code&gt; file, so when you see the code below, you&apos;ll also see some placeholders for Next boilerplate code in addition to the code directly related to preserving the map&apos;s state.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useState, useEffect } from &quot;react&quot;;
import {
  convertObjectToArray,
  groupEventsByDevice,
} from &quot;@/components/utils/helpers&quot;;
import PlotlyMap from &quot;@/components/PlotlyMap&quot;;

const inter = Inter({ subsets: [&quot;latin&quot;] });

type HomeProps = {
  data: any;
};

export default function Home({ data }: HomeProps) {
  const rawData = data;

  const [mapBounds, setMapBounds] = useState({
    center: { lon: -98.5795, lat: 39.8283 },
    zoom: 3,
    topLeft: { lat: 0, lon: 0 },
    topRight: { lat: 0, lon: 0 },
    bottomRight: { lat: 0, lon: 0 },
    bottomLeft: { lat: 0, lon: 0 },
  });


  // devices currently visible on the map after a user pans or zooms
  const [mapDataPoints, setMapDataPoints] = useState([]);
  const [visibleDevices, setVisibleDevices] = useState([]);

  {/* function to set current date range in rendered JSX date components */}

  // group all the events together by device ID
  useEffect(() =&amp;gt; {
    const groupedEventsByDevice = groupEventsByDevice(rawData);
    const devicesList = convertObjectToArray(groupedEventsByDevice);
    setMapDataPoints(devicesList);

    const filteredVisibleDevices = filterVisibleDevicesWithinBounds(
      devicesList,
      mapBounds
    );
    setVisibleDevices(filteredVisibleDevices);
  }, [rawData]);

  const filterVisibleDevicesWithinBounds = (devices, bounds) =&amp;gt; {
    return devices.filter((device) =&amp;gt; {
      const { best_lat, best_lon } = device[0];
      return (
        best_lat &amp;gt;= bounds.bottomLeft.lat &amp;amp;&amp;amp;
        best_lat &amp;lt;= bounds.topLeft.lat &amp;amp;&amp;amp;
        best_lon &amp;gt;= bounds.bottomLeft.lon &amp;amp;&amp;amp;
        best_lon &amp;lt;= bounds.bottomRight.lon
      );
    });
  };

  // when map bounds change, filter out devices that are not within the new bounds
  useEffect(() =&amp;gt; {
    if (mapBounds.topLeft.lat !== 0 &amp;amp;&amp;amp; mapBounds.topLeft.lon !== 0) {
      const filteredVisibleDevices = filterVisibleDevicesWithinBounds(
        mapDataPoints,
        mapBounds
      );
      setVisibleDevices(filteredVisibleDevices);
    }
  }, [mapBounds]);

  const handleMapBoundsChange = (newBounds) =&amp;gt; {
    if (newBounds[&quot;mapbox._derived&quot;]) {
      setMapBounds({
        center: newBounds[&quot;mapbox.center&quot;],
        zoom: newBounds[&quot;mapbox.zoom&quot;],
        topLeft: {
          lat: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][0][1],
          lon: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][0][0],
        },
        topRight: {
          lat: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][1][1],
          lon: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][1][0],
        },
        bottomRight: {
          lat: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][2][1],
          lon: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][2][0],
        },
        bottomLeft: {
          lat: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][3][1],
          lon: newBounds[&quot;mapbox._derived&quot;][&quot;coordinates&quot;][3][0],
        },
      });
    }
  };

  return (
    &amp;lt;&amp;gt;
    {/* Next.js head boilerplate */}
      &amp;lt;main&amp;gt;
        &amp;lt;div&amp;gt;
          {/* page tile and date range display components */}
          &amp;lt;div style={{ width: &quot;100%&quot;, height: &quot;450px&quot; }}&amp;gt;
            &amp;lt;PlotlyMap
              data={mapDataPoints}
              onBoundsChange={handleMapBoundsChange}
              mapBounds={mapBounds}
            /&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;h3&amp;gt;
              Number of devices currently shown on map within map bounds:{&quot; &quot;}
              {visibleDevices.length}
            &amp;lt;/h3&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;h3&amp;gt;Current map bounds:&amp;lt;/h3&amp;gt;
            &amp;lt;p&amp;gt;Northernmost latitude: {mapBounds.topLeft.lat.toFixed(4)}&amp;lt;/p&amp;gt;
            &amp;lt;p&amp;gt;Southernmost latitude: {mapBounds.bottomLeft.lat.toFixed(4)}&amp;lt;/p&amp;gt;
            &amp;lt;p&amp;gt;Westernmost longitude: {mapBounds.bottomLeft.lon.toFixed(4)}&amp;lt;/p&amp;gt;
            &amp;lt;p&amp;gt;Easternmost longitude: {mapBounds.bottomRight.lon.toFixed(4)}&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

export async function getStaticProps() {
  {/* fetch data to display in map here */}

  return {
    props: {
      data,
    },
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I glossed over some of the Next.js code in the component above that&apos;s irrelevant to this article like data fetching, CSS styling, and other page elements like date range display components. If you&apos;d like to see the full code, you can check out this &lt;a href=&quot;https://codesandbox.io/p/devbox/resize-plotlyjs-react-maps-dpzl6y&quot;&gt;Codesandbox demo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now let&apos;s discuss of the variables being tracked in this &lt;code&gt;&amp;lt;Home/&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mapBounds&lt;/code&gt; - an object that tracks all of the map component&apos;s relevant information: map&apos;s center coordinates, zoom level, and coordinates for each map corner&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mapDataPoints&lt;/code&gt; - all of the objects to be displayed as markers on the map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visibleDevices&lt;/code&gt; - once the user&apos;s begun interacting with the map, the full list of &lt;code&gt;mapDataPoints&lt;/code&gt; is filtered down to just the devices currently visible within the map&apos;s visible bounds (I included it here to illustrate how the currently visible objects update and persist on the map even as the component re-renders other parts of the browser with updated data)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the data is fetched from the server (in this case, I&apos;m using a CSV of air quality data produced by &lt;a href=&quot;https://blues.com/products/airnote/&quot;&gt;Blues Airnote devices&lt;/a&gt; located all around the world), the &lt;code&gt;&amp;lt;Home/&amp;gt;&lt;/code&gt; component uses that &lt;code&gt;rawData&lt;/code&gt; variable to group all the air quality events by device ID and then sets that list as the &lt;code&gt;mapDataPoints&lt;/code&gt; array that get passed to the map component.&lt;/p&gt;
&lt;p&gt;Now that same &lt;code&gt;useEffect()&lt;/code&gt; function also calls another function called &lt;code&gt;filterVisibleDevicesWithinBounds()&lt;/code&gt;. This function is what sets the &lt;code&gt;visibleDevices&lt;/code&gt; state variable that displays a count of the devices visible in the map component based on the map&apos;s coordinate bounds underneath the map container in the DOM.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; There is a small bug with this component in that, before a user has interacted with the map immediately after page load, the map bounds (and thus the number of map markers visible) are unknown to the browser.&lt;/p&gt;
&lt;p&gt;As soon as the user does interact, the browser can update all the data points under the map container, but until they do, that data remains unknown. It&apos;s annoying, but a small enough inconvenience I&apos;m willing to overlook it for the sake of this post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Further down in the code, there&apos;s a &lt;code&gt;handleMapBoundsChange()&lt;/code&gt; function that is attached to the &lt;code&gt;&amp;lt;PlotlyMap/&amp;gt;&lt;/code&gt; component&apos;s &lt;code&gt;onRelayout()&lt;/code&gt; function. When that &lt;code&gt;onRelayout()&lt;/code&gt; function is activated by the user interacting with the map, it sends the new map bounds to the &lt;code&gt;handleMapBoundsChange()&lt;/code&gt; function which updates the &lt;code&gt;mapBounds&lt;/code&gt; state in this component.&lt;/p&gt;
&lt;p&gt;When the &lt;code&gt;mapBounds&lt;/code&gt; state is updated the second &lt;code&gt;useEffect()&lt;/code&gt; function that gets triggered and calculates the amount of devices currently visible in the current map bounds.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;mapDataPoints&lt;/code&gt;, &lt;code&gt;mapBounds&lt;/code&gt;, and &lt;code&gt;handleMapBoundsChange()&lt;/code&gt; function are all passed to the &lt;code&gt;&amp;lt;PlotlyMap/&amp;gt;&lt;/code&gt; component and any time the user interacts with the map, the new map bounds and zoom level get passed back to this parent component, and the map state is updated and persisted, even as map coordinates and amount of devices visible on screen are also updated and re-rendered.&lt;/p&gt;
&lt;h3&gt;Interact with the map component and verify the coordinates and device count persist&lt;/h3&gt;
&lt;p&gt;If you&apos;d like to see a working demo of how you can interact with a React Plotly.js map full of markers and see other data on the screen update while the map bounds and interactions persist, I&apos;ve got a CodeSandbox for you to try out.&lt;/p&gt;
&lt;p&gt;&amp;lt;CodeSandbox url=&quot;https://codesandbox.io/p/devbox/resize-plotlyjs-react-maps-dpzl6y&quot; file=&quot;/src/pages/index.tsx&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;Open a terminal inside of Codesandbox and type &lt;code&gt;npm run dev&lt;/code&gt; to get it started.&lt;/p&gt;
&lt;p&gt;In addition to the &lt;code&gt;&amp;lt;PlotlyMap/&amp;gt;&lt;/code&gt; component, I also included a couple of Ant Design date picker components to display the entire date range of the data from the CSV (July 16, 2024 to July 18, 2024).&lt;/p&gt;
&lt;p&gt;Feel free to zoom on in on different parts of the map, drag and scroll around, and hover over markers for additional info in tooltips. Every time you interact with the map, coordinates and count of devices being displayed on screen should update accordingly.&lt;/p&gt;
&lt;p&gt;And if you want to, comment out the &lt;code&gt; onRelayout={onBoundsChange}&lt;/code&gt; line of code inside of the &lt;code&gt;&amp;lt;PlotlyMap/&amp;gt;&lt;/code&gt; component&apos;s JSX, refresh the browser and then try zooming in or navigating around inside the map. You should see now that the count of visible devices and map coordinates displayed under the map don&apos;t update despite the user interactions.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Plotly is a great, open source data visualization and map component library, made even more convenient for a JavaScript-heavy web developer like me by the fact that it has a library dedicated specifically to working well with the React JS framework.&lt;/p&gt;
&lt;p&gt;Initially when I tried to use React Plotly to render a bunch of objects as markers on a map, shortly after I&apos;d start interacting with the map, when a React re-render would occur I&apos;d be back to square one as if I hadn&apos;t touched the map at all.&lt;/p&gt;
&lt;p&gt;The trick, I learned, was to keep track of the map&apos;s current state in the parent component, and lean on the &lt;code&gt;onRelayout()&lt;/code&gt; function inside of the map component itself to persist the map&apos;s current view while DOM elements around it changed. Once I started tracking those things, map interactions worked as expected.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope if you choose to use a Plotly.js map inside of your own React-based project you&apos;ll find these tips on persisting the map&apos;s current state across component re-renders useful. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://plotly.com/javascript/react/&quot;&gt;React Plotly.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plotly.com/javascript/&quot;&gt;Plotly JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codesandbox.io/p/devbox/resize-plotlyjs-react-maps-dpzl6y&quot;&gt;CodeSandbox demo of persistent map coordinates and zoom level with React Plotly.js map&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category><category>nextjs</category><category>plotlyjs</category><category>maps</category></item><item><title>How to Cross Link Plotly.js Charts in a React App</title><link>https://www.paigeniedringhaus.com/blog/how-to-cross-link-plotlyjs-charts-in-a-react-app/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/how-to-cross-link-plotlyjs-charts-in-a-react-app/</guid><description>A simple custom implementation to cross link JavaScript Plotly charts.</description><pubDate>Wed, 19 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;
import CodeSandbox from &apos;../../src/components/CodeSandbox.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-plotlyjs-charts/react-plotly-charts-hero.png&quot; alt=&quot;React Plotly.js Cross Linked Charts on a dashboard page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://plotly.com/&quot;&gt;&lt;strong&gt;Plotly&lt;/strong&gt;&lt;/a&gt; is a powerful, highly customizable set of open source, browser-based graphing libraries for JavaScript and Python. It&apos;s used by the likes of companies as big as Intuit and Grafana, so when I needed to build a data visualization heavy dashboard for a project at work, I looked to Plotly for help with the charts, graphs, and maps the app required.&lt;/p&gt;
&lt;p&gt;Especially appealing to me is the fact that not only does Plotly have a &lt;a href=&quot;https://www.npmjs.com/package/plotly.js/v/1.47.4&quot;&gt;JavaScript version of its library&lt;/a&gt;, but it also has a &lt;a href=&quot;https://www.npmjs.com/package/react-plotly.js&quot;&gt;React-specific version&lt;/a&gt;, which is one of the JavaScript frameworks I use most day-to-day.&lt;/p&gt;
&lt;p&gt;Unfortunately, although Plotly has implementations in multiple languages, they don&apos;t have complete feature parity. The feature I was most interested in was the ability to zoom in on a section of one timeseries-based chart, and have any other related charts on the page automatically show the same time selection - a functionality known as &lt;strong&gt;cross linking&lt;/strong&gt; or &lt;strong&gt;cross filtering&lt;/strong&gt;. The Python version of Plotly has the ability to cross link charts right out of the box, but the JavaScript and React versions do not.&lt;/p&gt;
&lt;p&gt;Lucky for me, I&apos;m a web developer, and if something&apos;s not already available via a library, I&apos;ll figure out a way to build it myself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will demonstrate how you can to make your own cross linked Plotly.js charts inside of a Next.js application by using a shared parent component to manage the date ranges.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s what the cross linked charts look like and a link to a &lt;a href=&quot;https://codesandbox.io/p/devbox/cross-link-plotlyjs-charts-dj78t3&quot;&gt;live demo in CodeSandbox&lt;/a&gt; you can interact with.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=Vy3HOUMsL8o&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Install Plotly.js and React-Plotly.js&lt;/h2&gt;
&lt;p&gt;To use Plotly data visualizations inside of a React-based application, you&apos;ll need to install the &lt;a href=&quot;https://plotly.com/javascript/&quot;&gt;&lt;strong&gt;Plotly.js&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://plotly.com/javascript/react/&quot;&gt;&lt;strong&gt;React-Plotly.js libraries&lt;/strong&gt;&lt;/a&gt; first.&lt;/p&gt;
&lt;p&gt;Run this command in the terminal in the root of your project to add them both.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install react-plotly.js plotly.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As I said earlier, Plotly is a flexible, well documented, open source data visualization library, and the amount of customization it offers for even very complex charts and graphs makes it a good choice for dashboards that need to display this type of information.&lt;/p&gt;
&lt;h3&gt;Create a Reusable Chart Component&lt;/h3&gt;
&lt;p&gt;The first thing to do after installing the Plotly libraries inside of a React-based application is to create a reusable chart component that can display different values passed to it from the parent component.&lt;/p&gt;
&lt;p&gt;For me, a &lt;a href=&quot;https://plotly.com/javascript/line-charts/&quot;&gt;Plotly line chart&lt;/a&gt; was one of the chart types that made the most sense to have on hand, but this sort of reusable React component structure should translate pretty well to many different &lt;a href=&quot;https://plotly.com/javascript/basic-charts/&quot;&gt;Plotly chart types&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is the full code for my &lt;code&gt;&amp;lt;PlotlyLineChart/&amp;gt;&lt;/code&gt; component, I&apos;ll go through each of the pieces in it below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; All of my JavaScript-related code is actually written in TypeScript, so if you prefer to use JavaScript, just know that it can be fairly easily adapted to plain JS by removing things like types from the components and variable declarations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;import dynamic from &quot;next/dynamic&quot;;
const Plot = dynamic(() =&amp;gt; import(&quot;react-plotly.js&quot;), { ssr: false });

const PlotlyLineChart = ({
  title,
  data,
  property,
  displayValue,
  startDate,
  endDate,
  setDate,
  maxStartDate,
  maxEndDate,
}: {
  title: string;
  data: any[];
  property: string;
  displayValue?: string;
  startDate: Date;
  endDate: Date;
  setDate: ({ startDate, endDate }: { startDate: Date; endDate: Date }) =&amp;gt; void;
  maxStartDate: Date;
  maxEndDate: Date;
}) =&amp;gt; {
  const layout = {
    width: 640,
    height: 480,
    title: title,
    xaxis: {
      autorange: false, // determines whether or not the range of the axis is computed in relation to the input data
      range: [startDate, endDate],
      rangeselector: {
        buttons: [
          {
            step: &quot;day&quot; as &quot;day&quot;,
            stepmode: &quot;backward&quot; as &quot;backward&quot;,
            count: 1,
            label: &quot;1d&quot;,
          },
          {
            step: &quot;day&quot; as &quot;day&quot;,
            stepmode: &quot;backward&quot; as &quot;backward&quot;,
            count: 2,
            label: &quot;2d&quot;,
          },
          {
            step: &quot;week&quot; as &quot;week&quot;,
            stepmode: &quot;backward&quot; as &quot;backward&quot;,
            count: 1,
            label: &quot;1w&quot;,
          },
          {
            step: &quot;month&quot; as &quot;month&quot;,
            stepmode: &quot;backward&quot; as &quot;backward&quot;,
            count: 1,
            label: &quot;1m&quot;,
          },
          {
            step: &quot;year&quot; as &quot;year&quot;,
            stepmode: &quot;backward&quot; as &quot;backward&quot;,
            count: 1,
            label: &quot;1y&quot;,
          },
          {
            step: &quot;all&quot; as &quot;all&quot;,
          },
        ],
      },
      rangeslider: { range: [maxStartDate, maxEndDate] as [Date, Date] },
      type: &quot;date&quot; as &quot;date&quot;,
    },
    yaxis: { title: displayValue },
  };

  const prepareChartData = () =&amp;gt; {
    if (data.length === 0) return [];

    // loop through each array of device events and create a trace for each device
    const traces = data.map((device: any) =&amp;gt; {
      return {
        type: &quot;scatter&quot;,
        mode: &quot;lines+markers&quot;,
        name: device[0].device,
        x: device.map((event: { when: number }) =&amp;gt; new Date(event.when * 1000)),
        y: device.map(
          (event: { [x: string]: number }) =&amp;gt;
            Math.round(event[property] * 10) / 10
        ),
      };
    });

    return traces;
  };

  const handleRelayout = (event: any) =&amp;gt; {
    if (event[&quot;xaxis.autorange&quot;]) {
      setDate({ startDate: maxStartDate, endDate: maxEndDate });
    } else {
      let rangeLeft = event[&quot;xaxis.range[0]&quot;] || event[&quot;xaxis.range&quot;][0];
      let rangeRight = event[&quot;xaxis.range[1]&quot;] || event[&quot;xaxis.range&quot;][1];
      if (rangeLeft &amp;amp;&amp;amp; rangeRight) {
        setDate({
          startDate: rangeLeft,
          endDate: rangeRight,
        });
      }
    }
  };

  return (
    &amp;lt;Plot
      data={prepareChartData()}
      layout={layout}
      onRelayout={handleRelayout}
    /&amp;gt;
  );
};

export default PlotlyLineChart;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is &lt;em&gt;a lot&lt;/em&gt; of code here, I know, but it&apos;s not actually as complicated as it might seem at first.&lt;/p&gt;
&lt;p&gt;First: the many props being passed to the component, which serve to make it reusable in the app for many different line charts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt; - the title text to display above the line chart&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt; - the list of objects and their values to display inside of the chart&lt;/li&gt;
&lt;li&gt;&lt;code&gt;property&lt;/code&gt; - the name of the property inside of each object to get the value for and display in the graph (for instance, the property of &lt;code&gt;voltage&lt;/code&gt; to show device voltage over time)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;displayValue&lt;/code&gt; - the title to display on the Y-axis of the graph (the X-axis will always show dates)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;startDate&lt;/code&gt; - the currently selected beginning of the date range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;endDate&lt;/code&gt; - the currently selected end date of the date range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setDate&lt;/code&gt; - a function to update the current &lt;code&gt;startDate&lt;/code&gt; and &lt;code&gt;endDate&lt;/code&gt; variables&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxStartDate&lt;/code&gt; - the earliest date timestamp based on the data present in the parent component&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxEndDate&lt;/code&gt; - the latest date timestamp based on the data present in the parent component&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next is the &lt;code&gt;layout&lt;/code&gt; object, which is mostly boilerplate for the Plotly component. The layout takes in some of the props like &lt;code&gt;title&lt;/code&gt;, the &lt;code&gt;range&lt;/code&gt; for the x-axis (&lt;code&gt;startDate&lt;/code&gt; and &lt;code&gt;endDate&lt;/code&gt;), the maximum date range of &lt;code&gt;maxStartDate&lt;/code&gt; and &lt;code&gt;maxEndDate&lt;/code&gt; for the &lt;code&gt;rangeslider&lt;/code&gt; (the mini version of the line chart underneath the main chart), and the &lt;code&gt;displayValue&lt;/code&gt; string for the y-axis.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;rangeselector&lt;/code&gt; code which takes up a fair amount of space is actually just directions for a series of buttons that allow users to quickly choose different time ranges to view in the chart. It can accept values like &quot;month&quot;, &quot;year&quot;, &quot;day&quot;, &quot;hour&quot;, &quot;minute&quot;, or &quot;second&quot;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;prepareChartData()&lt;/code&gt; function is where the array of data passed to the chart is transformed into &quot;traces&quot; that the Plotly chart requires. For my scenario, each item in the array has a &lt;code&gt;device&lt;/code&gt; property which is a unique ID, a &lt;code&gt;when&lt;/code&gt; property that is a timestamp for the x-axis of the graph in &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_time&quot;&gt;Unix time&lt;/a&gt;, and whatever numeric value the &lt;code&gt;property&lt;/code&gt; prop passed into the component matches. The appropriate data is pulled from each item and the final list of &lt;code&gt;traces&lt;/code&gt; data ends up being organized by device ID.&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;handleRelayout()&lt;/code&gt; function helps the chart&apos;s parent component knows when a user zooms in or out on a particular section of a chart. It uses the &lt;code&gt;setDate()&lt;/code&gt; function prop passed from the parent component to ensure that the parent&apos;s view of the currently selected dates stays accurate. &lt;strong&gt;This is one of the keys to cross linking multiple charts in the project.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;These pieces of set up code: the &lt;code&gt;layout&lt;/code&gt; variable, &lt;code&gt;prepareChartData()&lt;/code&gt;, and &lt;code&gt;handleRelayout()&lt;/code&gt; are all passed to the &lt;code&gt;&amp;lt;Plot/&amp;gt;&lt;/code&gt; component, and then it can render a JavaScript version of the appropriate data visualization.&lt;/p&gt;
&lt;p&gt;Ok, that&apos;s enough time spent on this reusable chart component. Let&apos;s move on to tracking the date state next.&lt;/p&gt;
&lt;h3&gt;Leverage React&apos;s useState() to track date selections in the charts&lt;/h3&gt;
&lt;p&gt;The other key to ensuring that all Plotly charts in a React application are showing the same selected date range relies on React&apos;s &lt;code&gt;useState()&lt;/code&gt; hook in a shared parent component. For my particular Next.js application, it made sense for me to import my &lt;code&gt;&amp;lt;PlotlyLineChart/&amp;gt;&lt;/code&gt; component directly into my &lt;code&gt;pages/index.tsx&lt;/code&gt; file, so when you view the code below, you&apos;ll see a few placeholders for the Next pages boilerplate code mixed in with the code specific to cross linking the charts.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useState, useEffect } from &quot;react&quot;;
import dayjs from &quot;dayjs&quot;;
import {
  convertObjectToArray,
  groupEventsByDevice,
} from &quot;@/components/utils/helpers&quot;;
import PlotlyLineChart from &quot;@/components/PlotlyLineChart&quot;;

type HomeProps = {
  data: any;
};

export default function Home({ data }: HomeProps) {
  const rawData = data;

  const [initialDate, setInitialDateRange] = useState({
    startDate: dayjs(),
    endDate: dayjs(),
  });

  const [selectedDate, setSelectedDateRange] = useState({
    startDate: dayjs(),
    endDate: dayjs(),
  });

  const [devices, setDevices] = useState&amp;lt;any&amp;gt;([]);
  const [mostActiveDevices, setMostActiveDevices] = useState&amp;lt;any&amp;gt;([]);

  useEffect(() =&amp;gt; {
    if (rawData.length &amp;gt; 0) {
      getInitialDateRange(rawData);
    }
  }, [rawData]);

  function getInitialDateRange(data: any[]) {
    data.sort((a, b) =&amp;gt; {
      return Number(new Date(a.when * 1000)) - Number(new Date(b.when * 1000));
    });

    // set initial start date and end date for charts
    const startDate = new Date(data[0].when * 1000);
    const endDate = new Date(data[data.length - 1].when * 1000);
    setInitialDateRange({ startDate: startDate, endDate: endDate });
    setSelectedDateRange({ startDate: startDate, endDate: endDate });
  }

  // group all the events together by device ID
  useEffect(() =&amp;gt; {
    const groupedEventsByDevice = groupEventsByDevice(rawData);
    const deviceList = convertObjectToArray(groupedEventsByDevice);

    setDevices(deviceList);
  }, [rawData, selectedDate]);

  // set the 5 most active devices
  useEffect(() =&amp;gt; {
    if (devices.length &amp;gt; 0) {
      setMostActiveDevices(
        devices.sort((a, b) =&amp;gt; b.length - a.length).slice(0, 5)
      );
    }
  }, [devices]);

  return (
    &amp;lt;&amp;gt;
    {/* Next.js head boilerplate */}
      &amp;lt;main&amp;gt;
        &amp;lt;div&amp;gt;
          {/* page tile and date range display components */}
          &amp;lt;div&amp;gt;
            &amp;lt;PlotlyLineChart
              title={&quot;Most Active Device Temperature&quot;}
              data={mostActiveDevices}
              property={&quot;temp&quot;}
              displayValue=&quot;Celsius&quot;
              startDate={selectedDate.startDate}
              endDate={selectedDate.endDate}
              setDate={setSelectedDateRange}
              maxStartDate={initialDate.startDate}
              maxEndDate={initialDate.endDate}
            /&amp;gt;
            &amp;lt;PlotlyLineChart
              title={&quot;Most Active Device Voltage&quot;}
              data={mostActiveDevices}
              property={&quot;voltage&quot;}
              displayValue=&quot;Voltage&quot;
              startDate={selectedDate.startDate}
              endDate={selectedDate.endDate}
              setDate={setSelectedDateRange}
              maxStartDate={initialDate.startDate}
              maxEndDate={initialDate.endDate}
            /&amp;gt;
            &amp;lt;PlotlyLineChart
              title={&quot;Most Active Device RSSI&quot;}
              data={mostActiveDevices}
              property={&quot;rssi&quot;}
              displayValue={&quot;&quot;}
              startDate={selectedDate.startDate}
              endDate={selectedDate.endDate}
              setDate={setSelectedDateRange}
              maxStartDate={initialDate.startDate}
              maxEndDate={initialDate.endDate}
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

export async function getStaticProps() {
  {/* fetch data to display in charts here */}

  return {
    props: {
      data,
    },
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As I mentioned, I put in some placeholders for code that&apos;s not really relevant to the cross linking, so bits like data fetching, CSS styling, and some of the other HTML elements like the date range display components are omitted to keep the code cleaner. If you&apos;d like to see the full code, you can check out this &lt;a href=&quot;https://codesandbox.io/p/devbox/cross-link-plotlyjs-charts-dj78t3&quot;&gt;CodeSandbox demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s discuss some of the variables being tracked in this &lt;code&gt;&amp;lt;Home/&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;initialDate&lt;/code&gt; - the maximum starting and ending date range for the charts (determined by the data fetched from the server)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;selectedDate&lt;/code&gt; - the user selected starting and ending date range being viewed on the charts at any time (on page load these dates are the same as the &lt;code&gt;initialDate&lt;/code&gt; object&apos;s values)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devices&lt;/code&gt; - after data is fetched from the server, it&apos;s grouped by device IDs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mostActiveDevices&lt;/code&gt; - once the data is grouped by device ID, the devices are sorted by how many data events each one has associated with it, and the top 5 devices are passed to the chart components&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the data is fetched from the server (in this case, I&apos;m using a CSV of air quality data produced by &lt;a href=&quot;https://blues.com/products/airnote/&quot;&gt;Blues Airnote devices&lt;/a&gt; located all around the world), the &lt;code&gt;&amp;lt;Home/&amp;gt;&lt;/code&gt; component uses that data to determine the starting and ending date ranges and sets the &lt;code&gt;initialDate&lt;/code&gt; and &lt;code&gt;selectedDate&lt;/code&gt; objects via the &lt;code&gt;getInitialDates()&lt;/code&gt; function. Each row of data from the CSV has a Unix timestamp associated with it, hence the date manipulations inside the function. These date objects will then get passed to the &lt;code&gt;&amp;lt;PlotlyLineChart/&amp;gt;&lt;/code&gt; components further down in the code.&lt;/p&gt;
&lt;p&gt;After the first &lt;code&gt;useEffect()&lt;/code&gt; that sets the dates, a second &lt;code&gt;useEffect()&lt;/code&gt; is called to group all of the data from the CSV by device ID (each row of data from the server has a device ID included in it), and the &lt;code&gt;devices&lt;/code&gt; variable is set.&lt;/p&gt;
&lt;p&gt;And last, the &lt;code&gt;devices&lt;/code&gt; array sorts all the objects in it by how many events each device has, and the top 5 devices are chosen to be set as the &lt;code&gt;mostActiveDevices&lt;/code&gt;, which will then be passed to the &lt;code&gt;&amp;lt;PlotlyLineChart/&amp;gt;&lt;/code&gt; component as well.&lt;/p&gt;
&lt;p&gt;Now all the data needed by the chart components is ready to be supplied to them. The &lt;code&gt;initialDate&lt;/code&gt; and &lt;code&gt;selectedDate&lt;/code&gt; data gets passed in as &lt;code&gt;startDate/endDate&lt;/code&gt; and &lt;code&gt;maxStartDate/maxEndDate&lt;/code&gt;. The &lt;code&gt;setSelectedDate()&lt;/code&gt; function gets passed to the &lt;code&gt;setDate()&lt;/code&gt; function within the component. The &lt;code&gt;mostActiveDevices&lt;/code&gt; list is passed in as the &lt;code&gt;data&lt;/code&gt; for the chart to render. And the &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;property&lt;/code&gt;, and &lt;code&gt;displayValue&lt;/code&gt; are all strings passed to each chart. For the data I was using, I had values like &lt;code&gt;temp&lt;/code&gt;, &lt;code&gt;voltage&lt;/code&gt;, and &lt;code&gt;rssi&lt;/code&gt; (received signal strength indicator - used to describe wireless signal strength) available to me, so I chose to display those in the line charts.&lt;/p&gt;
&lt;p&gt;And that&apos;s basically all you need to do cross link your charts in your React application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The thing to understand about this component is that it controls the state for the dates that gets passed to all the chart components. As the &lt;code&gt;selectedDate&lt;/code&gt; is updated via &lt;code&gt;setSelectedDate()&lt;/code&gt; by the user interacting with any of the charts, it sends the new &lt;code&gt;selectedDate&lt;/code&gt; state down to all the charts to display.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Test out the cross linked charts&lt;/h3&gt;
&lt;p&gt;If you&apos;d like to see a working demo of these cross linked Plotly charts in action, I&apos;ve got a CodeSandbox for you to try out.&lt;/p&gt;
&lt;p&gt;&amp;lt;CodeSandbox url=&quot;https://codesandbox.io/p/devbox/cross-link-plotlyjs-charts-dj78t3&quot; file=&quot;/src/pages/index.tsx&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;Open a terminal and type &lt;code&gt;npm run dev&lt;/code&gt; to get it started.&lt;/p&gt;
&lt;p&gt;In addition to the &lt;code&gt;&amp;lt;PlotlyLineChart/&amp;gt;&lt;/code&gt; component, I also included a couple of Ant Design date picker components to display the entire date range of the data from the CSV (July 16, 2024 to July 18, 2024).&lt;/p&gt;
&lt;p&gt;Feel free to zoom on in on different parts of different charts or on the range sliders below the charts, or click the range selector buttons above each chart. Every time you interact with one chart, all the other charts should update accordingly. Pretty cool!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When I saw how the Python implementation of Plotly cross linked charts so when a user interacted with one on the page all of them adjusted, I knew I wanted that same functionality in my JavaScript application. Unfortunately, Plotly didn&apos;t have feature in the React version of the library, so I had to build it myself.&lt;/p&gt;
&lt;p&gt;It turned out to be fairly simple just by having a parent component keep track of the selected date range that was passed to all the chart components, and reacting accordingly when a user updated the date range in one chart by passing that same date range to all the charts.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope if you want to cross link multiple charts inside of your own dashboard (whether they&apos;re Plotly.js charts or another data viz library) you&apos;ll consider giving this solution a try and just lifting the date state up one level so it can be passed to all the charts at once. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://plotly.com/javascript/react/&quot;&gt;React Plotly.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plotly.com/javascript/&quot;&gt;Plotly JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codesandbox.io/p/devbox/cross-link-plotlyjs-charts-dj78t3&quot;&gt;CodeSandbox demo of cross linked Plotly charts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category><category>nextjs</category><category>plotlyjs</category><category>data visualization</category></item><item><title>Build a Custom Time Slider Component with Ant Design and Next.js</title><link>https://www.paigeniedringhaus.com/blog/build-a-custom-time-slider-component-with-ant-design-and-nextjs/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/build-a-custom-time-slider-component-with-ant-design-and-nextjs/</guid><description>With the right building blocks, even complex UI components don&apos;t require weeks of effort to achieve.</description><pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;
import CodeSandbox from &apos;../../src/components/CodeSandbox.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/custom-antd-time-slider/hero.png&quot; alt=&quot;Ant Design custom date range slider with differently styled future dates&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Part of my job as a software engineer working for a startup involves building proof of concept (POC) web apps quickly, and one of my preferred tech stacks for such a project is a Next.js application in conjunction with the Ant Design component library.&lt;/p&gt;
&lt;p&gt;I&apos;m a fan of &lt;a href=&quot;https://ant.design/&quot;&gt;Ant Design&lt;/a&gt; because it&apos;s a library I&apos;m familiar with, and it offers &lt;em&gt;a lot&lt;/em&gt; of more complicated components (think filterable tables, nested trees, complex forms, date pickers, and so on) that are highly customizable and just work right out of the box.&lt;/p&gt;
&lt;p&gt;When I was tasked recently with building a web app that contained a time slider akin to the adjustable sliders you see in interactive weather maps or other time series data applications that would allow a user to adjust the visible time range within a predetermined set of dates, because I couldn&apos;t find a suitable, React-based component or package already available, I ended up modifying a basic Ant Design slider component to suit my needs.&lt;/p&gt;
&lt;p&gt;My time slider component modifies its tick mark date formatting appropriately based on how big or small the original time span is, it allows users to drag the slider from either end to adjust the currently selected date range, it allows for date ranges set in the future, and it even delineates on the slider between past dates and future dates with different colors and styling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to build your own custom time slider inside of a Next.js application using the Ant Design &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component and the Day.js date formatting library.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s what the final adjustable time slider component looks like and a link to the &lt;a href=&quot;https://codesandbox.io/p/devbox/custom-time-slider-nextjs-ant-design-kcxm75&quot;&gt;live demo site in CodeSandbox&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=LYYZ9lFvx90&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Install Ant Design and Day.js&lt;/h2&gt;
&lt;p&gt;The two libraries you&apos;ll need to add to a React-based application to build this custom time range slider are the &lt;a href=&quot;https://ant.design/&quot;&gt;&lt;strong&gt;Ant Design library&lt;/strong&gt;&lt;/a&gt; and the &lt;a href=&quot;https://day.js.org/&quot;&gt;&lt;strong&gt;Day.js&lt;/strong&gt;&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;Run this command in the terminal in the root of your project to add them both.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install antd dayjs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As I said before, Ant Design is a great, full-featured, very well documented component library I&apos;ve worked with many times in the past and it makes building complex web apps that contain elements like drawers, cards, cascading selects, and a host of other components much quicker and easier to get going.&lt;/p&gt;
&lt;p&gt;Ant Design uses Day.js by default, and Day.js is a lightweight, JavaScript library that parses, validates, manipulates, and displays dates and times with a largely Moment.js-compatible API. If you&apos;ve ever used Moment to handle dates in a JavaScript application, you&apos;ll feel right at home with Day.js, with the added bonus that it&apos;s a fraction of the size of Moment.&lt;/p&gt;
&lt;h3&gt;Ant Design Slider&lt;/h3&gt;
&lt;p&gt;One particularly useful component that Ant Design offers is a &lt;a href=&quot;https://ant.design/components/slider&quot;&gt;&lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt;&lt;/a&gt; component with a lot of customizable functionality not many other sliders contain.&lt;/p&gt;
&lt;p&gt;For my app, I needed a slider that could:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select a range within the slider&apos;s bound (instead of being anchored to one end of the slider or the other),&lt;/li&gt;
&lt;li&gt;Allow that range track to be dragged within the slider.&lt;/li&gt;
&lt;li&gt;Offer customizable tick marks, tooltips, and range track styles.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Day.js&lt;/h3&gt;
&lt;p&gt;Working with dates in JavaScript applications is still quite the pain, even today without a supporting date library. The Day.js library is a faster, smaller alternative to Moment.js, an extremely popular library for handling dates and times, with a very similar API and great internationalization support.&lt;/p&gt;
&lt;p&gt;To make dates work for my app with the Ant Design slider, I needed a library that could:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Transform human readable dates like &quot;2024-12-01&quot; into Unix millisecond timestamps, because the slider expects numbers (not date formatted objects) to be passed to it in order to work correctly&lt;/li&gt;
&lt;li&gt;Format those same dates appropriately for tick marks of varying date spans&lt;/li&gt;
&lt;li&gt;Format said date for hoverable tooltips as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The Day.js library is capable of all this and more with simple, easy to understand functions and great documentation, and since it&apos;s the default library for Ant Design anyway, it make sense to just fall in line with what Ant D knows best.&lt;/p&gt;
&lt;h2&gt;Create a TimeSlider component&lt;/h2&gt;
&lt;p&gt;Once those two libraries are installed in the project, it&apos;s time to move on to actually creating the &lt;code&gt;&amp;lt;TimeSlider/&amp;gt;&lt;/code&gt; component. Below is the starting code for the component. I&apos;ll go through all the pieces that comprise it afterwards.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Col, Row, Slider } from &quot;antd&quot;;
import dayjs, { Dayjs } from &quot;dayjs&quot;;

type TimeSliderProps = {
  outerDateRange: { from: Dayjs; upto: Dayjs };
  innerDateRange: { from: Dayjs; upto: Dayjs };
  onChange: (innerDateRange: { from: Dayjs; upto: Dayjs }) =&amp;gt; void;
};

const TimeSlider = ({
  outerDateRange,
  innerDateRange,
  onChange,
}: TimeSliderProps) =&amp;gt; {
  const min = outerDateRange.from.valueOf();
  const max = outerDateRange.upto.valueOf();
  const values: [number, number] = [
    innerDateRange.from.valueOf(),
    innerDateRange.upto.valueOf(),
  ];

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Row&amp;gt;
        &amp;lt;Col span={24}&amp;gt;
          &amp;lt;Slider
            range={{ draggableTrack: true }}
            min={min}
            max={max}
            value={values}
            onChange={(value: number[]) =&amp;gt; {
              onChange({
                from: dayjs(value[0]),
                upto: dayjs(value[1]),
              });
            }}
          /&amp;gt;
        &amp;lt;/Col&amp;gt;
      &amp;lt;/Row&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default TimeSlider;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I created a new file called &lt;code&gt;TimeSlider.tsx&lt;/code&gt; where all this code is going to live, and made a basic shell of the component that accepts the props &lt;code&gt;outerDateRange&lt;/code&gt;, &lt;code&gt;innerDateRange&lt;/code&gt;, and &lt;code&gt;onChange()&lt;/code&gt; from the parent component. Later on in this article I&apos;ll show you how to set up the required state and functions in the parent component to pass down to this component.&lt;/p&gt;
&lt;p&gt;As this is actually a TypeScript file, this component also gets its own &lt;code&gt;TimeSliderProps&lt;/code&gt; types defined for each of the props being passed to it. This is where the &lt;code&gt;Day.js&lt;/code&gt; library initially comes into play as well, as the type for &lt;code&gt;outerDateRange&lt;/code&gt;, &lt;code&gt;innerDateRange&lt;/code&gt;, and even the &lt;code&gt;onChange()&lt;/code&gt; function expect Day.js dates to be passed to them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; All of my JavaScript-related code is actually written in TypeScript, so if you prefer to use JavaScript, just know that it can be fairly easily adapted to plain JS by removing things like types from the components and variable declarations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Inside of this component we&apos;re going to set a bunch of variables required by the Ant &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component to render properly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; variable to tell the slider what it&apos;s beginning and ending values are.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;values&lt;/code&gt; object that is an array of the &lt;code&gt;innerDateRange&lt;/code&gt;&apos;s &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;upto&lt;/code&gt; values.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; For the range slider to work as you&apos;d expect with date objects, the dates must be converted to Unix Epoch time, that is why you&apos;ll notice both the &lt;code&gt;outerDateRange&lt;/code&gt; and &lt;code&gt;innerDateRange&lt;/code&gt; dates are being called with the Day.js library&apos;s &lt;a href=&quot;https://day.js.org/docs/en/display/unix-timestamp-milliseconds&quot;&gt;&lt;code&gt;valueOf()&lt;/code&gt; function&lt;/a&gt;. This takes the date and turns it into a Unix Timestamp in milliseconds, which can then be passed to the &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the bare minimum of data the Ant Design component will need to actually render onscreen. Then, it&apos;s time to create the component with the help of the Ant Design &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; element and pass the necessary details to it.&lt;/p&gt;
&lt;p&gt;For a bit of nicer formatting, I also employed Ant Design&apos;s &lt;code&gt;&amp;lt;Col/&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Row/&amp;gt;&lt;/code&gt; elements, but those are not required for this component to work. They help the component to lay out in a horizontal fashion and take up as much space as the screen width will allow.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component itself requires the &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; variables, the &lt;code&gt;values&lt;/code&gt; array, the &lt;code&gt;onChange()&lt;/code&gt; function, and in order to make it a range slider whose track can be dragged, the &lt;code&gt;range={{draggableTrack: true}}&lt;/code&gt; value must be added to the slider&apos;s props.&lt;/p&gt;
&lt;p&gt;If this component were to receive valid dates right now, it should render, albeit without much to see. Let&apos;s keep going.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/custom-antd-time-slider/basic-slider-1.png&quot; alt=&quot;Ant Design barebones custom date range slider&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Calculate and style the tick marks to handle different date ranges appropriately&lt;/h3&gt;
&lt;p&gt;The next step is to calculate the tick marks that will appear along the slider&apos;s track showing the range of the slider.&lt;/p&gt;
&lt;p&gt;Here&apos;s the code that will get added to the &lt;code&gt;TimeSlider.tsx&lt;/code&gt; component to make that happen.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Col, Row, Slider } from &quot;antd&quot;;
import { SliderRangeProps } from &quot;antd/lib/slider&quot;;
import dayjs, { Dayjs } from &quot;dayjs&quot;;

type TimeSliderProps = {
  outerDateRange: { from: Dayjs; upto: Dayjs };
  innerDateRange: { from: Dayjs; upto: Dayjs };
  onChange: (innerDateRange: { from: Dayjs; upto: Dayjs }) =&amp;gt; void;
};

const TimeSlider = ({
  outerDateRange,
  innerDateRange,
  onChange,
}: TimeSliderProps) =&amp;gt; {
  const min = outerDateRange.from.valueOf();
  const max = outerDateRange.upto.valueOf();
  const tickCount = 15;
  const tickInterval = Math.floor((max - min) / tickCount);
  const values: [number, number] = [
    innerDateRange.from.valueOf(),
    innerDateRange.upto.valueOf(),
  ];

   const fmt = (date: number) =&amp;gt; {
    const d = dayjs(date);
    const { from, upto } = outerDateRange;
    const range = dayjs(upto).diff(dayjs(from)); // Calculate time difference in milliseconds

    // Pick an appropriate level of granularity for the date range we&apos;re viewing
    if (range &amp;lt; 1000 * 60 * 60 * 24) return d.format(&quot;hh:mm A&quot;); // range is less than a day, show hours and minutes

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 7) return d.format(&quot;M/D, HH:mm&quot;); // range is less than a week, show day of the week

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 30) return d.format(&quot;M/D&quot;); // range is less than a month, show month / day

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 365) return d.format(&quot;MMM D&quot;); // range is less than a year, show month and day

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 365 * 10) return d.format(&quot;MMM YYYY&quot;); // range is more than a year, show year and month

    return d.format(&quot;YYYY&quot;); // range is more than 10 years, show year
  };

  const marks: Record&amp;lt;number, { label: string; style?: React.CSSProperties }&amp;gt; =
    {
      [min]: { label: fmt(min) },
      [max]: { label: fmt(max) },
    };

  // add ticks to marks
  for (let i = min + tickInterval; i &amp;lt;= max; i += tickInterval) {
    marks[i] = {
      label: fmt(i),
    };
  }

   return (
    &amp;lt;div&amp;gt;
      &amp;lt;Row&amp;gt;
        &amp;lt;Col span={24}&amp;gt;
          &amp;lt;Slider
            range={{ draggableTrack: true }}
            min={min}
            max={max}
            marks={marks}
            value={values}
            onChange={(value: number[]) =&amp;gt; {
              onChange({
                from: dayjs(value[0]),
                upto: dayjs(value[1]),
              });
            }}
          /&amp;gt;
        &amp;lt;/Col&amp;gt;
      &amp;lt;/Row&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default TimeSlider;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First a couple of new variables are introduced at the top of the component: &lt;code&gt;tickCount&lt;/code&gt; and &lt;code&gt;tickInterval&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tickCount&lt;/code&gt; is the number of ticks that should be displayed on the slider.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tickInterval&lt;/code&gt; is a value calculated by determining how far away from each other the &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; dates are in time and then dividing that difference by the &lt;code&gt;tickCount&lt;/code&gt; number to figure out how to evenly space the ticks along the slider, regardless of what the actual date values are.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, I created a function called &lt;code&gt;fmt()&lt;/code&gt; which handles the heavy lifting of formatting the dates associated with the tick marks appropriately based on how far apart in time the dates actually are.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   const fmt = (date: number) =&amp;gt; {
    const d = dayjs(date);
    const { from, upto } = outerDateRange;
    const range = dayjs(upto).diff(dayjs(from)); // Calculate time difference in milliseconds

    // Pick an appropriate level of granularity for the date range we&apos;re viewing
    if (range &amp;lt; 1000 * 60 * 60 * 24) return d.format(&quot;hh:mm A&quot;); // range is less than a day, show hours and minutes

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 7) return d.format(&quot;M/D, HH:mm&quot;); // range is less than a week, show day of the week

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 30) return d.format(&quot;M/D&quot;); // range is less than a month, show month / day

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 365) return d.format(&quot;MMM D&quot;); // range is less than a year, show month and day

    if (range &amp;lt; 1000 * 60 * 60 * 24 * 365 * 10) return d.format(&quot;MMM YYYY&quot;); // range is more than a year, show year and month

    return d.format(&quot;YYYY&quot;); // range is more than 10 years, show year
  };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;fmt()&lt;/code&gt; function takes in a date (which will eventually be a tick mark), translates it to a Day.js date (&lt;code&gt;d&lt;/code&gt;) that can be easily formatted as needed, figures out the range between between the &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; dates passed into the component from its parent, and then formats the &lt;code&gt;d&lt;/code&gt; date according to how wide the total timeline &lt;code&gt;range&lt;/code&gt; is.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;range&lt;/code&gt; is less than a day, the tick marks will be styled to show hours and minutes, if the &lt;code&gt;range&lt;/code&gt; is less than a week, it will show day of the week plus hours and minutes, and so on as the &lt;code&gt;range&lt;/code&gt; increases. It takes a little bit of effort to decide when it makes sense to switch from one tick display format to the next, but it ends up working out pretty well in practice. Feel free to adjust your formatting of different date ranges to suit your needs.&lt;/p&gt;
&lt;p&gt;Next I created the &lt;code&gt;marks&lt;/code&gt; that will get passed to the Ant Design slider component.&lt;/p&gt;
&lt;p&gt;These &lt;code&gt;marks&lt;/code&gt; are created in two parts.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  // marks for each end of the time slider component
  const marks: Record&amp;lt;number, { label: string; style?: React.CSSProperties }&amp;gt; =
    {
      [min]: { label: fmt(min) },
      [max]: { label: fmt(max) },
    };

  // add ticks to marks
  for (let i = min + tickInterval; i &amp;lt;= max; i += tickInterval) {
    marks[i] = {
      label: fmt(i),
    };
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first half of the code, where &lt;code&gt;const marks&lt;/code&gt; is declared, is where the marks for each end of the slider are created. Each end&apos;s date is passed to the &lt;code&gt;fmt()&lt;/code&gt; function to have it correctly rendered based on the length of the time span.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  [min]: { label: fmt(min) },
  [max]: { label: fmt(max) },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, each tick between the two ends is run through the formatting function as well via this &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (let i = min + tickInterval; i &amp;lt;= max; i += tickInterval) {
  marks[i] = {
    label: fmt(i),
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, the resulting &lt;code&gt;marks&lt;/code&gt; array is passed to the &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component, along with all the other values covered earlier.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Slider
range={{ draggableTrack: true }}
min={min}
max={max}
marks={marks}
value={values}
onChange={(value: number[]) =&amp;gt; {
    onChange({
    from: dayjs(value[0]),
    upto: dayjs(value[1]),
    });
}}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/custom-antd-time-slider/slider-ticks-2.png&quot; alt=&quot;Ant Design custom date range slider with formatted tick marks&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Format the tooltip&lt;/h3&gt;
&lt;p&gt;After marks for the timeline, it&apos;s time to format the tooltip when a user hovers over either end of the range slider. This is actually one of the easier bits of code within this component as well.&lt;/p&gt;
&lt;p&gt;Inside of the component under where all the variables are declared at the top add the following function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { SliderRangeProps } from &quot;antd/lib/slider&quot;;

const TimeSlider = ({
  outerDateRange,
  innerDateRange,
  onChange,
}: TimeSliderProps) =&amp;gt; {
// variables declared up here

 const formatter: NonNullable&amp;lt;SliderRangeProps[&quot;tooltip&quot;]&amp;gt;[&quot;formatter&quot;] = (
    value: string | number | undefined
  ) =&amp;gt; `${value ? dayjs(value).format(&quot;MM/DD/YYYY HH:mm A&quot;) : &quot;&quot;}`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;code&gt;formatter()&lt;/code&gt; function takes in the current value of the end of the range slider a user is hovering over, and reformats it to a nicely readable date.&lt;/p&gt;
&lt;p&gt;Then call this &lt;code&gt;formatter()&lt;/code&gt; function within the &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component at the bottom of the component file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Slider
range={{ draggableTrack: true }}
min={min}
max={max}
marks={marks}
value={values}
onChange={(value: number[]) =&amp;gt; {
    onChange({
    from: dayjs(value[0]),
    upto: dayjs(value[1]),
    });
}}
tooltip={{ formatter }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Voila! Nicely formatted tooltips for the time range slider on hover.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/custom-antd-time-slider/slider-tooltip-3.png&quot; alt=&quot;Ant Design custom date range slider with formatted tooltips on hover&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Style the track and marks to handle current and future dates differently&lt;/h3&gt;
&lt;p&gt;Now for the extra credit additions to this time slider component: styling future dates differently within the same component. Sounds impossible? I thought so too, at first, but now I can assure you it&apos;s not.&lt;/p&gt;
&lt;p&gt;There&apos;s two changes I wanted to implement to help users know when they were looking at dates in the past/present versus dates in the future with the time slider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I wanted to change the color of the track from Ant Design&apos;s light blue default to a different color, and&lt;/li&gt;
&lt;li&gt;I wanted to change change the color of tick marks in the future, as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lucky for me, Ant Design allows for immense customization of its components, even down to things as specific as track and tick mark styling.&lt;/p&gt;
&lt;p&gt;The track styling was more complicated, so let&apos;s tackle that one first.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import dayjs, { Dayjs } from &quot;dayjs&quot;;

const TimeSlider = ({
  outerDateRange,
  innerDateRange,
  onChange,
}: TimeSliderProps) =&amp;gt; {
  // other variables declared at top of component here
  const current = dayjs().valueOf();

  // Calculate track styles based on the current date
  const getTrackStyle = () =&amp;gt; {
    if (values[1] &amp;lt;= current) {
      // All within past/present
      return {
        backgroundColor: &quot;#91caff&quot;,
      };
    } else if (values[0] &amp;gt;= current) {
      // All in future
      return {
        backgroundColor: &quot;rgb(165, 222, 129)&quot;,
      };
    } else {
      // Split between past/present and future
      const pastWidthPercentage =
        ((current - values[0]) / (values[1] - values[0])) * 100;
      return {
        background: `linear-gradient(
            to right,
            #91caff 0%,
            #91caff ${pastWidthPercentage}%,
            rgb(165, 222, 129) ${pastWidthPercentage}%,
            rgb(165, 222, 129) 100%
          )`,
      };
    }
  };


return (
    &amp;lt;div&amp;gt;
      &amp;lt;Row&amp;gt;
        &amp;lt;Col span={24}&amp;gt;
          &amp;lt;Slider
            range={{ draggableTrack: true }}
            min={min}
            max={max}
            marks={marks}
            value={values}
            styles={{
              track: getTrackStyle(),
            }}
            onChange={(value: number[]) =&amp;gt; {
              onChange({
                from: dayjs(value[0]),
                upto: dayjs(value[1]),
              });
            }}
            tooltip={{ formatter }}
          /&amp;gt;
        &amp;lt;/Col&amp;gt;
      &amp;lt;/Row&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default TimeSlider;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to get the track to change color midway through (for when it straddled date ranges both in the past and the future), I needed to declare a new variable called &lt;code&gt;current&lt;/code&gt; to keep track of what the actual current date is.&lt;/p&gt;
&lt;p&gt;At the top of the component where the other variables are declared, &lt;code&gt;current&lt;/code&gt; is added to the mix, and it&apos;s simply calling the Day.js library&apos;s &lt;code&gt;valueOf()&lt;/code&gt; function) to get the current date as a Unix timestamp.&lt;/p&gt;
&lt;p&gt;Once the current date is identified, I made a function called &lt;code&gt;getTrackStyle()&lt;/code&gt; that compares the values captured by either end of the draggable date range slider and sets the color of the track accordingly.&lt;/p&gt;
&lt;p&gt;When both slider values are less than or equal to the current time, the entire track is styled light blue, when both slider values are greater than current time (i.e. the future), the entire track is styled light green. When the range spans both past and future dates, the function creates a gradient effect relying on the &lt;code&gt;pastWidthPercentage()&lt;/code&gt; function to determine where to transition the colors and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient&quot;&gt;CSS linear-gradient&lt;/a&gt; to create a split color effect.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;ll be honest with you: ChatGPT helped me with this track styling magic. It&apos;s been extremely helpful for many complex things I&apos;ve needed to do with Ant Design components, and I&apos;d recommend working with it if you get stuck.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;getTrackStyle()&lt;/code&gt; function was passed to the &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component inside its &lt;code&gt;styles&lt;/code&gt; property as &lt;code&gt;styles={{ track: getTrackStyle() }}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, I styled the tick marks based in the future in a different color as well.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  for (let i = min + tickInterval; i &amp;lt;= max; i += tickInterval) {
    const futureDate = i &amp;gt; current;
    marks[i] = {
      label: fmt(i),
      style: futureDate
        ? {
            color: &quot;rgb(73, 163, 15)&quot;,
          }
        : {},
    };
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To accomplish this, I modified the &lt;code&gt;for&lt;/code&gt; loop that went through all the predetermined ticks and compared each one to the &lt;code&gt;current&lt;/code&gt; variable declared above. If any of the marks were in the future, those marks got a little extra styling applied to them in the form of a green font color. If the marks were not in the future, they retained their original font color.&lt;/p&gt;
&lt;p&gt;Bonus section: I also wanted a &quot;Now&quot; tick mark to clearly delineate where the time slider track went from blue dates in the past/present to green dates in the future.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const marks: Record&amp;lt;number, { label: string; style?: React.CSSProperties }&amp;gt; =
    {
      [min]: { label: fmt(min) },
      [current]: {
        label: &quot;Now&quot;,
        style: {
          color: &quot;rgb(89, 147, 251)&quot;,
          transform: &quot;translate(-50%, -36px)&quot;,
          fontWeight: &quot;bold&quot;,
        },
      },
      [max]: { label: fmt(max) },
    };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To add an extra tick mark entitled &quot;Now&quot; along my time slider track, I modified the &lt;code&gt;marks&lt;/code&gt; variable, adding in the &lt;code&gt;current&lt;/code&gt; variable as one more pre-defined tick mark, and giving it a label of &quot;Now&quot; and a little styling to stand apart from the rest of the tick marks along the track.&lt;/p&gt;
&lt;p&gt;The &quot;Now&quot; tick mark only shows up when the dates passed to the time slider actually cross the current date, but I think it aids in understanding of what&apos;s going on onscreen.&lt;/p&gt;
&lt;p&gt;With all of that done, the time slider component itself is complete, and it&apos;s time to add it to a parent component that will pass it the dates and functions it requires.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/custom-antd-time-slider/slider-future-date-styling-4.png&quot; alt=&quot;Ant Design custom date range slider with differently styled future dates&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Import the TimeSlider component into the parent page&lt;/h2&gt;
&lt;p&gt;Ok, now it&apos;s time to give the custom &lt;code&gt;&amp;lt;TimeSlider/&amp;gt;&lt;/code&gt; component the props it needs.&lt;/p&gt;
&lt;p&gt;In my case, I had other components that also needed to be aware of any changes to the date range for display purposes (I had chart and map child components that needed to be updated as well when selected dates changed), so I had a page within my Next.js app holding the date state variables and &lt;code&gt;onChange()&lt;/code&gt; function that were passed to the &lt;code&gt;&amp;lt;TimeSlider/&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;Inside of the &lt;code&gt;index.tsx&lt;/code&gt; file within the &lt;code&gt;pages/&lt;/code&gt; folder, I added the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useState } from &quot;react&quot;;
import dayjs, { Dayjs } from &quot;dayjs&quot;;
import TimeSlider from &quot;@/components/TimeSlider&quot;;
import styles from &quot;@/styles/MainContent.module.css&quot;;

type HomeProps = {
  startDate: string;
  endDate: string;
};

export default function Home({ startDate, endDate }: HomeProps) {
  const [initialDate, setInitialDateRange] = useState({
    startDate: dayjs(startDate),
    endDate: dayjs(endDate),
  });

  const [selectedDate, setSelectedDateRange] = useState({
    startDate: dayjs(startDate),
    endDate: dayjs(endDate),
  });

  const handleDateSliderChange = (innerDateSpan: { from: Dayjs; upto: Dayjs }) =&amp;gt; {
    setSelectedDateRange({
      startDate: innerDateSpan.from,
      endDate: innerDateSpan.upto,
    });
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;main className={styles.mainContent}&amp;gt;
        &amp;lt;div className={styles.page}&amp;gt;
          &amp;lt;h2 style={{ textAlign: &quot;center&quot;, margin: &quot;20px auto 0 auto&quot; }}&amp;gt;
            Custom Ant Design Next.js Time Slider
          &amp;lt;/h2&amp;gt;
          &amp;lt;div className={styles.timeSlider}&amp;gt;
            &amp;lt;TimeSlider
              outerDateRange={{
                from: initialDate.startDate,
                upto: initialDate.endDate,
              }}
              innerDateRange={{
                from: selectedDate.startDate,
                upto: selectedDate.endDate,
              }}
              onChange={handleDateSliderChange}
            /&amp;gt;
          &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

export async function getStaticProps() {
  const startDate = dayjs(&quot;2024-12-01&quot;).utc().format(&quot;YYYY-MM-DDTHH:mm:ss[Z]&quot;);
  const endDate = dayjs(&quot;2025-02-28&quot;).utc().format(&quot;YYYY-MM-DDTHH:mm:ss[Z]&quot;);

  return {
    props: {
      startDate,
      endDate,
    },
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;index.tsx&lt;/code&gt; page, I created three variables related to the &lt;code&gt;&amp;lt;TimeSlider/&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;initialDate&lt;/code&gt; and &lt;code&gt;selectedDate&lt;/code&gt; React states, which are both objects containing a &lt;code&gt;startDate&lt;/code&gt; and &lt;code&gt;endDate&lt;/code&gt; property.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;handleDateSliderChange()&lt;/code&gt; function, which accepts new &lt;code&gt;startDate&lt;/code&gt; and &lt;code&gt;endDate&lt;/code&gt; values, and updates the &lt;code&gt;selectedDate&lt;/code&gt; state accordingly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For convenience, I chose to set my start and end date values inside the Next.js &lt;code&gt;getStaticProps()&lt;/code&gt; function call which runs before the page renders in the browser, but it&apos;s not required, and I set both date state objects equal to the defined dates.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;initialDate&lt;/code&gt; values (which end up determining the min and max ends of the time slider won&apos;t change again until they are modified in &lt;code&gt;getStaticProps()&lt;/code&gt; and the page is refreshed), but the &lt;code&gt;selectedDate&lt;/code&gt; values are free to change within those bounds thanks to the &lt;code&gt;handleDateSliderChange()&lt;/code&gt; function which will update the state of the &lt;code&gt;selectedDate&lt;/code&gt; values whenever the user interacts with the &lt;code&gt;&amp;lt;TimeSlider/&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;TimeSlider/&amp;gt;&lt;/code&gt; component was imported into the &lt;code&gt;index.tsx&lt;/code&gt; file and the &lt;code&gt;initialDate&lt;/code&gt; object was passed as its &lt;code&gt;outerDateRange&lt;/code&gt; prop, the &lt;code&gt;selectedDate&lt;/code&gt; object was passed as its &lt;code&gt;innerDateRange&lt;/code&gt; prop, and the &lt;code&gt;handleDateSliderChange()&lt;/code&gt; function was passed as its &lt;code&gt;onChange()&lt;/code&gt; prop.&lt;/p&gt;
&lt;p&gt;At this point, the component should have everything it needs to work.&lt;/p&gt;
&lt;h3&gt;Test out the Time Slider component&lt;/h3&gt;
&lt;p&gt;If you&apos;d like to see a working demo of this &lt;code&gt;&amp;lt;TimeSlider/&amp;gt;&lt;/code&gt; component in action, I&apos;ve got a CodeSandbox link for you to use.&lt;/p&gt;
&lt;p&gt;&amp;lt;CodeSandbox url=&quot;https://codesandbox.io/p/devbox/custom-time-slider-nextjs-ant-design-kcxm75&quot; file=&quot;/src/pages/index.tsx&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;Open a terminal and type &lt;code&gt;npm run dev&lt;/code&gt; to get it started.&lt;/p&gt;
&lt;p&gt;In addition to the time slider component, I also included a few nice extras: some Ant Design date picker components and buttons with values like &quot;Last month&quot;, &quot;Last week&quot;, and &quot;Last day&quot; to show other ways of manipulating the &lt;code&gt;selectedDate&lt;/code&gt; state controlled by the parent component.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to see how the time slider adjusts to larger or smaller date ranges or play around with past and future dates, just adjust the dates inside the &lt;code&gt;getStaticProps()&lt;/code&gt; function in the &lt;code&gt;index.tsx&lt;/code&gt; file and refresh the browser.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As I was building a React-based proof of concept web app that needed a time slider that users could drag and adjust to zoom in or out on particular pieces of data over time, I couldn&apos;t find a ready-made solution for such a need. So I built one myself.&lt;/p&gt;
&lt;p&gt;Using the Ant Design component library&apos;s highly customizable &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component as the base and manipulating dates with the help of the Day.js library, I was able to build a flexible, full-featured, and decent looking time slider without a whole lot of extra code on my end.&lt;/p&gt;
&lt;p&gt;Then I took it a few steps further making the slider handle future dates and style them differently and even display a little &quot;Now&quot; tick mark when the slider crossed over dates in the past to dates in the future dates. It&apos;s a pretty specific use case, I know, but I think there&apos;s more possible applications for interesting sliders like this once you start to think beyond the typical date time options.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope if you need a way to control time series data views within an app and don&apos;t want to rely on just date pickers or inputs, you&apos;ll consider giving this solution a try. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ant.design/components/slider&quot;&gt;Ant Design &lt;code&gt;&amp;lt;Slider/&amp;gt;&lt;/code&gt; component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://day.js.org/&quot;&gt;Day.js date time formatting library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codesandbox.io/p/devbox/custom-time-slider-nextjs-ant-design-kcxm75&quot;&gt;CodeSandbox demo of working time slider component&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category><category>typescript</category><category>nextjs</category><category>ant design</category></item><item><title>Automatically Publish a Repo as a PyPI Library with GitHub Actions</title><link>https://www.paigeniedringhaus.com/blog/automatically-publish-a-repo-as-a-pypi-library-with-github-actions/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/automatically-publish-a-repo-as-a-pypi-library-with-github-actions/</guid><description>Just a config file, a few Python scripts, and a GitHub Actions workflow make publishing to PyPI effortless.</description><pubDate>Mon, 21 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-pypi/workflow-hero.jpg&quot; alt=&quot;Person diagramming out a mobile app workflow&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Last year I had the opportunity to turn my company&apos;s API into a JavaScript SDK by relying on the project&apos;s &lt;code&gt;openapi.yaml&lt;/code&gt; file and the &lt;a href=&quot;https://openapi-generator.tech/docs/installation&quot;&gt;&lt;strong&gt;OpenAPI Generator CLI&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Notehub JS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For the full details of how I did created Notehub JS, I encourage you to read the original blog post I published about it &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I did this as much for myself as for other developers, because I and a group of my coworkers were building a lot of JavaScript-based web apps to display and interact with the IoT data our company &lt;a href=&quot;https://blues.com/&quot;&gt;Blues&lt;/a&gt; specializes in transporting from a device in the real world to the cloud via cellular. To make it easier to update the JavaScript library as the API it&apos;s based on continues to grow and evolve, I set up a bunch of GitHub Actions workflows to do most of the tedious, repetitive tasks for me, and I learned a bunch of useful new things along the way.&lt;/p&gt;
&lt;p&gt;This year, one of my other coworkers who works frequently in Python, asked if I could create a Python SDK for the API, and I agreed, feeling pretty confident about most of the steps involved. One new thing I did have to learn was how to build and publish a Python package to the Python Package Index, PyPI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this blog, I&apos;ll show you how to set up a GitHub Actions workflow to automatically publish a new version of a GitHub project to PyPI when a new release is made - no muss, no fuss, very little manual input required.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Notehub Py&lt;/h2&gt;
&lt;p&gt;As with the original Notehub JS project, the &lt;a href=&quot;https://github.com/blues/notehub-py&quot;&gt;&lt;strong&gt;Notehub Py&lt;/strong&gt;&lt;/a&gt; project&apos;s structure is a bit different from your typical repo because it is automatically generated from the &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/api-introduction/&quot;&gt;Notehub API&apos;s&lt;/a&gt; &lt;code&gt;openapi.yaml&lt;/code&gt; file. The &lt;code&gt;openapi.yaml&lt;/code&gt; file follows the &lt;a href=&quot;https://swagger.io/specification/&quot;&gt;OpenAPI specification&lt;/a&gt; standards, and can be used with the &lt;a href=&quot;https://openapi-generator.tech/docs/installation&quot;&gt;&lt;strong&gt;OpenAPI Generator CLI&lt;/strong&gt;&lt;/a&gt; to build a Python-based SDK to interact with the Notehub API in just a few commands from a terminal.&lt;/p&gt;
&lt;p&gt;Here&apos;s a simplified view of the &lt;a href=&quot;https://github.com/blues/notehub-py&quot;&gt;Notehub Py repo&lt;/a&gt;&apos;s folder structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── .github/
│   └── workflows/
│       └── GH Action files
├── lib_template/
│   └── python library template files
├── src/
│   ├── notehub_py/
│   │   └── Python-based API and model files
│   ├── docs/
│   │   └── MD documentation
│   ├── test/
│   │   └── unit tests
│   ├── dist/
│   │   └── bundled .tar and .whl binaries for PyPi
│   ├── pyproject.toml
│   ├── requirements.txt
│   └── setup.py
├── openapi.yaml
├── config.json
├── README.md
└── scripts.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;openapi.yaml&lt;/code&gt; file lives at the root level of the project along with its &lt;code&gt;config.json&lt;/code&gt; file, a &lt;code&gt;scripts.py&lt;/code&gt; file, and a few other other bits and pieces (license, contribution guidelines, code of conduct, etc.), but the real meat of the library lives inside of the &lt;code&gt;src/&lt;/code&gt; subfolder.&lt;/p&gt;
&lt;p&gt;What&apos;s unique about this subfolder is that it is regenerated each time the &lt;code&gt;openapi.yaml&lt;/code&gt; file is updated, and it has all the API endpoints, models, docs, and the &lt;code&gt;dist/&lt;/code&gt; folder for the &lt;code&gt;notehub-py&lt;/code&gt; SDK that actually gets published on PyPI. Publishing just a subfolder of a project inside a GitHub repo is a little unusual, but not to worry, it can be done in an automated fashion.&lt;/p&gt;
&lt;h3&gt;Create a &lt;code&gt;scripts.py&lt;/code&gt; and &lt;code&gt;config.json&lt;/code&gt; file to automate generating the library and packaging it for distro to PyPI&lt;/h3&gt;
&lt;p&gt;To automate the build and publish steps to deploy Notehub Py to the PyPI registry, we need a couple of things: a &lt;code&gt;config.json&lt;/code&gt; file and a &lt;code&gt;scripts.py&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;config.json&lt;/code&gt; file is a configuration file of additional properties used by the OpenAPI Generator and its Python library template to define certain variables like package name, package version, GitHub repo URL, etc. Here is what the Notehub Py&apos;s &lt;code&gt;config.json&lt;/code&gt; file looks like.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-py/blob/main/config.json&quot;&gt;&lt;strong&gt;&lt;code&gt;config.json&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;packageName&quot;: &quot;notehub_py&quot;,
  &quot;packageUrl&quot;: &quot;https://github.com/blues/notehub-py&quot;,
  &quot;projectName&quot;: &quot;notehub-py&quot;,
  &quot;packageVersion&quot;: &quot;1.0.2&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every time a new version of the Notehub Py library needs to be published to PyPI, the &lt;code&gt;packageVersion&lt;/code&gt; for the project will be updated in this file, then the commands to regenerate the library and its distribution packages (which I&apos;ll cover next) gets run.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;scripts.py&lt;/code&gt; file is a set of reusable commands to automate the steps of updating this repo based on the latest version of the &lt;code&gt;openapi.yaml&lt;/code&gt;, and packaging it up for publishing to PyPI.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-py/blob/main/scripts.py&quot;&gt;&lt;strong&gt;&lt;code&gt;scripts.py&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import sys
import subprocess
import shutil
import os

def generate_package():
    try:
        subprocess.run([
            &quot;openapi-generator-cli&quot;,
            &quot;generate&quot;,
            &quot;-g&quot;,
            &quot;python&quot;,
            &quot;--library&quot;,
            &quot;urllib3&quot;,
            &quot;-t&quot;,
            &quot;lib_template&quot;,
            &quot;-o&quot;,
            &quot;src&quot;,
            &quot;-i&quot;,
            &quot;openapi.yaml&quot;,
            &quot;-c&quot;,
            &quot;config.json&quot;
        ])
    except Exception as e:
        print(&quot;Exception when generating package: %s\n&quot; % e)


def build_distro_package():
    try:
        os.chdir(&quot;src/&quot;)
        # Check if the &apos;dist/&apos; folder exists
        if os.path.exists(&quot;dist&quot;):
            # If it exists, delete it and its contents
            shutil.rmtree(&quot;dist&quot;)

        # Upgrade the &apos;build&apos; module
        subprocess.run([
            &quot;python3&quot;,
            &quot;-m&quot;,
            &quot;pip&quot;,
            &quot;install&quot;,
            &quot;--upgrade&quot;,
            &quot;build&quot;
        ])

        # Generate a new &apos;dist/&apos; folder  
        subprocess.run([
            &quot;python3&quot;,
            &quot;-m&quot;,
            &quot;build&quot;
        ])  
    except Exception as e:
        print(&quot;Exception when building distro package: %s\n&quot; % e)       


if __name__ == &quot;__main__&quot;:
    if len(sys.argv) != 2:
        print(&quot;Usage: python3 scripts.py [generate_package | build_distro_package]&quot;)
        sys.exit(1)
    
    script_to_run = sys.argv[1]
    if script_to_run == &quot;generate_package&quot;:
        generate_package()
    elif script_to_run == &quot;build_distro_package&quot;:
        build_distro_package()
    else:
        print(&quot;Invalid script name. Use one of: generate_package, build_distro_package&quot;)
        sys.exit(1) 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first function, &lt;code&gt;generate_package()&lt;/code&gt;, uses the &lt;code&gt;subprocess&lt;/code&gt; module to run the &lt;code&gt;openapi-generator-cli&lt;/code&gt; tool to generate a new version of the Notehub Py library. Let&apos;s break down each of the arguments in the command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;generate&quot;&lt;/code&gt;: Specifies the action to generate code.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;-g&quot;, &quot;python&quot;&lt;/code&gt;: Indicates that the target language for the generated code is Python.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;--library&quot;, &quot;urllib3&quot;&lt;/code&gt;: Specifies that the generated code should use the &lt;code&gt;urllib3&lt;/code&gt; library for HTTP requests.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;-t&quot;, &quot;lib_template&quot;&lt;/code&gt;: Points to a template directory named &lt;code&gt;lib_template&lt;/code&gt; that contains custom templates for the code generation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;-o&quot;, &quot;src&quot;&lt;/code&gt;: Sets the output directory to &lt;code&gt;src&lt;/code&gt;, where the generated code will be placed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;-i&quot;, &quot;openapi.yaml&quot;&lt;/code&gt;: Specifies the input OpenAPI specification file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;-c&quot;, &quot;config.json&quot;&lt;/code&gt;: Uses a configuration file named &lt;code&gt;config.json&lt;/code&gt; to customize the generation process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second function, &lt;code&gt;build_distro_package()&lt;/code&gt;, builds the distribution package for the the Notehub Py project that will be deployed to PyPI.&lt;/p&gt;
&lt;p&gt;First, the function checks if a &lt;code&gt;dist&lt;/code&gt; folder exists inside the &lt;code&gt;src&lt;/code&gt; folder where all the Notehub Py API code lives, and deletes the older version of the folder if it does exist to ensure any previous build artifacts are removed before adding a new distro package.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;os.chdir(&quot;src/&quot;)
# Check if the &apos;dist/&apos; folder exists
if os.path.exists(&quot;dist&quot;):
    # If it exists, delete it and its contents
    shutil.rmtree(&quot;dist&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, the function upgrades the &lt;code&gt;build&lt;/code&gt; module to ensure the latest version is installed. This module is essential for generating the distribution packages.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;subprocess.run([
    &quot;python3&quot;,
    &quot;-m&quot;,
    &quot;pip&quot;,
    &quot;install&quot;,
    &quot;--upgrade&quot;,
    &quot;build&quot;
])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, the function generates a new &lt;code&gt;dist&lt;/code&gt; directory by invoking the &lt;code&gt;build&lt;/code&gt; module to create the distribution package, which includes both source distributions and wheel distributions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;subprocess.run([
    &quot;python3&quot;,
    &quot;-m&quot;,
    &quot;build&quot;
])  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both of these functions can be invoked from the command line by running &lt;code&gt;python scripts.py generate_package&lt;/code&gt; or &lt;code&gt;python scripts.py build_distro_package&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Set up a PyPI account and library to publish to&lt;/h3&gt;
&lt;p&gt;Now that the Notehub Py config file and scripts to automate the generation and building of the SDK are done, it&apos;s time to prepare PyPI to receive the library.&lt;/p&gt;
&lt;p&gt;Follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://pypi.org/account/register/&quot;&gt;Create a PyPI user account&lt;/a&gt; if you haven’t done so already.&lt;/li&gt;
&lt;li&gt;After logging into PyPI, go to the “Account Settings” page and select the “Publishing” tab.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-pypi/pypi-acct-settings.png&quot; alt=&quot;Navigating to the publishing tab in PyPI site&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Get to this screen by clicking the “Account Settings” tab in the user’s dropdown menu, then select “Publishing” under “Your account”.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Scroll down to the “Add a new pending publisher” section of the page, and input the details of your project you want to publish to PyPI: publisher platform (GitHub), project name to display on PyPI, project owner, repo name, publishing workflow name (something like &lt;code&gt;publish-pypi.yaml&lt;/code&gt;), and click the &quot;Add&quot; button when you&apos;re done.
&lt;ol&gt;
&lt;li&gt;Using &lt;a href=&quot;https://docs.pypi.org/trusted-publishers/&quot;&gt;PyPI’s trusted publishing option&lt;/a&gt; utilizes OpenID Connect (OIDC) technology to provide credential-free publishing authority to trusted third party services like GitHub Actions. This allows us to automate the release process without needing to use API tokens or passwords.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-pypi/pypi-trusted-publisher.png&quot; alt=&quot;Setting up trusted publishing to PyPI project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;Now, we&apos;re ready for the final step in the process: a GitHub Actions workflow to automate publishing the newly generated distribution packages to PyPI.&lt;/p&gt;
&lt;h3&gt;Write a GitHub Actions workflow to publish to PyPI&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Need a refresher on GitHub Actions?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want a quick primer on what GitHub Actions are, I recommend you check out a previous article I wrote about them &lt;a href=&quot;./use-secret-environment-variables-in-git-hub-actions#what-is-github-actions&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For me, it made the most sense to trigger a GitHub Actions workflow by creating a new &lt;a href=&quot;https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases&quot;&gt;&lt;strong&gt;release&lt;/strong&gt;&lt;/a&gt; in GitHub to publish the Notehub Py &lt;code&gt;src/&lt;/code&gt; subfolder to PyPI.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GitHub specifically defines a &lt;strong&gt;release&lt;/strong&gt; as a deployable software iteration that you can package and make available for a wider audience to download and use, which is exactly what I want.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once I&apos;d chosen this as the trigger for my workflow, it was a pretty straightforward set of steps to publish to PyPI.&lt;/p&gt;
&lt;p&gt;Here&apos;s what the finished &lt;code&gt;publish-pypi.yml&lt;/code&gt; file looks like inside of the &lt;code&gt;./github/workflows/&lt;/code&gt; folder - I&apos;ll break it all down below.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-py/tree/main/.github/workflows&quot;&gt;&lt;strong&gt;&lt;code&gt;publish-pypi.yml&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Upload Python Package

on:
  release:
    types: [created]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: 
      name: pypi
      url: https://pypi.org/p/notehub-py
    permissions:
      id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
    defaults:
      run:
        working-directory: ./src
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: &quot;3.x&quot;

      - name: Install dependencies
        run: |
          python3 -m pip install --upgrade pip
          pip install build

      - name: Build package
        run: |
          python3 -m pip install --upgrade build
          python3 -m build

      - name: Publish package to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          packages-dir: ./src/dist/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each GH Actions workflow file needs a &lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt;, so I chose: &lt;code&gt;Upload Python Package&lt;/code&gt;. It tells users exactly what this script&apos;s purpose is.&lt;/p&gt;
&lt;p&gt;As I said earlier, this workflow is triggered whenever a new release is created in GitHub, which is where the following lines take effect.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;on:
  release: 
    types: [created]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on&quot;&gt;&lt;strong&gt;&lt;code&gt;on&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is how a workflow is triggered.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release&quot;&gt;&lt;strong&gt;&lt;code&gt;release&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is the event that triggers the workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;types: [created]&lt;/code&gt;&lt;/strong&gt; is the activity type for a &lt;code&gt;release&lt;/code&gt; event that triggers the workflow. This gives us more fine-grained control of when the workflow should run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then the &lt;strong&gt;&lt;code&gt;jobs&lt;/code&gt;&lt;/strong&gt; section runs inside of the workflow. This particular script only has one job, &lt;code&gt;deploy&lt;/code&gt;, but if there&apos;s multiple jobs, they&apos;ll run sequentially unless otherwise specified.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;deploy&lt;/code&gt; job defines that it runs on the latest version of Ubuntu in &lt;strong&gt;&lt;code&gt;runs-on&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The job is configured to operate within an environment named &lt;code&gt;pypi&lt;/code&gt;, with a URL that points to the PyPI project page for &lt;code&gt;notehub-py&lt;/code&gt;, and the &lt;code&gt;permissions&lt;/code&gt; section grants the job the necessary &lt;code&gt;id-token: write&lt;/code&gt; permission, which is required for trusted publishing to PyPI. All of this will correspond to the details filled out in PyPI in the previous section setting up the &lt;a href=&quot;https://docs.pypi.org/trusted-publishers/&quot;&gt;trusted publishing option via OpenID Connect&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; environment: 
      name: pypi
      url: https://pypi.org/p/notehub-py
    permissions:
      id-token: write # this permission is mandatory for trusted publishing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#defaultsrun&quot;&gt;&lt;strong&gt;&lt;code&gt;defaults.run&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; section sets the working directory to &lt;code&gt;./src&lt;/code&gt; for all &lt;code&gt;run&lt;/code&gt; steps, ensuring the commands are executed within the source subdirectory of the project.&lt;/p&gt;
&lt;p&gt;Finally, we get to the &lt;strong&gt;&lt;code&gt;steps&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The steps are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check out the code so the workflow can clone the repository&apos;s code into the runner with &lt;a href=&quot;https://github.com/actions/checkout&quot;&gt;&lt;code&gt;actions/checkout@v4&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set up a Python environment with version &lt;code&gt;3.x&lt;/code&gt; using &lt;a href=&quot;https://github.com/actions/setup-python&quot;&gt;&lt;code&gt;actions/setup-python@v5&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Upgrade &lt;code&gt;pip&lt;/code&gt; and install the &lt;code&gt;build&lt;/code&gt; modules necessary for building the distribution package.&lt;/li&gt;
&lt;li&gt;Build the distribution package using &lt;code&gt;python3 -m build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Publish the built packages to PyPI using the &lt;a href=&quot;https://github.com/pypa/gh-action-pypi-publish&quot;&gt;&lt;code&gt;pypa/gh-action-pypi-publish@release/v1&lt;/code&gt;&lt;/a&gt; action. The &lt;code&gt;packages-dir&lt;/code&gt; parameter specifies the directory containing the distribution files (&lt;code&gt;./src/dist/&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And there you have it: each time a new release is created in the Notehub Py repo, this GitHub Actions workflow will run and deploy the updated code to PyPI.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;After publishing my first JavaScript SDK of my company&apos;s API on npm last year, I was asked to build a similar SDK in Python and distribute it to PyPI.&lt;/p&gt;
&lt;p&gt;I was able to repurpose a lot of the same steps and workflows I used for generating the JavaScript library to generate the Python library, but configuring the deployment to PyPI was a bit different as that package platform recommends using trusted publishing to deploy new package versions.&lt;/p&gt;
&lt;p&gt;With just a few Python scripts, a config file, and a little bit of set up on the PyPI site, I was able to deploy the auto-generated subfolder inside of the Notehub Py project to PyPI, helping developers more easily interact with the Notehub API. GitHub Actions allowed me to build the code, package it up for distribution, and publish it to PyPI in no time.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about the useful things I learned while building this project in addition to other topics on JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning how to deploy a subfolder of a project to PyPI through GitHub Actions workflows comes in handy for you in the future. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blues/notehub-py&quot;&gt;Notehub Py&lt;/a&gt; GitHub repo&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pypi.org/project/notehub-py/&quot;&gt;notehub-py&lt;/a&gt; SDK on PyPI&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openapi-generator.tech/docs/installation&quot;&gt;OpenAPI Generator CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>python</category><category>github</category><category>git</category><category>pypi</category><category>devops</category></item><item><title>Animate an Auto-Scrolling Carousel with Only HTML and CSS</title><link>https://www.paigeniedringhaus.com/blog/animate-an-auto-scrolling-carousel-with-only-html-and-css/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/animate-an-auto-scrolling-carousel-with-only-html-and-css/</guid><description>No libraries, no JavaScript, just CSS keyframes and the scroll snap module.</description><pubDate>Fri, 23 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nifty-fifty-connected-electronic-kiosk/sample-web-app-hero.png&quot; alt=&quot;Cellular-connected electronic kiosk demo app showing weather forecast in Barcelona&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;As web developers working with powerful computers we don&apos;t often stop to consider that while things like memory and stable Internet connections aren&apos;t a problem for us, they may be where our apps end up running.&lt;/p&gt;
&lt;p&gt;Case in point: building a web app to run on a Raspberry Pi - which could be quite possible for something like a kiosk in a mall, a doctor&apos;s office or even an amusement park.&lt;/p&gt;
&lt;p&gt;Last year, I was tasked with building a small demo for work to demonstrate how to package up a simple web application and download it to a Raspberry Pi using a cellular-based Blues Notecard.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;re interested in how to do this, you can read the full details &lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/tree/main/web-app&quot;&gt;here&lt;/a&gt;. But that is outside the scope of this post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I decided a good demo would be a weather app where a list of cities would be provided, and the app would fetch the weather forecast for each city and display it in an endlessly looping carousel.&lt;/p&gt;
&lt;p&gt;In order to keep the app size small (and quicker to download via cellular data to a Raspi), I built it with pure HTML, CSS, and a little vanilla-JavaScript.&lt;/p&gt;
&lt;p&gt;For the auto-scrolling feature of each city&apos;s forecast I&apos;d normally look for a carousel library to help me, but since I needed the app to stay lightweight I did some research and found that CSS alone could do what I needed.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nifty-fifty-connected-electronic-kiosk/huzzah-gift.webp&quot; alt=&quot;Two Englishmen saying &apos;Huzzah&apos;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to use CSS &lt;code&gt;keyframes&lt;/code&gt; animations along with scroll snap module and a few well-placed CSS classes to make auto-scrolling, CSS-only carousels possible.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s what the final auto-scrolling carousel animation looks like.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=PqX_NG_QtCU&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;CSS keyframes and scroll snap&lt;/h2&gt;
&lt;p&gt;Before we get to the implementation of this auto-scrolling carousel,let&apos;s talk a bit about the CSS features that make it possible: CSS &lt;code&gt;keyframes&lt;/code&gt; and the CSS scroll snap module.&lt;/p&gt;
&lt;h3&gt;CSS keyframes&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes&quot;&gt;&lt;code&gt;@keyframes&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; rule controls the intermediate steps in a CSS animation sequence by defining styles for keyframes (or waypoints) along an animation sequence. This gives more control over the intermediate steps of the animation sequence than CSS transitions.&lt;/p&gt;
&lt;p&gt;Not only do &lt;code&gt;@keyframes&lt;/code&gt; allow for complex animations without the need for JavaScript, but they also offer a straightforward syntax, and reusability across multiple elements (as you&apos;ll soon see in my own code examples below).&lt;/p&gt;
&lt;h3&gt;CSS scroll snap&lt;/h3&gt;
&lt;p&gt;The CSS &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll_snap&quot;&gt;scroll snap module&lt;/a&gt;&lt;/strong&gt; provides properties that let you control the panning and scrolling behavior by defining snap positions. Content can be snapped into position as the user scrolls overflowing content within a scroll container, providing paging and scroll positioning.&lt;/p&gt;
&lt;p&gt;It has two properties in particular we&apos;ll take advantage of today for the carousel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CSS scroll-snap-type&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The CSS &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type&quot;&gt;&lt;code&gt;scroll-snap-type&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; property sets how strictly snap points are enforced on the scroll container.&lt;/p&gt;
&lt;p&gt;It accepts a variety of different &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type#syntax&quot;&gt;values&lt;/a&gt;, but the most common ones are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mandatory&lt;/code&gt; - The scroll container must snap to the nearest snap point after scrolling.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proximity&lt;/code&gt; - The scroll container will only snap to a point if the scrolling comes to a natural rest near a snap point.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt; - No snapping behavior is enforced.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In practice, you might use &lt;code&gt;mandatory&lt;/code&gt; when you need precise control over the final position of the scroll (like with carousels or paginated content where each item should be fully visible after scrolling), and you might use &lt;code&gt;proximity&lt;/code&gt; when you want to give users more control over the scroll stopping point, which can feel smoother and less jarring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CSS scroll-snap-align&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The other part of this scroll snap equation, &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-align&quot;&gt;&lt;code&gt;scroll-snap-align&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, specifies a box&apos;s snap position within its snap container when using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll_snap&quot;&gt;CSS scroll snap&lt;/a&gt; module.&lt;/p&gt;
&lt;p&gt;A child element of the scroll snap container can have the &lt;code&gt;scroll-snap-align&lt;/code&gt; property set to control how it snaps into the viewport when scrolling stops. Its &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-align#values&quot;&gt;values&lt;/a&gt; include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; - Aligns the start edge of the item with the start edge of the scroll container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt; - Aligns the end edge of the item with the end edge of the scroll container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;center&lt;/code&gt; - Centers the item in the scroll container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt; - No snap alignment will occur.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that bit of background out of the way, let&apos;s get on to the code.&lt;/p&gt;
&lt;h2&gt;Set up the HTML and CSS&lt;/h2&gt;
&lt;p&gt;First, the proper HTML must be set up for the CSS auto-scrolling to work correctly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Wrap the HTML elements to be part of the carousel in a parent div.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To begin, wrap all the slides to be scrolled through inside a parent container. This is where the CSS &lt;code&gt;scroll-snap-type&lt;/code&gt; property will be applied so that the child elements will be able to interpret the &lt;code&gt;scroll-snap-align&lt;/code&gt; property applied to them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; In my full code sample, I defined an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template&quot;&gt;HTML template&lt;/a&gt; to hold all my weather data for each city, and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template#examples&quot;&gt;&lt;code&gt;template.content.cloneNode()&lt;/code&gt; function&lt;/a&gt; to clone the template for each city in my list and add it inside the  &lt;code&gt;weather-forecast-container&lt;/code&gt; element&lt;/p&gt;
&lt;p&gt;That&apos;s outside the scope of what&apos;s needed for this article, but if you&apos;d like to see the full code, it&apos;s available &lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/blob/main/web-app/index.htm&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is my HTML file where the parent container and its children are defined.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/blob/main/web-app/index.htm&quot;&gt;&lt;code&gt;index.htm&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;lt;div class=&quot;weather-forecast-container&quot;&amp;gt;
    &amp;lt;div class=&quot;weather-template&quot;&amp;gt;
      &amp;lt;div class=&quot;current-header-wrapper&quot;&amp;gt;
        &amp;lt;div class=&quot;current-date&quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;h2 class=&quot;location&quot;&amp;gt;Loading current weather...&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;current-conditions&quot;&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;span class=&quot;conditions&quot;&amp;gt;
            &amp;lt;img class=&quot;condition-icon&quot; src=&quot;&quot; /&amp;gt;
            &amp;lt;span class=&quot;condition-text&quot; /&amp;gt;
          &amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&quot;current-temp&quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;div class=&quot;details&quot;&amp;gt;
          &amp;lt;div class=&quot;wind-speed&quot;&amp;gt;&amp;lt;/div&amp;gt;
          &amp;lt;div class=&quot;rainfall&quot;&amp;gt;&amp;lt;/div&amp;gt;
          &amp;lt;div class=&quot;pressure&quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;forecast&quot;&amp;gt;
        &amp;lt;table&amp;gt;
          &amp;lt;tbody class=&quot;future-forecast&quot;&amp;gt;&amp;lt;/tbody&amp;gt;
        &amp;lt;/table&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;weather-carousel-snapper&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see from the HTML above, the &lt;code&gt;weather-forecast-container&lt;/code&gt; class wraps the div with the class of &lt;code&gt;weather-template&lt;/code&gt; which holds all the weather info for a given city, and contains an empty div at the bottom with a class of &lt;code&gt;weather-carousel-snapper&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Position the empty div at the bottom of the &lt;code&gt;weather-template&lt;/code&gt; div to be the carousel&apos;s snapper element.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Make sure that this element is &lt;em&gt;inside&lt;/em&gt; of the &lt;code&gt;weather-template&lt;/code&gt; div and not a sibling to it. It will continue to be empty, but it needs to be present.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;weather-carousel-snapper&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. Add base styling to the parent container and position the weather template and scroll-snap div inside it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is where the CSS scroll snap module comes into play.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/blob/main/web-app/styles.css&quot;&gt;&lt;code&gt;styles.css&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.weather-forecast-container {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  height: clamp(290px, 88vh, 430px);
  max-width: 780px;
  margin: 8px auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overflow-x: scroll;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the &lt;code&gt;weather-forecast-container&lt;/code&gt; class, we&apos;re going to go beyond the basic styling of the container like positioning and defining its &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; (both set to the width of a small screen attached to the Raspi), and add the first CSS scroll snap properties here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type#values&quot;&gt;&lt;strong&gt;&lt;code&gt;scroll-snap-type: x mandatory;&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - this defines a mandatory snapping in the horizontal axis.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior&quot;&gt;&lt;strong&gt;&lt;code&gt;scroll-behavior: smooth;&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - makes the carousel appear to scroll to the next page, instead of just jumping there as it would by default.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-x#scroll&quot;&gt;&lt;strong&gt;&lt;code&gt;overflow-x: scroll;&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - overflow content is clipped if necessary to fit horizontally inside the element&apos;s padding box.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next up, is the styling for the &lt;code&gt;weather-template&lt;/code&gt; div that contains the weather info and the empty &lt;code&gt;weather-carousel-snapper&lt;/code&gt; div.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/blob/main/web-app/styles.css&quot;&gt;&lt;code&gt;styles.css&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.weather-template {
  position: relative;
  flex: 0 0 100%;
  background-size: 780px 100%;
  background-repeat: no-repeat;
  border: 1px solid rgba(0, 0, 0, 0.25);
  border-radius: 4px;
  padding: 0 10px;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;ve included the stying for the &lt;code&gt;weather-template&lt;/code&gt; div as it&apos;s the true parent of the &lt;code&gt;weather-carousel-snapper&lt;/code&gt; element, but this is just standard CSS styling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/blob/main/web-app/styles.css&quot;&gt;&lt;code&gt;styles.css&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.weather-carousel-snapper {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  scroll-snap-align: center;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Last but not least, we add the last bit of scroll snap CSS to the empty div with the class of &lt;code&gt;weather-carousel-snapper&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-align#center&quot;&gt;&lt;strong&gt;&lt;code&gt;scroll-snap-align: center;&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - this will align each item to the center of the container.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Create the animation keyframes to auto-scroll the forecast slides&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After the CSS styling is done, and scroll snap is enabled, it&apos;s time to make the &lt;code&gt;@keyframes&lt;/code&gt; animations that will actually make the different cities appear to slide through the viewport from one city to the next.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/blob/main/web-app/styles.css&quot;&gt;&lt;code&gt;styles.css&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes tonext {
  75% {
    left: 0;
  }
  95% {
    left: 100%;
  }
  98% {
    left: 100%;
  }
  99% {
    left: 0;
  }
}

@keyframes tostart {
  75% {
    left: 0;
  }
  95% {
    left: -300%;
  }
  98% {
    left: -300%;
  }
  99% {
    left: 0;
  }
}

@keyframes snap {
  96% {
    scroll-snap-align: center;
  }
  97% {
    scroll-snap-align: none;
  }
  99% {
    scroll-snap-align: none;
  }
  100% {
    scroll-snap-align: center;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, there are three separate animations defined.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tonext&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;tostart&lt;/code&gt;&lt;/strong&gt; - manage the horizontal position of each city&apos;s weather forecast at different stages of the carousel, creating a sliding effect either to the right or far left, followed by a reset to the starting position (for getting the animation to endlessly loop back to the first city in the list again).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;snap&lt;/code&gt;&lt;/strong&gt; - controls the &lt;code&gt;scroll-snap-align&lt;/code&gt; property, adjusting the snapping behavior at specific points in the animation timeline. This creates the dynamic snapping behavior that centers up the next city forecast in the carousel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By combining these three keyframes, we&apos;ll have the slick-looking animation in the demo video where the carousel appears to smoothly slide from one forecast to the next.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Apply the keyframe animations to the appropriate HTML elements inside the &lt;code&gt;weather-forecast-container&lt;/code&gt; parent div.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now we&apos;re going to apply the &lt;code&gt;@keyframes&lt;/code&gt; animations defined in the previous step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk/blob/main/web-app/styles.css&quot;&gt;&lt;code&gt;styles.css&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media (hover: hover) {
  .weather-carousel-snapper {
    animation-name: tonext, snap;
    animation-timing-function: ease;
    animation-duration: 4s;
    animation-iteration-count: infinite;
  }

  .weather-template:last-child .weather-carousel-snapper {
    animation-name: tostart, snap;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@media (hover: hover)&lt;/code&gt;&lt;/strong&gt; - in an effort to ensure that the carousel animations and scroll snap are not applied to devices where hovering isn&apos;t possible, such as with most smartphones and tablets, I wrapped these animations inside of the &lt;code&gt;hover&lt;/code&gt; media query.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;.weather-carousel-snapper&lt;/code&gt; class is given the &lt;code&gt;tonext&lt;/code&gt; and &lt;code&gt;snap&lt;/code&gt; animations to run simultaneously with &lt;code&gt;animation-name: tonext, snap;&lt;/code&gt;, and it will ease over 4 seconds and loop infinitely.&lt;/p&gt;
&lt;p&gt;A rule targeting the last child of the .&lt;code&gt;weather-template&lt;/code&gt; element with the class of &lt;code&gt;weather-carousel-snapper&lt;/code&gt;, applies a different animation combination (&lt;code&gt;tostart&lt;/code&gt; and &lt;code&gt;snap&lt;/code&gt;), to reset the carousel after the last city&apos;s weather forecast has been displayed onscreen to get the carousel back to it&apos;s starting position (and first city in the list).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. And there you have it: a CSS only, auto-scrolling carousel with just HTML and CSS&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The finished product demoed once more in this video.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=PqX_NG_QtCU&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In certain situations, it&apos;s really crucial that web applications be as small as possible. For instance, when that app may be running on a low power or underpowered system (like a Raspberry Pi).&lt;/p&gt;
&lt;p&gt;When I needed to build a small demo app that would download over cellular to a Raspi, I decided to do it with plain HTML, CSS, and a bit of vanilla-JS to keep the zip file size as small as possible - no JS frameworks like React or Svelte to help me out.&lt;/p&gt;
&lt;p&gt;I wanted to build a weather app that would display the forecast for a list of cities and auto-rotate through the list before returning to the beginning of the list to start over. At first, I thought I might need a carousel library to make this happen, but it turns out CSS scroll snap and keyframe animations can do exactly the same thing, no JS needed. That&apos;s pretty darn sweet.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope if you need a carousel in the future (auto rotating or not) that you&apos;ll try implementing it yourself with CSS - I think you&apos;ll be pleasantly surprised how little code is needed to make it happen. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CSS-Tricks, &lt;a href=&quot;https://css-tricks.com/css-only-carousel/&quot;&gt;CSS-Only Carousel article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN docs, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes&quot;&gt;CSS @keyframes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN docs, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll_snap&quot;&gt;CSS scroll snap module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN docs, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type&quot;&gt;CSS scroll-snap-type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN docs, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-align&quot;&gt;CSS scroll-snap-align&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub repo, &lt;a href=&quot;https://github.com/blues/accelerators-cellular-connected-electronic-kiosk&quot;&gt;Cellular-Connected Electronic Kiosk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>css</category></item><item><title>Lean on CSS Clip Path to Make Cool Shapes in the DOM without Images</title><link>https://www.paigeniedringhaus.com/blog/lean-on-css-clip-path-to-make-cool-shapes-in-the-dom-without-images/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/lean-on-css-clip-path-to-make-cool-shapes-in-the-dom-without-images/</guid><description>Hearts, stars, and horseshoes - or maybe just a jaunty polygon for extra flair.</description><pubDate>Wed, 19 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-clip-path/shapes-hero.png&quot; alt=&quot;Colorful shapes all slotted together&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Up until a few years ago if you wanted background shapes or sections of a website that were anything besides rectangles you most likely needed a designer to provide you with a static PNG or JPEG image that would be added as required, but CSS has come a long way since then, my friends.&lt;/p&gt;
&lt;p&gt;When I was working on a website update that broke up the contents on the page into different colored background sections, alternating between pure white and soft gray colors, the design mock up I had included one section whose bottom edge tilted up and to the right instead of going across the page at a perfect 90 degree angle, as a typical block element does.&lt;/p&gt;
&lt;p&gt;Now I could have asked the designer to make a background image to do this for me, but instead I wanted to see if I could do it on my own with the power of CSS. And lo and behold I could, with CSS &lt;code&gt;clip-path&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interesting shapes and visuals in the DOM are no longer purely the domain of designers, with tools like CSS &lt;code&gt;clip-path&lt;/code&gt;, devs have the power to reshape elements and I&apos;ll show you how.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;CSS clip-path&lt;/h2&gt;
&lt;p&gt;If you&apos;re less familiar with the &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot;&gt;CSS &lt;code&gt;clip-path&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; property, like me, it creates a clipping region that sets which parts of an element should be shown. Parts that are inside the region are shown, while those outside are hidden.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-clip-path/clip-path-demo.png&quot; alt=&quot;CSS clip-path demo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A demo from the MDN clip-path docs. Different clip-path options provide different views of the hot air balloon and text.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;clip-path&lt;/code&gt; property can accept a large variety of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path#syntax&quot;&gt;values&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path#clip-source&quot;&gt;&lt;code&gt;&amp;lt;clip-source&amp;gt;&lt;/code&gt;&lt;/a&gt;, which accepts values like &lt;code&gt;url&lt;/code&gt; for an SVG element with clipping path defined.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path#geometry-box&quot;&gt;&lt;code&gt;&amp;lt;geometry-box&amp;gt;&lt;/code&gt;&lt;/a&gt;, which accepts values like &lt;code&gt;margin-box&lt;/code&gt; and &lt;code&gt;border-box&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape&quot;&gt;&lt;code&gt;&amp;lt;basic-shape&amp;gt;&lt;/code&gt;&lt;/a&gt;, which accepts values like &lt;code&gt;circle()&lt;/code&gt; and &lt;code&gt;rect()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;global-values&lt;/code&gt;, which accepts values like &lt;code&gt;inherit&lt;/code&gt; and &lt;code&gt;revert&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;geometry-box&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;basic-shape&amp;gt;&lt;/code&gt; values can even be combined together in one &lt;code&gt;clip-path&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* this CSS combines two different clip path properties */
clip-path: padding-box circle(50px at 0 100px);
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;This post doesn&apos;t go into great detail about all of the properties &lt;code&gt;clip-path&lt;/code&gt; can accept and how they can be combined to create quite complex shapes. If you want more information and examples of &lt;code&gt;clip-path&lt;/code&gt; in action, I recommend starting with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot;&gt;Mozilla documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One of the &lt;code&gt;&amp;lt;basic-shape&amp;gt;&lt;/code&gt; properties &lt;code&gt;clip-path&lt;/code&gt; accepts is &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape/polygon&quot;&gt;&lt;code&gt;polygon()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, and this ended up being the solution I needed for my tilted background section.&lt;/p&gt;
&lt;h2&gt;The polygon I needed to recreate with CSS&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-clip-path/clip-path-screenshot.png&quot; alt=&quot;Website section with imperfect bottom angle courtesy of CSS clip path&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The gray polygon background I needed to create with CSS.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The image above is a screenshot of the gray background section I needed to recreate with CSS &lt;code&gt;clip-path&lt;/code&gt;&apos;s &lt;code&gt;polygon()&lt;/code&gt; property. And the first thing I needed to do was create some HTML elements to apply the CSS to.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;polygon() clip-path vs rect() clip-path&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You might be wondering why I chose to use the &lt;code&gt;polygon()&lt;/code&gt; property instead of the &lt;code&gt;rect()&lt;/code&gt; property with &lt;code&gt;clip-path&lt;/code&gt;. While the two are similar, &lt;code&gt;polygon()&lt;/code&gt; can create more complex polygonal shapes and offers greater versatility for advanced designs by accepting pairs of coordinates to define each vertex of the polygon, whereas &lt;code&gt;rect()&lt;/code&gt; can only handle rectangular shapes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Set up the HTML and CSS&lt;/h3&gt;
&lt;p&gt;The site I was working on relied on the static site generator &lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt;, a Go-based framework. Hugo uses &lt;a href=&quot;https://gohugo.io/templates/introduction/&quot;&gt;templates&lt;/a&gt; to render the site&apos;s HTML, so the example code below should look relatively familiar to you if you know HTML.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on templates:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;ve ever used JSX components, Node.js with Pug or Handlebars, or Jekyll - Hugo&apos;s templates are similar: HTML elements with Go variables and functions sprinkled in with &lt;code&gt;{{ }}&lt;/code&gt; to render the correct information wherever the templates are injected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&apos;s the code for what I&apos;d nicknamed the &quot;puzzle section&quot; of the page due to the puzzle piece in the foreground of this section. For the purposes and clarity of this article, I&apos;ve replaced the Go variables injected into the template with the generated HTML.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;single.html&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;lt;div class=&quot;about-body&quot;&amp;gt;
    &amp;lt;!-- more HTML elements up here  --&amp;gt;

    &amp;lt;section class=&quot;puzzle-section section&quot;&amp;gt;
      &amp;lt;div class=&quot;container&quot;&amp;gt;
        &amp;lt;div class=&quot;row&quot;&amp;gt;
          &amp;lt;div class=&quot;col-12 col-md-6 col-lg-6&quot;&amp;gt;
              &amp;lt;h4 class=&quot;mb-3&quot;&amp;gt;
                Lorem ipsum dolor
              &amp;lt;/h4&amp;gt;
              &amp;lt;p class=&quot;mb-5&quot;&amp;gt;
                Sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Ipsum dolor sit amet consectetur adipiscing elit pellentesque.
              &amp;lt;/p&amp;gt;
              &amp;lt;h4 class=&quot;mb-3&quot;&amp;gt;
                Duis aute irure dolor in reprehenderit
              &amp;lt;/h4&amp;gt;
              &amp;lt;p class=&quot;mb-5&quot;&amp;gt;
                in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Consectetur adipiscing elit pellentesque habitant morbi tristique senectus et.
              &amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div
            class=&quot;col-sm-8 offset-sm-2 col-md-6 offset-md-0 col-lg-6 offset-lg-0&quot;
          &amp;gt;
            &amp;lt;img
              class=&quot;img-fluid&quot;
              src=&quot;/images/about/puzzle-pieces.png&quot;
              alt=&quot;Puzzle pieces&quot;
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/section&amp;gt;

     &amp;lt;!-- more HTML elements below  --&amp;gt;
  &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This section of code is relatively compact, but it deserves discussion. In addition to the HTML elements, there are quite a few CSS classes which come from the &lt;strong&gt;&lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt;&lt;/strong&gt; library, one of the original open source CSS frameworks for responsive web designs.&lt;/p&gt;
&lt;p&gt;Among the custom classes like &lt;code&gt;about-body&lt;/code&gt;, which I used for adding custom styling, there are classes like &lt;code&gt;container&lt;/code&gt;, &lt;code&gt;row&lt;/code&gt;, &lt;code&gt;col-12&lt;/code&gt; or &lt;code&gt;col-md-6&lt;/code&gt;, &lt;code&gt;mb-5&lt;/code&gt;, and &lt;code&gt;mb-3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All of the latter classes are Bootstrap classes, which serve to make the text and image elements onscreen share the width of the page when the viewport is over a certain width (&lt;code&gt;col-md-6&lt;/code&gt;), or apply a &lt;code&gt;margin-bottom&lt;/code&gt; of a certain amount to the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tags (&lt;code&gt;mb-3&lt;/code&gt; or &lt;code&gt;mb-5&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The Bootstrap classes are beside the point for this post though, the class to focus on is the &lt;strong&gt;&lt;code&gt;puzzle-section&lt;/code&gt;&lt;/strong&gt; which wraps all the text and puzzle piece image.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;puzzle-section&lt;/code&gt; class is where we&apos;re going to add the &lt;code&gt;clip-path&lt;/code&gt; property to display the light grey background behind the text and image with the slightly tilted, up-and-to-the-right design.&lt;/p&gt;
&lt;h3&gt;Add the CSS clip-path to shape puzzle-section&lt;/h3&gt;
&lt;p&gt;As I wasn&apos;t quite sure how to style a normal, rectangular &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; into an uneven shape, I started looking for a solution online and found this helpful, interactive &lt;code&gt;clip-path&lt;/code&gt;-focused site, &lt;a href=&quot;https://bennettfeely.com/clippy/&quot;&gt;CSS clip-path maker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-clip-path/clippy-website.png&quot; alt=&quot;CSS clip-path maker website&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This CSS &lt;code&gt;clip-path&lt;/code&gt; maker website is fantastic because it has a whole slew of preset shapes, adjustable image sizes and backgrounds, and the currently displayed image&apos;s vertices can be dragged into any arrangement you want. The line at the bottom of the screen shows the exact &lt;code&gt;clip-path&lt;/code&gt; CSS values that you can copy/paste into your own project&apos;s CSS.&lt;/p&gt;
&lt;p&gt;I chose the parallelogram preset shape as my starting point, and then dragged the corners to match the angle of the background section I was trying to recreate from scratch. Once I was satisfied it looked accurate, I copied the CSS line at the bottom of the page to my clipboard.&lt;/p&gt;
&lt;p&gt;In my project&apos;s SCSS file, I added the copied &lt;code&gt;clip-path&lt;/code&gt; CSS in addition to the light grey &lt;code&gt;background-color&lt;/code&gt; property and some padding to give the text and puzzle piece images some breathing room on the page.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Even though this file shown in the example code is SCSS instead of pure CSS, for this post it shouldn&apos;t make a difference here. It should be a direct 1:1 comparison.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;about.scss&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.about-body {
  // this white sets the white background color for the whole webpage
  background-color: white; 

  .puzzle-section {
    // clip-path code copied from the clip-path maker website
    clip-path: polygon(0 0, 100% 0%, 100% 75%, 0% 100%);
    background-color: light-grey;
    padding: 2rem 0 10rem 0;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That little bit of CSS for &lt;code&gt;clip-path&lt;/code&gt; was all that was needed to take my perfectly rectangular DOM element and turn it into an imperfect polygon instead. Not too shabby!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;CSS is pushing the boundaries of what web developers can do without resorting to images, videos, and custom designed elements all the time. And the satisfaction of figuring out how to do a cool little bit of design on all on your own feels pretty empowering.&lt;/p&gt;
&lt;p&gt;A recent example of this was using the CSS &lt;code&gt;clip-path&lt;/code&gt; property to create a background box for some text and images that had an uneven bottom edge. With the help of an &lt;a href=&quot;https://bennettfeely.com/clippy/&quot;&gt;interactive website dedicated to decoding clip-paths&lt;/a&gt; of all shapes and sizes, I was able to make quick work of this slightly skewed polygon.&lt;/p&gt;
&lt;p&gt;And let me take a moment to shout out how much I appreciate the folks putting out those little sites or code snippets that solve a very specific problem for another developer - you folks continue to make the Internet a better place.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning to reshape how elements look in the DOM with just the power of CSS helps you as much as it&apos;s helped me.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;MDN docs, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot;&gt;CSS clip-path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bennettfeely.com/clippy/&quot;&gt;CSS clip-path generator website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>css</category></item><item><title>Create a Custom Formatted CSV from Python Data</title><link>https://www.paigeniedringhaus.com/blog/create-a-custom-formatted-csv-from-python-data/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/create-a-custom-formatted-csv-from-python-data/</guid><description>The DictWriter package makes creating a CSV file from a Python list simple.</description><pubDate>Fri, 19 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-csv/csv-data-hero.jpg&quot; alt=&quot;Spreadsheet of numbers&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In 2023, a friend of mine asked me to write a program to collect the data from an NFT collection on the &lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; website. He was interested in the following information: all the NFTs currently for sale in the collection, the current price of BNB (the cryptocurrency the NFTs are listed for sale in), the price of each NFT converted to US dollars based on the current price of BNB, and put all that data into a spreadsheet that&apos;s easy to manipulate, sort, and filter.&lt;/p&gt;
&lt;p&gt;I couldn&apos;t use my go-to JavaScript skills to fetch data via HTTP calls from the NFTrade site because there is no public-facing API, so instead, I taught myself to build a small web scraping script to visit the site and &quot;scrape&quot; that data from it.&lt;/p&gt;
&lt;p&gt;Python seems to be a very popular language for such projects, so I went with it, and as I worked on it, the requirements got a bit more complex, and I learned a lot of useful things about Python as a result, which I&apos;ve shared in a series of blog posts. This post will be the last in my series covering this web scraper.&lt;/p&gt;
&lt;p&gt;In previous articles I:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./scrape-data-from-a-lazy-loading-website-with-selenium-python&quot;&gt;Scraped the NFT data off of NFTrade using the Selenium Python package&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./use-selenium-with-python-to-target-the-x-path-of-a-particular-object&quot;&gt;Filtered each NFT&apos;s raw data into a separate object in a list of NFTs&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./filter-merge-and-update-python-lists-based-on-object-attributes&quot;&gt;Narrowed the list down to NFTs just for sale, fetched the current price of BNB, and added the list price of each NFT in US dollars to each NFT&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And now, with all the data in one place, I needed to make it into a spreadsheet my friend could work with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Python csv.DictWriter module makes turning a list of Python objects into a standard CSV file a straightforward task, which I&apos;ll demonstrate in this article.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I am not normally a Python developer so my code examples may not be the most efficient or elegant Python code ever written, but they get the job done.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Sample Python data&lt;/h2&gt;
&lt;p&gt;I need to set the stage and show you the shape of the my Python data before I show you the solution I ended up using. As I mentioned in the introduction, the data I wanted for each NFT included the following things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NFT ID&lt;/li&gt;
&lt;li&gt;NFT list price (in BNB)&lt;/li&gt;
&lt;li&gt;NFT rarity score (a number randomly assigned to each NFT in the collection)&lt;/li&gt;
&lt;li&gt;Current price of BNB in US dollars&lt;/li&gt;
&lt;li&gt;Cost of NFT in US dollars&lt;/li&gt;
&lt;li&gt;Cost of each rarity point assigned to the NFT in US dollars&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I ended up with is a list of objects (or &lt;a href=&quot;https://www.w3schools.com/python/python_dictionaries.asp&quot;&gt;&quot;dictionaries&quot;&lt;/a&gt; in Python parlance) because each object in the list is made up of key value pairs. Here&apos;s a sample of what the list of data looks like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample NFT data to be added to CSV file&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 28.2, &apos;id&apos;: 4, &apos;nft_price&apos;: &apos;0.8&apos;, &apos;price_usd&apos;: 281.95, &apos;rs&apos;: 10},
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 77.54, &apos;id&apos;: 42, &apos;nft_price&apos;: &apos;1.1&apos;, &apos;price_usd&apos;: 387.68, &apos;rs&apos;: 5},
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 98.68, &apos;id&apos;: 174, &apos;nft_price&apos;: &apos;1.4&apos;, &apos;price_usd&apos;: 493.42, &apos;rs&apos;: 5}, 
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 29.68, &apos;id&apos;: 184, &apos;nft_price&apos;: &apos;1.6&apos;, &apos;price_usd&apos;: 563.9, &apos;rs&apos;: 19},
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 46.99, &apos;id&apos;: 256, &apos;nft_price&apos;: &apos;2&apos;, &apos;price_usd&apos;: 704.88, &apos;rs&apos;: 15},
    # more NFT data
]
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you&apos;re interested in seeing how I got this list of data, check out my &lt;a href=&quot;./filter-merge-and-update-python-lists-based-on-object-attributes&quot;&gt;previous blog post&lt;/a&gt; for a more in-depth explanation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ok, now that I&apos;ve established what the data looks like we can move on to how I turned this list into a CSV, complete with a header row of each key in the dictionary object.&lt;/p&gt;
&lt;h3&gt;The csv.DictWriter module&lt;/h3&gt;
&lt;p&gt;Unlike core JavaScript, which tends to be pretty bare-bones and makes users install packages for most everything they want to do, the Python standard library is quite robust.&lt;/p&gt;
&lt;p&gt;It comes with a &lt;a href=&quot;https://docs.python.org/3/library/csv.html#&quot;&gt;&lt;strong&gt;&lt;code&gt;csv&lt;/code&gt; module&lt;/strong&gt;&lt;/a&gt; that implements classes to read and write tabular data in CSV format out of the box, as the CSV (Comma Separated Values) format is the most common import and export formats for spreadsheets and databases.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;csv&lt;/code&gt; module had two packages of particular interest to me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/library/csv.html#csv.writer&quot;&gt;&lt;strong&gt;&lt;code&gt;writer&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - a writer object responsible for converting the user&apos;s data into delimited strings on a given file-like object.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/library/csv.html#csv.DictWriter&quot;&gt;&lt;strong&gt;&lt;code&gt;DictWriter&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - an object like a writer but it maps dictionaries to output rows. This object requires a &lt;code&gt;fieldnames&lt;/code&gt; parameter that is a sequence of keys which identifies the order in which values in the dictionary are passed to the &lt;code&gt;writerow()&lt;/code&gt; method.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since my Python data is formatted as a list of dictionaries, as shown in the previous section, it made the most sense for me to use the &lt;code&gt;csv.DictWriter&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;For me, the &lt;code&gt;fieldnames&lt;/code&gt; parameter would be composed of the keys of each dictionary: &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;bnb&lt;/code&gt;, &lt;code&gt;nft_price&lt;/code&gt;, etc. and that would guarantee that each dictionary of NFT info passed through the &lt;code&gt;DictWriter&lt;/code&gt; object would match up the proper value with its corresponding key. And &lt;code&gt;DictWriter&lt;/code&gt; also has two handy public methods I wanted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/library/csv.html#csv.DictWriter.writeheader&quot;&gt;&lt;strong&gt;&lt;code&gt;writeheader()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - a method to write a row with the field names to the writer&apos;s file object (i.e. the top row in a CSV that typically has the column names listed for each column of data).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/library/csv.html#csv.csvwriter.writerows&quot;&gt;&lt;strong&gt;&lt;code&gt;writerows()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - the method that writes all the elements in rows to the writer&apos;s file object (i.e. the list of NFT objects I wanted added to the CSV file).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;DictWriter&lt;/code&gt; was the right choice for my situation, so let&apos;s get to how I put it into practice to make my file next.&lt;/p&gt;
&lt;h3&gt;Format the Python data into a CSV and save it locally&lt;/h3&gt;
&lt;p&gt;To transform the list of Python dictionaries into a CSV using the &lt;code&gt;csv.DictWriter&lt;/code&gt; module, I created a new function called &lt;code&gt;download_csv()&lt;/code&gt;, and here is what the code looked like in my &lt;code&gt;for_sale_scraper.py&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def download_csv(self, card_list):
      &quot;&quot;&quot;Turn card list into CSV file.&quot;&quot;&quot;
      date_time = datetime.now().strftime(&quot;%Y_%m_%d-%I_%M_%p_&quot;)
      # add date time to the front of the file name 
      with open(date_time + &apos;NFTs_For_Sale.csv&apos;, &apos;w&apos;, encoding=&apos;utf8&apos;, newline=&quot;&quot;) as output_file:
          dict_writer = csv.DictWriter(output_file, fieldnames=[&apos;id&apos;, &apos;bnb&apos;, &apos;nft_price&apos;, &apos;price_usd&apos;, &apos;rs&apos;, &apos;cost_per_rs&apos;])
          dict_writer.writeheader()
          dict_writer.writerows(card_list)
      pprint(&quot;CSV NFTs For Sale file generated!&quot;)    
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will probably be easiest to go through this function line by line, so let&apos;s start from the top.&lt;/p&gt;
&lt;p&gt;The function takes in a &lt;code&gt;card_list&lt;/code&gt; argument which is what I want written to each row in the CSV, and the first thing it does is create a variable named &lt;code&gt;date_time&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;date_time = datetime.now().strftime(&quot;%Y_%m_%d-%I_%M_%p_&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;date_time&lt;/code&gt; is a formatted date and time string representing the current date in the format of &lt;code&gt;&quot;Year_Month_Day-Hour_Minute_AM/PM&quot;&lt;/code&gt;. When called, it will generate a string like &lt;code&gt;&quot;2024_04_11-03_30_PM_&quot;&lt;/code&gt;, which will be tacked on to the beginning of the CSV&apos;s file name so it&apos;s easy to sort and identify the files after they&apos;re generated.&lt;/p&gt;
&lt;p&gt;On to the next line of the function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with open(date_time + &apos;NFTs_For_Sale.csv&apos;, &apos;w&apos;, encoding=&apos;utf8&apos;, newline=&quot;&quot;) as output_file:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;with open&lt;/code&gt; opens a file for writing with the specified filename, which is the newly created &lt;code&gt;date_time&lt;/code&gt; variable concatenated with the &lt;code&gt;&quot;NFTs_For_Sale.csv&quot;&lt;/code&gt; string. The &lt;code&gt;&apos;w&apos;&lt;/code&gt; mode indicates the file will be opened for writing, the &lt;code&gt;encoding=&apos;utf8&apos;&lt;/code&gt; parameter specifies the character encoding to be used, and the &lt;code&gt;newline=&quot;&quot;&lt;/code&gt; ensures the proper newline character is used for writing rows to the CSV file. The whole thing is named &lt;code&gt;output_file&lt;/code&gt; for reference later in the function.&lt;/p&gt;
&lt;p&gt;Then we come to the &lt;code&gt;DictWriter&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    dict_writer = csv.DictWriter(output_file, fieldnames=[&apos;id&apos;, &apos;bnb&apos;, &apos;nft_price&apos;, &apos;price_usd&apos;, &apos;rs&apos;, &apos;cost_per_rs&apos;])
    dict_writer.writeheader()
    dict_writer.writerows(card_list)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is &lt;code&gt;DictWriter&lt;/code&gt;&apos;s time to shine, as a new instance of it is created and the &lt;code&gt;output_file&lt;/code&gt; is passed to it, along with the &lt;code&gt;fieldnames&lt;/code&gt; list which includes all the dictionary keys as the headers for the CSV file. In the following two lines of code, &lt;code&gt;DictWriter&lt;/code&gt; writes the header row to the CSV file with the names specified in &lt;code&gt;fieldnames&lt;/code&gt;, and writes the list of dictionaries (the &lt;code&gt;card_list&lt;/code&gt; passed to this function) to the CSV file. Each dictionary in the list represents a row in the CSV file.&lt;/p&gt;
&lt;p&gt;Job complete!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pprint(&quot;CSV NFTs For Sale file generated!&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, a success message is printed out at the end of the function indicating the CSV file has been successfully generated, and the file should show up in the repo alongside all the other previously project files.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-csv/csvs-in-repo.png&quot; alt=&quot;CSVs being generated in local NFT scraper repo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Note all the generated CSV files, neatly ordered in descending order by their filename dates.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And the &lt;code&gt;download_csv()&lt;/code&gt; function is called from the main Python function like in the code snippet below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;ve included the other functions called before &lt;code&gt;download_csv&lt;/code&gt; so you can see how I divvied up the work this file was doing, but I have not included the details of those functions because it&apos;s outside the scope of this post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for_sale_scraper.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if __name__ == &apos;__main__&apos;:
   scraper = ForSaleNFTScraper();
   cards = scraper.get_cards(max_card_count=200)
   card_data = [] 
   for card in cards:
    info = (scraper.get_nft_data(card))
    card_data.append(info)

   # filter out any extra cards that aren&apos;t for sale
   cards_for_sale = scraper.filter_priced_cards(card_data)

   # add rarity scores to all cards in the list by merging them with the id_rs_list
   cards_with_rs = scraper.get_cards_rarity_score(cards_for_sale)

     # add the current bnb price, current usd price of cards and current usd price of each rs point
   cards_with_bnb_rs = scraper.add_pricing_to_cards(cards_with_rs)

   # generate csv file 
   scraper.download_csv(cards_with_bnb_rs)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, my friend can generate CSVs of the NFT collection whenever he wants to, or he could even set up a cron job on his machine to run this script on a regular basis and then review the generated files at his convenience.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building a web scraper to collect data from the NFTrade site was a good exercise for me to learn more about Python, and it was a great opportunity for me to share my learnings in a series of blog posts for anyone else looking to do something similar.&lt;/p&gt;
&lt;p&gt;I scraped the data with Selenium Python, narrowed it down to the pieces I wanted, added some extra info like the cost of each NFT in US dollars, and then bundled all data up into a downloadable CSV for easy scanning and sorting.&lt;/p&gt;
&lt;p&gt;The extra nice thing about making it into a CSV is that the CSV reading and writing functions are part of the core Python library so I didn&apos;t even have to install any third party packages to make it work - it was actually quite straightforward in the end.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning to use Python&apos;s &lt;code&gt;csv.DictWriter&lt;/code&gt; module to make your own CSVs from list of data comes in handy in your own apps and projects.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; website&lt;/li&gt;
&lt;li&gt;Python &lt;a href=&quot;https://docs.python.org/3/library/csv.html#csv.DictWriter&quot;&gt;DictWriter documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;First blog post about &lt;a href=&quot;./scrape-data-from-a-lazy-loading-website-with-selenium-python&quot;&gt;scraping data from a lazy-loading website using Selenium Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Second blog post about &lt;a href=&quot;./use-selenium-with-python-to-target-the-x-path-of-a-particular-object&quot;&gt;limiting data searches to a particular element on a page instead of the whole page when using XPath&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Third blog post about &lt;a href=&quot;./filter-merge-and-update-python-lists-based-on-object-attributes&quot;&gt;filtering, merging, and updating lists of objects in Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>python</category><category>big data</category><category>csv</category></item><item><title>Filter, Merge, and Update Python Lists Based on Object Attributes</title><link>https://www.paigeniedringhaus.com/blog/filter-merge-and-update-python-lists-based-on-object-attributes/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/filter-merge-and-update-python-lists-based-on-object-attributes/</guid><description>Manipulating lists of items by object attributes is surprisingly tricky.</description><pubDate>Fri, 23 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-lists/list-hero.jpg&quot; alt=&quot;Handwritten list&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Last year, I wrote a web scraping program to collect data from one of the NFT collections on the &lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; site. My friend wanted the following data included in a CSV: all the NFTs currently for sale in the collection, the total price of each NFT in US dollars based on the current market price of the BNB cryptocurrency that the NFT is for sale in, and the price in USD per rarity point (a value randomly assigned to each NFT in the collection).&lt;/p&gt;
&lt;p&gt;The NFTrade website does not have a public API so instead of writing a Node.js script to fetch the data via HTTP calls, I built a small site scraping script to go to the website and actually &quot;scrape&quot; the data from it.&lt;/p&gt;
&lt;p&gt;Having not written a web scraper before, I chose to write the program in Python, and as I built the scraper, the project requirements got a bit more complex, and I learned a bunch of useful techniques when coding in Python, which I&apos;m sharing in a series of posts.&lt;/p&gt;
&lt;p&gt;After choosing the Selenium Python package to use Selenium WebDriver to scrape the data from NFTrade and extract the details from each NFT that I wanted (the NFT&apos;s ID and price in BNB), I needed to update my new list of NFT data in several ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I needed to filter out any NFTs that weren&apos;t currently for sale (some that were scraped off the site weren&apos;t actually for sale),&lt;/li&gt;
&lt;li&gt;I needed to match all the NFTs for sale with their &quot;rarity scores&quot; (as defined in a separate JSON list) and include those scores along with the rest of the NFT data,&lt;/li&gt;
&lt;li&gt;I needed to compute the total cost and cost per rarity point for each NFT in USD based on the current market price of BNB and add those prices to each NFT in the list as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know this sounds quite complicated, but I broke each of these requirements down into separate methods inside my Python script and learned &lt;em&gt;a lot&lt;/em&gt; about working with lists in Python along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to filter lists by whether an attribute exists in an object, how to merge two lists of items together based on matching attributes, and even how to add new object properties to the objects within a list in Python.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I am not normally a Python developer so my code examples may not be the most efficient or elegant Python code ever written, but they get the job done.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Sample Python Data&lt;/h2&gt;
&lt;p&gt;Before I dive into the specifics of my list manipulations in Python, let me give you a little background on what the data looks like that I was working with. Here&apos;s a small sample of what the list of NFT data looked like before I started mutating it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample NFT data scraped from the NFTrade site&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
    {&apos;id&apos;: 6774, &apos;nft_price&apos;: &apos;0.22&apos;},
    {&apos;id&apos;: 5710, &apos;nft_price&apos;: &apos;0.16&apos;},
    {&apos;id&apos;: 3187, &apos;nft_price&apos;: &apos;0.8&apos;},
    {&apos;id&apos;: 6482, &apos;nft_price&apos;: &apos;1.1&apos;},
    {&apos;id&apos;: 7689, &apos;nft_price&apos;: &apos;0.5&apos;},
    {&apos;id&apos;: 335, &apos;nft_price&apos;: &apos;4&apos;},
    {&apos;id&apos;: 7025, &apos;nft_price&apos;: &apos;1.057&apos;},
    {&apos;id&apos;: 597, &apos;nft_price&apos;: &apos;5&apos;},
    {&apos;id&apos;: 3936, &apos;nft_price&apos;: &apos;3.1&apos;},
    {&apos;id&apos;: 2834, &apos;nft_price&apos;: &apos;0.649&apos;},
    {&apos;id&apos;: 763, &apos;nft_price&apos;: &apos;1.65&apos;},
    {&apos;id&apos;: 7683, &apos;nft_price&apos;: None},
    {&apos;id&apos;: 7914, &apos;nft_price&apos;: None}
 ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see from the output above, the original data I started with was pretty sparse: the ID number for each NFT and the price in BNB (if it existed) were the only pieces of data present in each object from the info scraped off the NFTrade site. I had my work cut out for me to clean this list up and add more useful data to it, so let&apos;s move on to how I did so in the next section.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you&apos;d like to see more about how to scrape the browser data and gather just the necessary bits, read my first couple of blog posts &lt;a href=&quot;./scrape-data-from-a-lazy-loading-website-with-selenium-python&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;./use-selenium-with-python-to-target-the-x-path-of-a-particular-object&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Filter objects in a list on whether an attribute exists or not&lt;/h3&gt;
&lt;p&gt;As I mentioned in the introduction, the first thing I needed to do was clean this list up by removing any NFTs that didn&apos;t have a price.&lt;/p&gt;
&lt;p&gt;Due to how I had to lazily load and scrape the data from the NFTrade website initially, there was a good chance there were a handful of NFTs I gathered up that weren&apos;t for sale, and therefore didn&apos;t have prices, so I needed to weed them out first.&lt;/p&gt;
&lt;p&gt;Technically every NFT in my list had an &lt;code&gt;nft_price&lt;/code&gt; attribute, but if there was no price listed in the card&apos;s scraped data, the &lt;code&gt;nft_price&lt;/code&gt; attribute was assigned &lt;code&gt;None&lt;/code&gt;, which proved very useful.&lt;/p&gt;
&lt;p&gt;Inside of the &lt;code&gt;__main__&lt;/code&gt; method in my Python script, I&apos;d already scraped the data from the webpage with the &lt;code&gt;get_cards()&lt;/code&gt; method, then looped through the NFT data to grab just the bits of relevant data with the &lt;code&gt;get_nft_data()&lt;/code&gt; method. Now I wanted to filter down the cards to only include ones listed for sale.&lt;/p&gt;
&lt;p&gt;Here&apos;s the &lt;code&gt;__main__&lt;/code&gt; method code first:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for_sale_scraper.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if __name__ == &apos;__main__&apos;:
   scraper = ForSaleNFTScraper();
   cards = scraper.get_cards(max_card_count=200)
   card_data = [] 
   for card in cards:
    info = (scraper.get_nft_data(card))
    card_data.append(info)

   # filter out any extra cards that aren&apos;t for sale
   cards_for_sale = scraper.filter_priced_cards(card_data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&apos;s the method I came up with to filter down to just the NFTs for sale: &lt;code&gt;filter_priced_cards()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def filter_priced_cards(self, card_list):
    &quot;&quot;&quot;Filter card list to only cards with NFT cost.&quot;&quot;&quot;

    # filter out any cards in the list that don&apos;t have an NFT price equal to None
    cards_for_sale = list(filter(lambda card: card[&apos;nft_price&apos;] != None, card_list))
    return cards_for_sale
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s break down what&apos;s happening in the second line of the &lt;code&gt;filter_priced_cards()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;I used Python&apos;s built-in &lt;a href=&quot;https://docs.python.org/3/library/functions.html#filter&quot;&gt;&lt;code&gt;filter()&lt;/code&gt;&lt;/a&gt; function to iterate over the &lt;code&gt;card_list&lt;/code&gt; passed to the function to create a new list named &lt;code&gt;cards_for_sale&lt;/code&gt;. The &lt;a href=&quot;https://www.programiz.com/python-programming/anonymous-function&quot;&gt;anonymous lambda function&lt;/a&gt; inside of &lt;code&gt;filter()&lt;/code&gt; takes each &lt;code&gt;card&lt;/code&gt; in the &lt;code&gt;card_list&lt;/code&gt; and returns &lt;code&gt;True&lt;/code&gt; if the &lt;code&gt;nft_price&lt;/code&gt; attribute of the card is not &lt;code&gt;None&lt;/code&gt;, and &lt;code&gt;False&lt;/code&gt; if it is - this is how it filters out all the cards that don&apos;t have a price.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;list()&lt;/code&gt; function that wraps the &lt;code&gt;filter()&lt;/code&gt; converts the result back to a list, because &lt;code&gt;filter()&lt;/code&gt; returns a filter object which is an iterator, not a list.&lt;/p&gt;
&lt;p&gt;And finally, the new &lt;code&gt;cards_for_sale&lt;/code&gt; list is returned.&lt;/p&gt;
&lt;h3&gt;Merge two lists together by matching object keys&lt;/h3&gt;
&lt;p&gt;Once the NFTs not for sale have been filtered out, the next step is to add the rarity score to each NFT based on its ID.&lt;/p&gt;
&lt;p&gt;For this particular set of NFTs, each NFT had a &quot;rarity score&quot; that had been randomly assigned to it. The rarity scores for each NFT were listed in a separate JSON file in the project and they look like this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;id_rs_score.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {&quot;id&quot;: 1, &quot;rs&quot;: 18},
  {&quot;id&quot;: 2, &quot;rs&quot;: 13},
  {&quot;id&quot;: 3, &quot;rs&quot;: 14},
  {&quot;id&quot;: 4, &quot;rs&quot;: 10},
  {&quot;id&quot;: 5, &quot;rs&quot;: 22},
  {&quot;id&quot;: 6, &quot;rs&quot;: 13},
  {&quot;id&quot;: 7, &quot;rs&quot;: 10},
  {&quot;id&quot;: 8, &quot;rs&quot;: 13},
  {&quot;id&quot;: 9, &quot;rs&quot;: 13},
  {&quot;id&quot;: 10, &quot;rs&quot;: 9},
  // more ids and rarity scores (&quot;rs&quot;) below
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I needed to combine my list of &lt;code&gt;cards_for_sale&lt;/code&gt; with the rarity scores in the JSON file by matching up the &lt;code&gt;id&lt;/code&gt; attribute in each list of objects. For this task, I came up with the following function: &lt;code&gt;get_cards_rarity_score()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_cards_rarity_score(self, card_list):
    &quot;&quot;&quot;Combine rarity scores with card list by ID.&quot;&quot;&quot;

    # get rs data for each card from json file 
    with open(&quot;id_rs_list.json&quot;) as file:
        id_rs_list = json.load(file)

    # merge together cards with id_rs_list by their matching ID numbers 
    match_cards_with_rs_list = groupby(sorted(card_list + id_rs_list, key=itemgetter(&quot;id&quot;)), itemgetter(&quot;id&quot;))
    combined_cards = [dict(ChainMap(*g)) for k, g in match_cards_with_rs_list]

    # filter out all the items in the merged list without a &quot;for sale&quot; value 
    filtered_combined_cards = []
    for card in combined_cards:
        if &apos;nft_price&apos; in card:
            filtered_combined_cards.append(card)

    return filtered_combined_cards
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To combine the rarity score with any of the NFT objects contained in the &lt;code&gt;card_list&lt;/code&gt; list, the first thing that had to happen was to read the data from the &lt;code&gt;id_rs_list.json&lt;/code&gt; file and assign it to a variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    # get rs data for each card from json file 
    with open(&quot;id_rs_list.json&quot;) as file:
        id_rs_list = json.load(file)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the JSON list was extracted from the file, the &lt;code&gt;card_list&lt;/code&gt; and &lt;code&gt;id_rs_list&lt;/code&gt; needed to be merged together based on their matching IDs.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.python.org/3/library/itertools.html#itertools.groupby&quot;&gt;&lt;code&gt;groupby()&lt;/code&gt;&lt;/a&gt; function groups elements with the same ID, and then &lt;a href=&quot;https://docs.python.org/3/library/collections.html#collections.ChainMap&quot;&gt;&lt;code&gt;ChainMap()&lt;/code&gt;&lt;/a&gt; merged the grouped items into Python &lt;a href=&quot;https://www.w3schools.com/python/python_dictionaries.asp&quot;&gt;dictionaries&lt;/a&gt; (objects). The result was a list of dictionaries (&lt;code&gt;combined_cards&lt;/code&gt;) where each dictionary represented a card with combined information from both lists.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    # merge together cards with id_rs_list by their matching ID numbers 
    match_cards_with_rs_list = groupby(sorted(card_list + id_rs_list, key=itemgetter(&quot;id&quot;)), itemgetter(&quot;id&quot;))
    combined_cards = [dict(ChainMap(*g)) for k, g in match_cards_with_rs_list]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing to note: the &lt;code&gt;combined_cards&lt;/code&gt; list has &lt;em&gt;every&lt;/em&gt; NFT listed from the &lt;code&gt;id_rs_list&lt;/code&gt;, not just the ones whose IDs match the IDs in the &lt;code&gt;card_list&lt;/code&gt;. So the &lt;code&gt;combined_cards&lt;/code&gt; list looks like the data below - but for every item in &lt;code&gt;id_rs_list&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ 
 {&apos;id&apos;: 1, &apos;rs&apos;: 4},
 {&apos;id&apos;: 2, &apos;nft_price&apos;: &apos;3&apos;, &apos;rs&apos;: 6},
 {&apos;id&apos;: 3, &apos;rs&apos;: 22},
 {&apos;id&apos;: 4, &apos;rs&apos;: 4},
 {&apos;id&apos;: 5, &apos;rs&apos;: 10},
 {&apos;id&apos;: 6, &apos;nft_price&apos;: &apos;5&apos;, &apos;rs&apos;: 1},
 {&apos;id&apos;: 7, &apos;rs&apos;: 1},
 {&apos;id&apos;: 8, &apos;nft_price&apos;: &apos;0.1&apos;, &apos;rs&apos;: 14},
 {&apos;id&apos;: 9, &apos;nft_price&apos;: &apos;1.5&apos;, &apos;rs&apos;: 5},
 {&apos;id&apos;: 10, &apos;rs&apos;: 1},
 # more IDs and NFT data 
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since the &lt;code&gt;combined_cards&lt;/code&gt; list had &lt;em&gt;every single NFT&lt;/em&gt; in it (not just ones for sale), once more I had to filter the list down so that every item without an &lt;code&gt;&quot;nft_price&quot;&lt;/code&gt; was omitted.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    # filter out all the items in the merged list without a &quot;for sale&quot; value 
    filtered_combined_cards = []
    for card in combined_cards:
        if &apos;nft_price&apos; in card:
            filtered_combined_cards.append(card)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, since there&apos;s a (very likely) chance the NFT data in the &lt;code&gt;combined_cards&lt;/code&gt; list did not have the &lt;code&gt;&quot;nft_price&quot;&lt;/code&gt; attribute, I checked if each card had the key &lt;code&gt;&quot;nft_price&quot;&lt;/code&gt; and if so, the card was added to the new &lt;code&gt;filtered_combined_cards&lt;/code&gt; list.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;filtered_combined_cards&lt;/code&gt; list ended up looking like the code snippet below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
 {&apos;id&apos;: 4, &apos;nft_price&apos;: &apos;0.8&apos;, &apos;rs&apos;: 10},
 {&apos;id&apos;: 42, &apos;nft_price&apos;: &apos;1.1&apos;, &apos;rs&apos;: 5},
 {&apos;id&apos;: 174, &apos;nft_price&apos;: &apos;1.4&apos;, &apos;rs&apos;: 5},
 {&apos;id&apos;: 184, &apos;nft_price&apos;: &apos;1.6&apos; &apos;rs&apos;: 19},
 {&apos;id&apos;: 256, &apos;nft_price&apos;: &apos;2&apos;, &apos;rs&apos;: 15},
 {&apos;id&apos;: 335, &apos;nft_price&apos;: &apos;4&apos;, &apos;rs&apos;: 2},
 {&apos;id&apos;: 562, &apos;nft_price&apos;: &apos;1.2&apos;, &apos;rs&apos;: 2},
 {&apos;id&apos;: 584, &apos;nft_price&apos;: &apos;5&apos;, &apos;rs&apos;: 14},
 {&apos;id&apos;: 597, &apos;nft_price&apos;: &apos;5&apos;, &apos;rs&apos;: 17},
 # more NFT data here
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once all this data manipulation and list combining was done, the function returned the final list of cards (&lt;code&gt;filtered_combined_cards&lt;/code&gt;) that had both rarity score information and an &lt;code&gt;&quot;nft_price&quot;&lt;/code&gt; attribute included.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return filtered_combined_cards
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For reference, here&apos;s the &lt;code&gt;__main__&lt;/code&gt; function in the Python script, which called the &lt;code&gt;get_cards_rarity_score()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for_sale_scraper.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if __name__ == &apos;__main__&apos;:
   scraper = ForSaleNFTScraper();
   cards = scraper.get_cards(max_card_count=200)
   card_data = [] 
   for card in cards:
    info = (scraper.get_nft_data(card))
    card_data.append(info)

   # filter out any extra cards that aren&apos;t for sale
   cards_for_sale = scraper.filter_priced_cards(card_data)

   # filter out any extra cards that aren&apos;t for sale
   cards_for_sale = scraper.filter_priced_cards(card_data)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Add new object properties to each object in a list&lt;/h3&gt;
&lt;p&gt;All right, here&apos;s the last Python list manipulation tip I&apos;ll be sharing in this post: how to add new properties to each object in a list.&lt;/p&gt;
&lt;p&gt;After filtering the NFTs to just the ones for sale, and adding the rarity scores from the &lt;code&gt;id_rs_list&lt;/code&gt; JSON file, I needed to fetch the current price of 1 BNB compared to US dollars, calculate the current price of each NFT in USD, and calculate the cost per rarity point for each NFT.&lt;/p&gt;
&lt;p&gt;Fortunately the cryptocurrency data aggregation site &lt;a href=&quot;https://www.coingecko.com/&quot;&gt;CoinGecko&lt;/a&gt;, has a REST API that I could use to get the current market price of BNB cryptocurrency in US dollars, and then calculate the rest of the required data based on the info in my NFT card list.&lt;/p&gt;
&lt;p&gt;Here is the &lt;code&gt;add_pricing_to_cards()&lt;/code&gt; function I came up with to calculate the prices.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def add_pricing_to_cards(self, card_list):
    &quot;&quot;&quot;Get current price of BNB and compute cost per rarity point&quot;&quot;&quot;

    URL=&quot;https://api.coingecko.com/api/v3/simple/price?ids=binancecoin&amp;amp;vs_currencies=USD&quot;
    response = requests.get(URL).json()
    bnb = response[&apos;binancecoin&apos;][&apos;usd&apos;]

    # add the current value of bnb to the card_list 
    cards_bnb_price = [dict(card, bnb=bnb) for card in card_list]

    # compute the current price of usd for each card based on its bnb price       
    cards_with_usd_price= [dict(card, price_usd=round(float(card[&apos;nft_price&apos;])*card[&apos;bnb&apos;], 2)) for card in cards_bnb_price]

    # compute the current cost usd of each rarity score point         
    cards_with_rs_prices = [dict(card, cost_per_rs=round(card[&apos;price_usd&apos;]/card[&apos;rs&apos;], 2)) for card in cards_with_usd_price]

    return cards_with_rs_prices  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the function, the first thing I did was call the CoinGecko price API to get the current price of BNB in USD.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    URL=&quot;https://api.coingecko.com/api/v3/simple/price?ids=binancecoin&amp;amp;vs_currencies=USD&quot;
    response = requests.get(URL).json()
    bnb = response[&apos;binancecoin&apos;][&apos;usd&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I added the &lt;code&gt;bnb&lt;/code&gt; to each object in the input &lt;code&gt;card_list&lt;/code&gt; and created a new list named &lt;code&gt;cards_bnb_price&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    # add the current value of bnb to the card_list 
    cards_bnb_price = [dict(card, bnb=bnb) for card in card_list]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After including the current BNB price in USD, I was able to compute the total price in USD for each NFT in the list by multiplying the card&apos;s original price in BNB by the current price of BNB in USD.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    # compute the current price of usd for each card based on its bnb price       
    cards_with_usd_price= [dict(card, price_usd=round(float(card[&apos;nft_price&apos;])*card[&apos;bnb&apos;], 2)) for card in cards_bnb_price]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I also calculated the price in USD per rarity score point as well, simply by dividing the card&apos;s total price in USD by the rarity score number (&lt;code&gt;rs&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    # compute the current cost usd of each rarity score point         
    cards_with_rs_prices = [dict(card, cost_per_rs=round(card[&apos;price_usd&apos;]/card[&apos;rs&apos;], 2)) for card in cards_with_usd_price]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function then returned the list of cards with the added pricing info, including BNB price, USD price, and USD cost per rarity score point. The final list data looked like this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 28.2, &apos;id&apos;: 4, &apos;nft_price&apos;: &apos;0.8&apos;, &apos;price_usd&apos;: 281.95, &apos;rs&apos;: 10},
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 77.54, &apos;id&apos;: 42, &apos;nft_price&apos;: &apos;1.1&apos;, &apos;price_usd&apos;: 387.68, &apos;rs&apos;: 5},
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 98.68, &apos;id&apos;: 174, &apos;nft_price&apos;: &apos;1.4&apos;, &apos;price_usd&apos;: 493.42, &apos;rs&apos;: 5}, 
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 29.68, &apos;id&apos;: 184, &apos;nft_price&apos;: &apos;1.6&apos;, &apos;price_usd&apos;: 563.9, &apos;rs&apos;: 19},
    {&apos;bnb&apos;: 352.44, &apos;cost_per_rs&apos;: 46.99, &apos;id&apos;: 256, &apos;nft_price&apos;: &apos;2&apos;, &apos;price_usd&apos;: 704.88, &apos;rs&apos;: 15},
    # more NFT data
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;add_pricing_to_cards()&lt;/code&gt; function is called from the main Python function like so:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for_sale_scraper.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if __name__ == &apos;__main__&apos;:
   scraper = ForSaleNFTScraper();
   cards = scraper.get_cards(max_card_count=200)
   card_data = [] 
   for card in cards:
    info = (scraper.get_nft_data(card))
    card_data.append(info)

   # filter out any extra cards that aren&apos;t for sale
   cards_for_sale = scraper.filter_priced_cards(card_data)

   # filter out any extra cards that aren&apos;t for sale
   cards_for_sale = scraper.filter_priced_cards(card_data)

   # add rarity scores to all cards in the list by merging them with the id_rs_list
   cards_with_rs = scraper.get_cards_rarity_score(cards_for_sale)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now that I had all the data that my friend requested for each NFT in the collection for sale on NFTrade, all that was left to do was turn the whole list into a downloadable CSV that would be easy to sort and manipulate. I&apos;ll save that for a future post.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When I had to use Python to build a website scraper to get NFT data off of the NFTrade site, I learned a lot of useful new coding tricks along the way.&lt;/p&gt;
&lt;p&gt;After I&apos;d managed to scrape the data with the help of Selenium Python, and extract the initial data I needed from each NFT by using WebDriver&apos;s XPath, my job was far from complete.&lt;/p&gt;
&lt;p&gt;I needed to take the little data I had and combine those NFTs with &quot;rarity scores&quot; in a JSON file, fetch the current market price for BNB cryptocurrency in US dollars, and then compute the total cost of each NFT and cost per rarity point, and as I completed these tasks I learned a heck of a lot about how to work with lists of complex objects in various new ways. And I feel confident these new techniques will help me out in any future Python endeavors I might undertake.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more blogs about the problems I had to solve while building this Python website scraper in addition to other topics on JavaScript or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning to filter, merge, and alter objects within lists in Python proves helpful for you in your own projects.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; website&lt;/li&gt;
&lt;li&gt;Python &lt;a href=&quot;https://docs.python.org/3/library/index.html&quot;&gt;documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.coingecko.com/&quot;&gt;CoinGecko&lt;/a&gt; cryptocurrency tracker and analytics site&lt;/li&gt;
&lt;li&gt;First blog post about &lt;a href=&quot;./scrape-data-from-a-lazy-loading-website-with-selenium-python&quot;&gt;scraping data from a lazy-loading website using Selenium Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow up blog post about &lt;a href=&quot;./use-selenium-with-python-to-target-the-x-path-of-a-particular-object&quot;&gt;limiting data searches to a particular element on a page instead of the whole page when using XPath&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>python</category><category>programming</category></item><item><title>Use Selenium with Python to Target the XPath of a Particular Object</title><link>https://www.paigeniedringhaus.com/blog/use-selenium-with-python-to-target-the-xpath-of-a-particular-object/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/use-selenium-with-python-to-target-the-xpath-of-a-particular-object/</guid><description>Extract data from each item in a list of items instead of the whole webpage.</description><pubDate>Mon, 18 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-xpath/dashboard-hero.jpg&quot; alt=&quot;Webpage analytics dashboard&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Earlier this year, I needed to write a program for my friend to collect the data of one of the NFT collections on the &lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; site. He wanted the following data included: all the NFTs currently for sale in the collection and the price of each NFT in US dollars based on the current market price of the BNB cryptocurrency that the NFT is for sale in, and he wanted it listed out line by line in a CSV file that he could sort and manipulate.&lt;/p&gt;
&lt;p&gt;Unfortunately, the NFTrade website does not have a public API so instead of writing a Node.js script to fetch the data via HTTP calls, I built a small script to navigate to the website page and actually &quot;scrape&quot; the data off of it.&lt;/p&gt;
&lt;p&gt;Having not written a web scraper before, I chose to write the program in Python as it seems to be a very popular programming language choice for a task such as this. While I built this scraper, the project requirements evolved and got more complex, and I learned a bunch of useful new techniques when using Python, which I&apos;ll be sharing in a series of posts over the coming months.&lt;/p&gt;
&lt;p&gt;After I&apos;d settled on using the Selenium Python package to start a Selenium WebDriver instance and scrape the data from NFTrade, I hit a snag: I was collecting all the individual NFT data to loop through and pull the details from, but each time the loop ran it only collected the data from the first NFT in the list.&lt;/p&gt;
&lt;p&gt;I was stumped and turned to the Internet for help and (once again) Stack Overflow came through for me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When extracting scraped web data using Selenium WebDriver&apos;s XPath to target the data, in order to search inside a particular element instead of the whole document, a period (&lt;code&gt;.&lt;/code&gt;) must be added in front of the XPath. I&apos;ll show you how to do it in this post.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I am not normally a Python developer so my code examples may not be the most efficient or elegant Python code ever written, but they get the job done.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Selenium Python package&lt;/h2&gt;
&lt;p&gt;For my project, I ended up using the &lt;a href=&quot;https://selenium-python.readthedocs.io/&quot;&gt;&lt;strong&gt;Selenium Python package&lt;/strong&gt;&lt;/a&gt; because it can scrape websites with dynamically loaded data, which is how NFTrade works. A user lands on a collection of NFTs and as they scroll down the page, periodically more NFTs are loaded into the browser window via JavaScript.&lt;/p&gt;
&lt;p&gt;Selenium Python operates the Selenium WebDriver software and drives a browser just like a user would, and although its original use was for automated end-to-end testing of software, it can also be used to scrape data off of live web pages.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to read more about how to use Selenium Python for this, I encourage you to visit &lt;a href=&quot;./scrape-data-from-a-lazy-loading-website-with-selenium-python&quot;&gt;my first blog post&lt;/a&gt; on this subject where I go in depth on it.&lt;/p&gt;
&lt;h3&gt;What is XPath?&lt;/h3&gt;
&lt;p&gt;Among the many useful methods included with the Selenium Python package are the methods &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.find_element&quot;&gt;&lt;code&gt;find_element()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.find_elements&quot;&gt;&lt;code&gt;find_elements()&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#locate-elements-by&quot;&gt;&lt;code&gt;By.XPATH&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;find_element&lt;/code&gt; methods do what their name implies: find an element (or elements) given a &lt;code&gt;By&lt;/code&gt; strategy and locator.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#locate-elements-by&quot;&gt;&lt;code&gt;By&lt;/code&gt;&lt;/a&gt; accepts element IDs, names, attributes, XPaths, class names, etc. And &lt;a href=&quot;https://www.w3schools.com/xml/xml_xpath.asp&quot;&gt;XPath&lt;/a&gt; is a syntax used to navigate through elements and attributes in a standard XML document (webpage).&lt;/p&gt;
&lt;p&gt;Due to the NFTrade site&apos;s structure, I used XPath expressions to identify all the individual NFTs on the page and scrape the data from each NFT to include later in my CSV file.&lt;/p&gt;
&lt;h3&gt;The Problem: XPath was targeting the whole document&lt;/h3&gt;
&lt;p&gt;After I&apos;d written the code to initially fire up my Selenium WebDriver instance, navigate to the NFTrade site, and load the NFTs into the browser that I wanted to scrape the data from, I had a list of NFT info I needed to slim down to just the data points I wanted to include in the CSV.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you&apos;d like to see how to scrape the browser data in-depth, read my first blog post &lt;a href=&quot;./scrape-data-from-a-lazy-loading-website-with-selenium-python&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For me, this was things like: the NFT ID number (part of the NFT card&apos;s name) and the the NFT&apos;s sale price in BNB.&lt;/p&gt;
&lt;p&gt;Inside of the &lt;code&gt;__main__&lt;/code&gt; method in my Python script, I&apos;d scraped the data from the webpage with the &lt;code&gt;get_cards()&lt;/code&gt; method, and then I wanted to loop through the NFT data I&apos;d collected and extract the data points from each NFT card with my &lt;code&gt;get_nft_data()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Here&apos;s the &lt;code&gt;__main__&lt;/code&gt; method code for reference:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for_sale_scraper.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if __name__ == &apos;__main__&apos;:
   scraper = ForSaleNFTScraper();
   cards = scraper.get_cards(max_card_count=200)
   card_data = []
   for card in cards:
    info = (scraper.get_nft_data(card)) 
    card_data.append(info)

    # pprint the card data to ensure we&apos;re getting the correct data out of each card
    pprint(card_data)    
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is the code for my &lt;code&gt;get_nft_data()&lt;/code&gt; method.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_nft_data(self, nft_data):
        &quot;&quot;&quot;Extracts and prints out NFT specific data.&quot;&quot;&quot;
        nft_name_element = self.driver.find_element(By.XPATH, &apos;//div[contains(@class, &quot;Item_itemName__ckoHR&quot;)]&apos;)
        nft_name = nft_name_element.get_attribute(&quot;innerHTML&quot;)
        nft_id = nft_name.partition(&apos;#&apos;)[-1]

        nft_price_element = nft_data.find_element(By.XPATH, &apos;//div[contains(@class, &quot;Item_itemPriceValueTxt__lblqJ&quot;)]&apos;)
        nft_price = nft_price_element.get_attribute(&quot;innerHTML&quot;)
        return {
            &apos;id&apos;: int(nft_id), &apos;price&apos;: nft_price
            }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What my &lt;code&gt;get_nft_data()&lt;/code&gt; method is &lt;em&gt;supposed&lt;/em&gt; to do is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use the XPath within each card to get the NFT&apos;s name via &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webelement.WebElement.get_attribute&quot;&gt;&lt;code&gt;get_attribute(&quot;innerHTML&quot;)&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;innerHTML&lt;/code&gt; targets the text content of the element which includes its ID number at the end of the name), &lt;a href=&quot;https://www.w3schools.com/python/ref_string_partition.asp&quot;&gt;&lt;code&gt;partition()&lt;/code&gt;&lt;/a&gt; the string into a tuple based on the &lt;code&gt;#&lt;/code&gt; included in the name, and take the last element in the tuple (which is the ID number).&lt;/li&gt;
&lt;li&gt;It should also get the NFT&apos;s price (also using &lt;code&gt;get_attribute(&quot;innerHTML&quot;)&lt;/code&gt;) via a second XPath within the NFT card.&lt;/li&gt;
&lt;li&gt;Finally return those two elements together as a new object with the keys of &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;price&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In theory, I wanted that to happen for every NFT I&apos;d collected into my &lt;code&gt;card_data&lt;/code&gt; list. In practice, I got 200 elements that all contained the ID and price data from the very first card in my &lt;code&gt;card_data&lt;/code&gt; list.&lt;/p&gt;
&lt;p&gt;Not quite what I was hoping for.&lt;/p&gt;
&lt;h3&gt;The Solution: How to restrict XPath inside a particular element&lt;/h3&gt;
&lt;p&gt;After several failed variations of the code above and searching through many Stack Overflow posts without success, I finally wrote my own SO post explaining my situation and asking for help from the greater web development community.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;d like to see my original Stack Overflow post and the helpful responses provided, &lt;a href=&quot;https://stackoverflow.com/questions/75604911/python-web-scraping-with-selenium-only-extracts-first-elements-data-in-list-of&quot;&gt;here&lt;/a&gt; is a link.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just over 30 minutes after posting my question, a kind soul answered it and got me moving forward again. That&apos;s the power of the web dev community at its finest.&lt;/p&gt;
&lt;p&gt;Below is the corrected &lt;code&gt;get_nft_data()&lt;/code&gt; code that actually gets the data from each individual NFT as the data is looped over. I also added some comments between lines of code to explain what&apos;s happening at each step.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_nft_data(self, nft_data):
      &quot;&quot;&quot;Extracts and prints out card specific data.&quot;&quot;&quot;
      # get full card name &quot;NFT_CARD #1234&quot; by XPATH
      nft_name_element = nft_data.find_element(By.XPATH, &apos;.//div[contains(@class, &quot;Item_itemName__ckoHR&quot;)]&apos;)
      nft_name = nft_name_element.text
      # parse out just ID number from name
      nft_id = nft_name.partition(&apos;#&apos;)[-1]

      # get nft recently sold value by XPATH
      nft_bnb_sale_price = nft_data.find_elements(By.XPATH, &apos;.//div[contains(@class, &quot;Item_itemPriceValueTxt__lblqJ&quot;)]&apos;)
      
      # if there is a for sale price, take it 
      if nft_bnb_sale_price:
          nft_price = nft_bnb_sale_price[0].text
      else: 
      # if there&apos;s no value, just put None in place of a value    
          nft_price = None   

      return {
          &apos;id&apos;: int(nft_id), 
          &apos;nft_price&apos;: nft_price
          }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this version of the Python code, there&apos;s three main differences.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The first is that instead of using &lt;code&gt;self.driver.find_element&lt;/code&gt;, this code is using &lt;code&gt;nft_data.find_element&lt;/code&gt;. By substituting &lt;code&gt;nft_data&lt;/code&gt; instead of &lt;code&gt;self.driver&lt;/code&gt;, it allows the XPath search to be restricted to a particular element.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Second, inside of each &lt;code&gt;find_element&lt;/code&gt; method referencing &lt;code&gt;By.XPATH&lt;/code&gt;, the XPath being passed has a &lt;code&gt;.&lt;/code&gt; in front of it. So &lt;code&gt;&apos;//div[contains(@class, &quot;Item_itemName_ckoHR&quot;)]&apos;&lt;/code&gt; becomes &lt;code&gt;&apos;.//div[contains(@class, &quot;Item_itemName__ckoHR&quot;)]&apos;&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The dot (&lt;code&gt;.&lt;/code&gt;) further restricts the XPath&apos;s search inside of a particular element (or &quot;context node&quot;). If the &lt;code&gt;.&lt;/code&gt; is not included, XPath will search the whole document, which is why it was always finding the values from the first NFT element each time the loop ran.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Last, the user suggested I could use &lt;code&gt;.text&lt;/code&gt; to get the NFT name and BNB price instead of having to write out the lengthier &lt;code&gt;.get_attribute(&quot;innerHTML&quot;)&lt;/code&gt; each time to reach the text in the NFT, which was a nice improvement in code readability.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The solution also mentioned there was a chance that some of the NFTs collected from the page may not have a price listed (NFTrade displays all NFTs in a collection, not just the ones for sale), and recommended wrapping the code that gets the &lt;code&gt;nft_price&lt;/code&gt; in an &lt;code&gt;if / else&lt;/code&gt; block so if the price is present, it will be collected and returned, and if it&apos;s not, it&apos;ll return &lt;code&gt;None&lt;/code&gt; in place of the value and not throw an error in the code.&lt;/p&gt;
&lt;p&gt;Hence this code for checking sale price:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; # if there is a for sale price, take it 
      if nft_bnb_sale_price:
          nft_price = nft_bnb_sale_price[0].text
      else: 
      # if there&apos;s no value, just put None in place of a value    
          nft_price = None   
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Test the refactored code&lt;/h3&gt;
&lt;p&gt;With my newly refactored &lt;code&gt;get_nft_data()&lt;/code&gt; method at the ready, it was time to test it out in my Python script.&lt;/p&gt;
&lt;p&gt;As a reminder, my &lt;code&gt;__main__&lt;/code&gt; method looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if __name__ == &apos;__main__&apos;:
   scraper = ForSaleNFTScraper();
   cards = scraper.get_cards(max_card_count=200)
   card_data = [] 
   for card in cards:
    info = (scraper.get_nft_data(card))
    card_data.append(info)

    # pprint the card data to ensure we&apos;re getting the correct data out of each card
    pprint(card_data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, when I ran the script from the command line with &lt;code&gt;python for_sale_scraper.py&lt;/code&gt;, here&apos;s a screenshot of the output I received.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-xpath/nft-xpath-data-output.png&quot; alt=&quot;Output from each of the NFT cards run through the  method&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;If you look closely you&apos;ll see that each object in this area has a different ID and price in it.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As you can see from the image, I got an array of items and each item in the array had a different &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;nft_price&lt;/code&gt; from the others. Now the &lt;code&gt;get_nft_data()&lt;/code&gt; method was working correctly, targeting the next NFT in the &lt;code&gt;card_data&lt;/code&gt; array with each successive iteration in the loop and pulling out the data specific to that card.&lt;/p&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;p&gt;With that hurdle overcome, I was ready to move on to the next steps of this project: converting the NFT&apos;s BNB prices into the current USD prices and assembling them into a CSV spreadsheet. Those tasks will be covered in detail in upcoming blog posts.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When I was asked to put together a spreadsheet of all the NFTs for sale in a particular collection on NFTrade, I ended up using Python to build a website scraper to accomplish it and learned a lot of new problem-solving techniques in the process.&lt;/p&gt;
&lt;p&gt;I managed to load and collect all the NFT data from a web page with the assistance of the Selenium Python package, but I got throughly stuck when trying to iterate through my data to extract the ID and price for each NFT from it.&lt;/p&gt;
&lt;p&gt;Luckily, the Stack Overflow community came through for me and taught me about the finer points of using Selenium WebDriver&apos;s XPath to target specific elements within a page instead of the whole page when looking for particular pieces of data, which got me unstuck and on my way to building my spreadsheet of data.&lt;/p&gt;
&lt;p&gt;Thank goodness for the knowledge sharing of the online web development community - I am truly grateful to be able to turn to them when I&apos;ve exhausted my own ideas to solve a problem.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more blogs about the problems I had to solve while building this Python website scraper in addition to other topics on JavaScript or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning how to restrict XPath searches to a particular element on a page instead of the entire page proves helpful for you in the future like was for me.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://selenium-python.readthedocs.io/&quot;&gt;Selenium Python&lt;/a&gt; docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.selenium.dev/documentation/webdriver/&quot;&gt;Selenium WebDriver&lt;/a&gt; docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; website&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/xml/xml_xpath.asp&quot;&gt;XPath&lt;/a&gt; documentation&lt;/li&gt;
&lt;li&gt;Original &lt;a href=&quot;https://stackoverflow.com/questions/75604911/python-web-scraping-with-selenium-only-extracts-first-elements-data-in-list-of&quot;&gt;Stack Overflow post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Previous blog post about &lt;a href=&quot;./scrape-data-from-a-lazy-loading-website-with-selenium-python&quot;&gt;scraping data from a lazy-loading website using Selenium Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>python</category><category>selenium</category><category>big data</category><category>webdriver</category><category>web scraping</category></item><item><title>Scrape Data from a Lazy Loading Website with Selenium Python</title><link>https://www.paigeniedringhaus.com/blog/scrape-data-from-a-lazy-loading-website-with-selenium-python/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/scrape-data-from-a-lazy-loading-website-with-selenium-python/</guid><description>No API to fetch data? No problem when you can build your own web scraper.</description><pubDate>Sun, 22 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-lazy-load-data/python-selenium-nftrade-hero.png&quot; alt=&quot;Python logo, Selenium Python logo, NFTrade site&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A few months ago, my friend wanted me to write a program to collect the data of one of the NFT collections on the &lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; site, compute the current price of each NFT in US dollars based on the current market price of the BNB cryptocurrency it was listed for sale in, and compile all of the NFTs for sale into a CSV file that he could sort and manipulate.&lt;/p&gt;
&lt;p&gt;Unfortunately, the NFTrade website does not have a public API so writing a Node.js script to fetch the data from the API and format it as required was not an option. Instead, I needed to make a site scraper to actually go to the website page and &quot;scrape&quot; the data off of it.&lt;/p&gt;
&lt;p&gt;Having not written a web scraper before (and also wanting to make the script easier for my friend to update and run on his own machine), I decided to write the program in Python (it seems to be a very popular programming language choice for a task such as this). Along the way, my little web scraper&apos;s requirements evolved and got more complex, and I learned a bunch of useful new techniques about using Python for my project, which I intend to share in a series of posts over the coming months.&lt;/p&gt;
&lt;p&gt;My first attempt to scrape the data from NFTrade was unsuccessful beyond locating the first 75 NFTs on the page. I figured out this was because NFTrade (as many other websites do) lazy loads NFTs onto the page 75 at a time: once the user&apos;s scrolled down far enough to reach the end of the currently visible items, the site loads the next batch of elements onto the page (essentially a fancier version of pagination). So I needed a way to have my web scraper program collect whatever data was available on the page then scroll down far enough to trigger more data to load and collect that, and rinse and repeat.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After some trial and error, I finally found a working solution with the help of a Python package named Selenium Python, and I&apos;ll share with you today how to write your own Python script to scrape data from a lazy loading website with Selenium WebDriver.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I am not normally a Python developer so my code examples may not be the most efficient or elegant Python code ever written, but they get the job done.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Selenium with Python package&lt;/h2&gt;
&lt;p&gt;There are a few different popular Python packages available for web scraping which I tried before reaching for Selenium, but I had an issue with them in that they only worked for static websites that were generated at build time, not for sites that are generated on the client-side via JavaScript, like NFTrade is.&lt;/p&gt;
&lt;p&gt;To that end, I had to do a little digging to find a package that could work with scraping sites with dynamically loaded data, and I ran across the &lt;a href=&quot;https://selenium-python.readthedocs.io/&quot;&gt;&lt;strong&gt;Selenium Python&lt;/strong&gt;&lt;/a&gt; package during my investigation.&lt;/p&gt;
&lt;p&gt;Selenium Python is a Python-based API that allows users to write scripts or automated tests using &lt;a href=&quot;https://www.selenium.dev/documentation/webdriver/&quot;&gt;Selenium WebDriver&lt;/a&gt; in an intuitive, Python-flavored way. And Selenium WebDriver is a software that can drive a browser natively, as a user would, either locally or on a remote machine. Originally created back in 2004, some version of Selenium has been around for years and is considered one of the earliest versions of automated testing that emulates user actions on a web page (commonly known today as end-to-end testing).&lt;/p&gt;
&lt;p&gt;The cool thing about WebDriver though, is that its uses span beyond automation testing, as scripts can actually be written to scrape data off of live web pages, and that&apos;s just what I ended up doing in my Python script, so let&apos;s get started.&lt;/p&gt;
&lt;h3&gt;Install Selenium Python in the Python project&lt;/h3&gt;
&lt;p&gt;As with most projects, the first thing to do is add the Selenium Python package to the Python project. The easiest way is to use &lt;a href=&quot;https://pip.pypa.io/en/latest/installation/&quot;&gt;pip&lt;/a&gt; to install the Selenium package.&lt;/p&gt;
&lt;p&gt;Assuming you have pip on your machine, at the root of your Python project folder, run the following command from a terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install selenium
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, add the &lt;code&gt;selenium&lt;/code&gt; package to your &lt;code&gt;requirements.txt&lt;/code&gt; file so anyone downloading the repo in the future can install all the necessary project dependencies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;selenium
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s all it takes to be ready to use WebDriver in your Python script. Simple enough.&lt;/p&gt;
&lt;h3&gt;Import Selenium WebDriver into Python script&lt;/h3&gt;
&lt;p&gt;After adding the Selenium Python bindings to the project, it&apos;s time to import Selenium&apos;s WebDriver and some of its helpful configuration options to the actual Python script that does the website scraping. I named my file &lt;code&gt;for_sale_scraper.py&lt;/code&gt; since I was specifically looking for NFTs that are for sale (not all of the NFTs listed on NFTrade are - some are just visible but not actually available to purchase), but you can choose any sort of file name that makes sense for you.&lt;/p&gt;
&lt;p&gt;Below are the imports I added to my file. I&apos;ll break down what each one is doing below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for_sale_scraper.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The very first import line brings in the &lt;code&gt;selenium.webdriver&lt;/code&gt; module and provides all the WebDriver implementations.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from selenium import webdriver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, as I chose to use Chrome as the browser I wanted WebDriver to interact with (Selenium supports Firefox, Chrome, Edge, and Safari browsers), I imported the &lt;code&gt;Options&lt;/code&gt; class from the &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.chrome.webdriver&quot;&gt;&lt;code&gt;selenium.webdriver.chrome.options&lt;/code&gt; module&lt;/a&gt;. This allowed me to add specific config details about how I want the Chrome browser to be set up when the Python script runs against it: things like headless mode or disable extensions, etc.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from selenium.webdriver.chrome.options import Options
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;ll cover the arguments I passed here in detail in the next section.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.wait&quot;&gt;&lt;code&gt;WebDriverWait&lt;/code&gt;&lt;/a&gt;, added in the third line of imports, is part of the special sauce that makes WebDriver a good solution for sites like NFTrade that dynamically fetch data on the client side: it allows for &lt;a href=&quot;https://selenium-python.readthedocs.io/waits.html&quot;&gt;implicit and explicit wait times&lt;/a&gt; before trying to locate an element on the page, which gives the browser time for data to come back from the server and populate in the DOM.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from selenium.webdriver.support.wait import WebDriverWait
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This type of wait is an &quot;explicit wait&quot;, meaning I manually set a period during which the code will wait before continuing to try and execute.&lt;/p&gt;
&lt;p&gt;And finally, there is the import for &lt;code&gt;By&lt;/code&gt;. &lt;code&gt;By&lt;/code&gt; is what allows me to &lt;a href=&quot;https://selenium-python.readthedocs.io/locating-elements.html&quot;&gt;locate elements&lt;/a&gt; on the page - it is immeasurably useful and powerful.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#locate-elements-by&quot;&gt;&lt;code&gt;By&lt;/code&gt;&lt;/a&gt; class accepts element IDs, names, attributes, XPaths, link text, tag names, class names, and CSS selectors just to name a few, and once again, it is a key player when it comes to scraping data off of the web page, as I&apos;ll demonstrate soon.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from selenium.webdriver.common.by import By
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right, all the Selenium WebDriver imports are now present in the Python file, time to initialize them and get to work.&lt;/p&gt;
&lt;h3&gt;Add methods to scrape data and lazy load more data&lt;/h3&gt;
&lt;p&gt;Before WebDriver can begin scraping the data from NFTrade, an instance of the browser that WebDriver will interact with must be instantiated and the proper options supplied to it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Initialize the Selenium WebDriver instance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In my attempt to try to follow good Python coding practices (again, disclaimer: I don&apos;t write Python as my primary coding language), I created a class for the the file named &lt;code&gt;class ForSaleNFTScraper&lt;/code&gt;, and created an &lt;code&gt;__init__()&lt;/code&gt; method immediately inside of it where I created the Chrome WebDriver instance that the whole script will be able reference in the remainder of its methods.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class ForSaleNFTScraper:
    def __init__(self):
        options = Options()
        options.add_argument(&apos;--headless&apos;)
        options.add_argument(&apos;--start-maximized&apos;)
        self.driver = webdriver.Chrome(options=options)
        self.wait = WebDriverWait(self.driver, 5)

# more code here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing I did inside of the &lt;code&gt;__init__()&lt;/code&gt; method was to add a couple of Chrome browser configs via the &lt;code&gt;Options&lt;/code&gt; import from the last section by declaring a new &lt;code&gt;options&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    options = Options():
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since I wanted this script to run without actually opening a browser window on the user&apos;s local machine, I added the config argument of &lt;code&gt;--headless&lt;/code&gt; and the argument of &lt;code&gt;--start-maximized&lt;/code&gt;, so the (unseen) window would take up as much screen size as was available (and hopefully load as many NFTs as quickly as possible by doing so).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    options.add_argument(&apos;--headless&apos;)
    options.add_argument(&apos;--start-maximized&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I passed the new &lt;code&gt;options&lt;/code&gt; object to the instance of &lt;code&gt;webdriver.Chrome&lt;/code&gt;, which was set to the variable of &lt;code&gt;self.driver&lt;/code&gt; (&lt;code&gt;self&lt;/code&gt; is a variable accessible throughout the rest of the methods within this &lt;code&gt;ForSaleNFTScraper&lt;/code&gt; class), and instructed the new WebDriver to wait for 5 seconds after startup (which would presumably give it time to go to the specified NFTrade web URL and load the data onto the page before attempting to scrape it).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    self.driver = webdriver.Chrome(options=options)
    self.wait = WebDriverWait(self.driver, 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&apos;s plenty happening in that first method, but it&apos;s all pretty straightforward once you go through the code line by line and understand what the arguments mean to the Chrome WebDriver instance, and why it&apos;s doing what it&apos;s doing. Now that the WebDriver instance was configured and ready to go, I could write the code fetching the NFT card data, and lazy loading more data once the end of the  currently visible info was reached.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Write the &lt;code&gt;get_cards()&lt;/code&gt; and &lt;code&gt;get_current_card_count()&lt;/code&gt; methods&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is where the code really starts to get interesting in my opinion, because it&apos;s where I learned to collect whatever data was currently visible in a (headless) browser &lt;em&gt;and then&lt;/em&gt; load more data to add to the list. Pay close attention, because this is where the lazy loading code resides that gets more and more data onto the page.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_current_card_count(self):
    &quot;&quot;&quot;Get the count of cards loaded into list of cards.&quot;&quot;&quot;
    return len(self.driver.find_elements(By.XPATH, &apos;//div[contains(@class, &quot;Item_itemContent__1XIcH&quot;)]&apos;))    

def get_cards(self, max_card_count = 500):
    &quot;&quot;&quot;Extract and returns card ID and price.&quot;&quot;&quot;
    URL=&quot;https://nftrade.com/collection/[NFT_COLLECTION_NAME]&quot;
    self.driver.get(URL)
    last_card_count = 0
    # loops through lazy loading cards on site until max_card_count number reached 
    while last_card_count &amp;lt; max_card_count:
        self.driver.execute_script(&quot;window.scrollTo(0, document.body.scrollHeight);&quot;)
        time.sleep(3)
        last_card_count = self.get_current_card_count()
    # grab all the cards now loaded into the browser by XPATH
    cards = self.driver.find_elements(By.XPATH, &apos;//div[contains(@class, &quot;Item_itemContent__1XIcH&quot;)]&apos;)
    return cards

# more code here        
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, here we go.&lt;/p&gt;
&lt;p&gt;For starters, there are two methods that I&apos;m displaying in the code snippet here. The first method, &lt;code&gt;get_current_card_count()&lt;/code&gt; is how I keep track of how many NFT cards in a collection are currently visible on the screen.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As I&apos;ve said, NFTrade lazy loads its NFT collections onto a site to make initial page load quicker, and when a user scrolls down to the end of the currently loaded batch of elements, the NFTrade page then triggers to load more cards into the DOM at that point in time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second method is &lt;code&gt;get_cards()&lt;/code&gt;, which handles going to the NFTrade collection URL and scraping all the available card data. It relies on &lt;code&gt;get_current_card_count()&lt;/code&gt; to help it know to load more NFT cards until the desired number of cards has been loaded in the browser to scrape data from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;get_cards()&lt;/code&gt; method&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ll talk about &lt;code&gt;get_cards()&lt;/code&gt; first as it&apos;s the more complicated of the two methods. The first thing the method does is declare a new variable named &lt;code&gt;URL&lt;/code&gt; - this variable is set to the URL of the NFTrade collection page I want WebDriver to navigate to and scrape the data from. I used the Selenium WebDriver &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.get&quot;&gt;&lt;code&gt;driver.get()&lt;/code&gt; method&lt;/a&gt; to navigate to the page given by the URL.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    URL=&quot;https://nftrade.com/collection/[NFT_COLLECTION_NAME]&quot;
    self.driver.get(URL)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After navigating to the proper URL, I created a variable called &lt;code&gt;last_card_count&lt;/code&gt; and set it equal to 0: this variable will be used to track how many NFTs are currently visible on the page and compare it to the &lt;code&gt;max_card_count&lt;/code&gt; variable passed to the &lt;code&gt;get_cards()&lt;/code&gt; method (if a number isn&apos;t passed for &lt;code&gt;max_card_count&lt;/code&gt; it defaults to 500).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Below is the key code to lazy loading more and more data in the browser&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Inside of &lt;code&gt;get_cards()&lt;/code&gt;, there&apos;s a &lt;code&gt;while&lt;/code&gt; loop set up to compare the &lt;code&gt;last_card_count&lt;/code&gt; and &lt;code&gt;max_card_count&lt;/code&gt; variables. As long as &lt;code&gt;last_card_count&lt;/code&gt; is less then &lt;code&gt;max_card_count&lt;/code&gt;, the loop will run, and each time it executes WebDriver uses the &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.execute_script&quot;&gt;&lt;code&gt;driver.execute_script()&lt;/code&gt; method&lt;/a&gt; to scroll down the page, wait for 3 seconds (allowing more cards to load onscreen), and then updating the &lt;code&gt;last_card_count&lt;/code&gt; variable equal to the new amount of cards on the page using the &lt;code&gt;get_current_card_count()&lt;/code&gt; method.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The &lt;code&gt;window.scrollTo()&lt;/code&gt; method is critical&lt;/p&gt;
&lt;p&gt;&lt;code&gt;driver.execute_script()&lt;/code&gt; allows for the synchronous execution of JavaScript in the current window, so when you see the code &lt;code&gt;self.driver.execute_script(&quot;window.scrollTo(0, document.body.scrollHeight);&quot;)&lt;/code&gt;, what&apos;s happening is that WebDriver is using the JavaScript &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo&quot;&gt;&lt;code&gt;window.scrollTo()&lt;/code&gt; method&lt;/a&gt; to scroll the browser all the way to the bottom of the page (that&apos;s why &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight&quot;&gt;&lt;code&gt;document.body.scrollHeight&lt;/code&gt;&lt;/a&gt; is present - it&apos;s a measurement of the height of the whole &lt;code&gt;document.body&lt;/code&gt; page element), which triggers the page to load more NFT cards into view.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    last_card_count = 0
    # loops through lazy loading cards on site until max_card_count number reached 
    while last_card_count &amp;lt; max_card_count:
        self.driver.execute_script(&quot;window.scrollTo(0, document.body.scrollHeight);&quot;)
        time.sleep(3)
        last_card_count = self.get_current_card_count()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is a perfect time to segue into discussing the &lt;code&gt;get_current_card_count()&lt;/code&gt; method, which is short and sweet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;get_current_card_count()&lt;/code&gt; method&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This method exists simply to find the count of the current elements loaded in the browser, and it does so by combining the WebDriver &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.find_elements&quot;&gt;&lt;code&gt;find_elements()&lt;/code&gt; method&lt;/a&gt; with the &lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#locate-elements-by&quot;&gt;&lt;code&gt;By.XPATH&lt;/code&gt; element locator&lt;/a&gt; method.&lt;/p&gt;
&lt;p&gt;Due to how the NFTrade site is built, there are no easily identifiable classes, IDs, or other consistent ways to identify all the cards on the page, so I had to resort to XPath expressions to identify each element and include it in my count to update the &lt;code&gt;last_card_count&lt;/code&gt; variable. I cobbled together the XPath below by using my Chrome DevTools to inspect the elements on the page and construct the XPath from there through trial and error.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; What is XPath?&lt;/p&gt;
&lt;p&gt;If you&apos;re unfamiliar like I was, &lt;a href=&quot;https://www.w3schools.com/xml/xml_xpath.asp&quot;&gt;XPath&lt;/a&gt; is a syntax that can be used to navigate through elements and attributes in a standard XML document (or webpage). The link I provided to W3Schools has some good examples of what typical XPath expressions look like and how to interpret them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the code inside of the &lt;code&gt;get_current_card_count()&lt;/code&gt; method is just the one line of code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return len(self.driver.find_elements(By.XPATH, &apos;//div[contains(@class, &quot;Item_itemContent__1XIcH&quot;)]&apos;))  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code snippet, I&apos;m getting the count (using the build-in &lt;a href=&quot;https://www.w3schools.com/python/ref_func_len.asp&quot;&gt;Python method &lt;code&gt;len()&lt;/code&gt;&lt;/a&gt;) of all the elements on the page that match the XPath of a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; containing the class of &lt;code&gt;&quot;Item_itemContent__1XIcH&quot;&lt;/code&gt;, because each NFT on the page is wrapped by that &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with that class. It&apos;s not the prettiest thing to read and understand, but it gets the job done.&lt;/p&gt;
&lt;p&gt;And finally, jumping back to the &lt;code&gt;get_cards()&lt;/code&gt; method again, once the &lt;code&gt;last_card_count&lt;/code&gt; variable has been updated and surpassed the &lt;code&gt;max_card_count&lt;/code&gt; variable (i.e. enough NFT cards are loaded into the browser), the &lt;code&gt;while&lt;/code&gt; loop ends, and all the cards on the screen are targeted (using the very same XPath used in the &lt;code&gt;get_current_card_count()&lt;/code&gt; method, I might add) and set equal to the &lt;code&gt;cards&lt;/code&gt; variable defined at the top of the &lt;code&gt;get_cards()&lt;/code&gt; method. That variable then gets returned to the &lt;code&gt;__main__&lt;/code&gt; method running the whole script, which I&apos;ll cover next.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    # grab all the cards now loaded into the browser by XPATH
    cards = self.driver.find_elements(By.XPATH, &apos;//div[contains(@class, &quot;Item_itemContent__1XIcH&quot;)]&apos;)
    return cards
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&apos;s quite a bit going on here, but hopefully it makes more sense now what these methods are doing. Time to test out this lazy loading script functionality and see how WebDriver does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Run the Python script&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;All right, now that all the code and logic to load multiple sets of NFTrade cards into the browser and collect the data has been written, it&apos;s time to run the code.&lt;/p&gt;
&lt;p&gt;To do that, I declared a &lt;code&gt;__main__&lt;/code&gt; method at the bottom of the file which can be started from the terminal with the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python for_sale_scraper.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is what &lt;code&gt;__main__&lt;/code&gt; method includes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if __name__ == &apos;__main__&apos;:
   scraper = ForSaleNFTScraper();

  # get all the cards from nftrade site
   cards = scraper.get_cards(max_card_count=200)

   # pprint the card data to ensure we&apos;re getting data
   pprint(cards)

   print(&quot;Total cards collected:&quot;, len(cards))
   # more code here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing the method does is create a new instantiation variable named &lt;code&gt;scraper&lt;/code&gt; by calling the &lt;code&gt;ForSaleNFTScraper()&lt;/code&gt; class. It then proceeds to fetch all the card data and set it equal to a variable named &lt;code&gt;cards&lt;/code&gt; by calling the method &lt;code&gt;scraper.get_cards(max_card_count=200)&lt;/code&gt; and supplying a &lt;code&gt;max_card_count&lt;/code&gt; variable of 200.&lt;/p&gt;
&lt;p&gt;After this step, as a sanity check, I used the Python &lt;a href=&quot;https://docs.python.org/3/library/pprint.html&quot;&gt;&lt;code&gt;pprint()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://www.w3schools.com/python/ref_func_print.asp&quot;&gt;&lt;code&gt;print()&lt;/code&gt;&lt;/a&gt; methods to print out all the card data and a count of the total cards fetched by the  &lt;code&gt;get_cards()&lt;/code&gt; method, and ensure all the info I needed to include in the CSV (NFT price, NFT ID, etc.) was available to me. Here&apos;s a screenshot of some of the data printed out in my console helping me know my code is doing what I expect.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-lazy-load-data/pprint-nft-cards.png&quot; alt=&quot;Example of the raw NFT data gathered from the  method&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here is what the raw NFT card data gathered from the &lt;code&gt;get_cards()&lt;/code&gt; method looks like printed in the terminal.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/python-lazy-load-data/print-nft-cards-length.png&quot; alt=&quot;Count of the amount of NFTs collected from the  method&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Since I set my &lt;code&gt;max_card_count&lt;/code&gt; to 200, but NFTrade loads NFTs in batches of 75 at a time, it makes sense that the total count of NFTs scraped off the page equals 225.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And after verifying the right data&apos;s there (and the right amount of data as well), I continued on extracting the data, calculating the current price in USD for each NFT, and assembling a CSV of all the data. But I&apos;ll save those steps for future blog posts.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building a Python-based website scraper to create a CSV of NFTs available for sale on NFTrade was a unique challenge I learned a lot of new things from.&lt;/p&gt;
&lt;p&gt;After my first attempt failed due to NFTrade dynamically lazy loading NFTs in batches of 75 onto the page as a user scrolled further down, I had to come up with a more creative solution that would allow me to trigger the site to load more cards on the page first, then grab the data on the cards for sale.&lt;/p&gt;
&lt;p&gt;I found the solution I was looking for with the help of a Python package called Selenium Python. Selenium Python is a powerful Python-based API that allows users to write scripts or automated tests leveraging Selenium WebDriver. And it was up to the task at hand: with just a few methods I was able to specify as many NFTs as I wanted loaded on the page before scraping and collecting all their data all at once.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more blogs about the problems I had to solve while building this Python website scraper in addition to other topics on JavaScript or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope seeing how to make a Python Selenium WebDriver load data onto a dynamic webpage before scraping it comes in handy for you in the future.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://selenium-python.readthedocs.io/&quot;&gt;Selenium Python&lt;/a&gt; docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.selenium.dev/documentation/webdriver/&quot;&gt;Selenium WebDriver&lt;/a&gt; docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nftrade.com/&quot;&gt;NFTrade&lt;/a&gt; website&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/xml/xml_xpath.asp&quot;&gt;XPath&lt;/a&gt; documentation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo&quot;&gt;JavaScript window.scrollTo() method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight&quot;&gt;JavaScript document.body.scrollHeight&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>python</category><category>selenium</category><category>big data</category><category>webdriver</category><category>web scraping</category></item><item><title>Copy Files from One Repo to Another Automatically with GitHub Actions</title><link>https://www.paigeniedringhaus.com/blog/copy-files-from-one-repo-to-another-automatically-with-github-actions/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/copy-files-from-one-repo-to-another-automatically-with-github-actions/</guid><description>Even add a newly copied file to a feature branch for easier pull request reviews.</description><pubDate>Sun, 13 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-copy-files/assembly-line-hero.png&quot; alt=&quot;Assembly line making identical pink shoes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Welcome to the third (and final) installment in my &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;series&lt;/a&gt; about the many things I learned while building my first open source API library for &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;Blues&lt;/a&gt;, the Internet of Things startup I work for.&lt;/p&gt;
&lt;p&gt;It was a good challenge and a great learning opportunity for me.&lt;/p&gt;
&lt;p&gt;I automated as many pieces of the library&apos;s maintenance and deployment to as I could with the help of GitHub Actions workflows, one of them being: copy the &lt;code&gt;openapi.yaml&lt;/code&gt; file from the Blues cloud repo, &lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;Notehub&lt;/a&gt;, whenever that file was updated, and push it into a feature branch in the &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS repo&lt;/a&gt; (the name of the API library).&lt;/p&gt;
&lt;p&gt;Interacting with two different repos in one workflow might sound tricky, and at first it was, but it &lt;em&gt;is&lt;/em&gt; possible and not too bad once you see how it can be done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this tutorial, I&apos;ll demonstrate how to create a GitHub Actions workflow that automatically copies a file from one repo to another and pushes the changes to another repo inside a feature branch.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I know the use case sounds a bit specific, but it came in really handy for me, and you never know when it might for you too.&lt;/p&gt;
&lt;h2&gt;Notehub JS&lt;/h2&gt;
&lt;p&gt;Before we get to the actual GitHub Actions workflows, I&apos;ll give you a little background on the &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;&lt;strong&gt;Notehub JS&lt;/strong&gt;&lt;/a&gt; project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This section outlines the folder structure for the repo in case you want to explore it in GitHub, if you just want to get to the solutions, feel free to jump down to the next section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Notehub JS is a JavaScript-based library for interacting with the native &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/api-introduction/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;&lt;strong&gt;Notehub API&lt;/strong&gt;&lt;/a&gt;, and it is actually generated from the Notehub project&apos;s own &lt;code&gt;openapi.yaml&lt;/code&gt; file, which follows the &lt;a href=&quot;https://swagger.io/specification/&quot;&gt;OpenAPI specification&lt;/a&gt; standards.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://openapi-generator.tech/docs/installation&quot;&gt;OpenAPI Generator CLI&lt;/a&gt; is a tool that uses the &lt;code&gt;openapi.yaml&lt;/code&gt; file to create an entire API library complete with documentation, models, endpoints, and scripts to package it up for publishing as an npm module. The end library that is published to npm is a &lt;em&gt;subfolder&lt;/em&gt; inside of the main Notehub JS repo. At the root of the project are the &lt;code&gt;openapi.yaml&lt;/code&gt; file, the GitHub Actions workflows, and a few other config files.&lt;/p&gt;
&lt;p&gt;Here&apos;s a simplified view of the &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS repo&apos;s&lt;/a&gt; folder structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root/
├── .github/ 
| ├── workflows/
| | ├── create-pr.yml 
| ├── PULL_REQUEST_TEMPLATE.md
├── src/ &amp;lt;- this is the folder generated by the OpenAPI Generator CLI
| ├── dist/
| ├── docs/
| ├── src/ 
| | ├── api/ 
| | ├── model/
| | ├── index.js 
| openapi.yaml
| config.json
| package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Based on the diagram above, the &lt;code&gt;openapi.yaml&lt;/code&gt; file that the library is generated from lives at the root of the repo, and the &lt;code&gt;src/&lt;/code&gt; folder is what holds all the Notehub API JavaScript code that powers the &lt;a href=&quot;https://www.npmjs.com/package/@blues-inc/notehub-js&quot;&gt;Notehub JS library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;openapi.yaml&lt;/code&gt; file gets copied from the Notehub repo when changes are made to it. And changes are made to that file whenever the Notehub API is updated with new features and functionality, so making sure that the Notehub JS library keeps up with the new additions to the original API it&apos;s based on is important.&lt;/p&gt;
&lt;p&gt;Now that I&apos;ve explained more about the Notehub JS repo and why keeping it in sync with the Notehub API is important (and depends on the &lt;code&gt;openapi.yaml&lt;/code&gt; file), we can get down to the business of ensuring the file gets copied to this repo whenever it&apos;s updated.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Looking for more details about Notehub JS?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Check out my &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;first blog post&lt;/a&gt; about how to use GitHub Actions to automatically publish new releases to npm - I do a fairly deep dive on Notehub JS there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Create a GitHub Actions workflow to run when the &lt;code&gt;openapi.yaml&lt;/code&gt; file is updated&lt;/h3&gt;
&lt;p&gt;First things first: creating a new GitHub Actions workflow that&apos;s triggered when the &lt;code&gt;openapi.yaml&lt;/code&gt; file changes in the Notehub repo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Need a refresher on GitHub Actions?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want a quick primer on what GitHub Actions are, I recommend you check out a previous article I wrote about them &lt;a href=&quot;./use-secret-environment-variables-in-git-hub-actions#what-is-github-actions&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Below is the final version of the &lt;code&gt;copy-openapi-file.yml&lt;/code&gt; file, which lives inside of the &lt;code&gt;./github/workflows/&lt;/code&gt; folder. I&apos;ll walk through each step of the script below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.github/workflows/copy-openapi-file.yml&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Copy updated OpenAPI file

# only run this workflow when the openapi file has changed on the master branch
on: 
  push:
    branches: 
      - master
    paths:
      - &apos;notehub/api/openapi.yaml&apos;

jobs:
  copy_openapi_file_to_notehub_js: 
    runs-on: ubuntu-latest
    steps:
    # check out notehub project
    - name: Check out Notehub project
      uses: actions/checkout@v3
    # check out notehub-js project using token generated in that project to successfully access it from inside the Notehub GitHub Action workflow
    - name: Check out Notehub JS project
      uses: actions/checkout@v3
      with:
        repository: blues/notehub-js
        path: ./notehub-js
        token: ${{ secrets.NOTEHUB_JS_TOKEN }}
    # make a copy the openapi file from notehub project
    - name: Copy OpenAPI file
      run: bash ./.github/scripts/copy-openapi-file.sh
      env:
        DESTINATION_PATH: ./notehub-js/
    # make a branch in notehub-js repo and push the copy of the openapi file there
    - name: Push to notehub-js repo
      run: bash ./.github/scripts/push-openapi-to-notehub-js.sh
      env:
        BRANCH: feat-openapi-update
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each GitHub Actions workflow needs a &lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt;, and I try to choose descriptive ones like this one: &lt;code&gt;Copy updated OpenAPI file&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, I want this workflow to only run when the &lt;code&gt;openapi.yaml&lt;/code&gt; file in the &lt;code&gt;master&lt;/code&gt; branch of the project is changed. &lt;code&gt;master&lt;/code&gt; is the branch that gets deployed to production, and in my case it&apos;s a safe assumption that when there&apos;s a change to this file in &lt;code&gt;master&lt;/code&gt;, those changes are going to prod, which is when I want to copy the file over to the Notehub JS repo so it can reflect those same changes.&lt;/p&gt;
&lt;p&gt;The code snippet below does just that.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;on: 
  push:
    branches: 
      - master
    paths:
      - &apos;notehub/api/openapi.yaml&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on&quot;&gt;&lt;strong&gt;&lt;code&gt;on&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is how a workflow is triggered.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushbranchestagsbranches-ignoretags-ignore&quot;&gt;&lt;strong&gt;&lt;code&gt;push&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is the event that triggers the workflow.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-including-branches-and-tags&quot;&gt;&lt;strong&gt;&lt;code&gt;branches&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; defines which branch names this workflow should run for.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-including-paths&quot;&gt;&lt;strong&gt;&lt;code&gt;paths&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is another filter to even more finely determine when the workflow runs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What it boils down to is: when there&apos;s a change to the &lt;code&gt;master&lt;/code&gt; branch in the repo for the &lt;code&gt;openapi.yaml&lt;/code&gt; file at this particular file path, run the GitHub Actions workflow.&lt;/p&gt;
&lt;p&gt;From there, the &lt;code&gt;copy_openapi_file_to_notehub_js&lt;/code&gt; job runs. There&apos;s only one job in the &lt;strong&gt;&lt;code&gt;jobs&lt;/code&gt;&lt;/strong&gt; section of this script, but if there were multiple jobs, they&apos;ll run sequentially.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;create_pr_repo_sync&lt;/code&gt; job defines that it runs on the latest version of Ubuntu in &lt;strong&gt;&lt;code&gt;runs-on&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;And finally, I get to the &lt;strong&gt;&lt;code&gt;steps&lt;/code&gt;&lt;/strong&gt; section. Here&apos;s how it goes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check out the Notehub code so the workflow can access it using the GitHub Action &lt;a href=&quot;https://github.com/actions/checkout&quot;&gt;&lt;code&gt;actions/checkout@v3&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Check out the Notehub JS code so the workflow can access it as well using the GitHub Action &lt;a href=&quot;https://github.com/actions/checkout&quot;&gt;&lt;code&gt;actions/checkout@v3&lt;/code&gt;&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Notice that in this second checkout action I had to include a &lt;a href=&quot;https://github.com/actions/checkout#checkout-multiple-repos-side-by-side&quot;&gt;&lt;code&gt;with&lt;/code&gt;&lt;/a&gt; parameter that allows me to specify another repo to check out by providing a &lt;code&gt;repository&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, and &lt;code&gt;token&lt;/code&gt;. The &lt;code&gt;token&lt;/code&gt; is a GitHub &lt;a href=&quot;https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens&quot;&gt;Personal Access Token (PAT)&lt;/a&gt; required when checking out other libraries beyond the current one the workflow is operating within.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Run a shell script named &lt;code&gt;copy-openapi-file.sh&lt;/code&gt; with the &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/variables#defining-environment-variables-for-a-single-workflow&quot;&gt;GitHub Actions environment variable&lt;/a&gt; &lt;code&gt;DESTINATION_PATH&lt;/code&gt; passed to the script.&lt;/li&gt;
&lt;li&gt;Run another shell script named &lt;code&gt;push-openapi-to-notehub-js.sh&lt;/code&gt; with the &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/variables#defining-environment-variables-for-a-single-workflow&quot;&gt;GitHub Actions environment variable&lt;/a&gt; &lt;code&gt;BRANCH&lt;/code&gt; passed to the script.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the following sections I&apos;ll go through what those two shell scripts do in detail.&lt;/p&gt;
&lt;p&gt;Ok, so the workflow file is done. Time to get into the details of the two scripts doing the heavy lifting.&lt;/p&gt;
&lt;h3&gt;Write one shell script to copy the &lt;code&gt;openapi.yaml&lt;/code&gt; file to the Notehub JS repo&lt;/h3&gt;
&lt;p&gt;Premade GitHub Actions can do many things, but something as specific as copying a file from one repo to another is a bit beyond them.&lt;/p&gt;
&lt;p&gt;Luckily, GitHub Action workflows can &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/essential-features-of-github-actions#adding-scripts-to-your-workflow&quot;&gt;run shell scripts&lt;/a&gt;, so if you can use a scripting language like PowerShell or Bash, you&apos;re in luck.&lt;/p&gt;
&lt;p&gt;Here is the Bash script I wrote to copy the file from the Notehub repo to the Notehub JS repo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;copy_openapi_file.sh&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/env bash
# bash boilerplate
set -euo pipefail # strict mode
readonly SCRIPT_NAME=&quot;$(basename &quot;$0&quot;)&quot;
readonly SCRIPT_DIR=&quot;$( cd &quot;$( dirname &quot;${BASH_SOURCE[0]}&quot; )&quot; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&amp;amp; pwd )&quot;
function l { # Log a message to the terminal.
    echo
    echo -e &quot;[$SCRIPT_NAME] ${1:-}&quot;
}

# File to copy from Notehub
OPENAPI_FILE=./notehub/api/openapi.yaml

# if the file exists in Notehub, copy it to Notehub-JS repo
if [ -f &quot;$OPENAPI_FILE&quot; ]; then
    echo &quot;Copying $OPENAPI_FILE&quot;
    cp -R ./notehub/api/openapi.yaml $DESTINATION_PATH
fi

echo &quot;OpenAPI file copied to $DESTINATION_PATH&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The 9 lines at the top of the file are Bash script set up, so don&apos;t worry too much about what&apos;s happening there.&lt;/p&gt;
&lt;p&gt;The first line to pay attention to is where the &lt;code&gt;OPENAPI_FILE&lt;/code&gt; variable is defined with a path to the &lt;code&gt;openapi.yaml&lt;/code&gt; file in the Notehub repo.&lt;/p&gt;
&lt;p&gt;After identifying the file to copy from the Notehub repo, a standard &lt;a href=&quot;https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html&quot;&gt;Bash &lt;code&gt;if&lt;/code&gt; statement&lt;/a&gt; checks if the file exists in the Notehub repo (just to be safe), and if it does, it copies the file recursively using &lt;code&gt;cp -R&lt;/code&gt; to the &lt;code&gt;$DESTINATION_PATH&lt;/code&gt; variable that was provided by the GitHub Actions environment variable.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this case, the &lt;code&gt;$DESTINATION_PATH&lt;/code&gt; is pointing to the root folder of the Notehub JS project where the file should be copied to, but you could specify it copy the file anywhere within the receiving repo that makes sense.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;During the copying process and when the script finishes copying the file I added a few &lt;a href=&quot;https://ss64.com/bash/echo.html&quot;&gt;&lt;code&gt;echo&lt;/code&gt; commands&lt;/a&gt; to print out useful messages in the logs to let me know things are going to plan.&lt;/p&gt;
&lt;p&gt;And that&apos;s the first shell script that actually copies the file that will be taken from one repo to the other. I hope it&apos;s not too complicated once the actions in the script are broken down.&lt;/p&gt;
&lt;p&gt;Now, it&apos;s time to add that file to the Notehub JS repo.&lt;/p&gt;
&lt;h3&gt;Use a second shell script to push the copied file to a feature branch in the other repo&lt;/h3&gt;
&lt;p&gt;When I checked the &lt;a href=&quot;https://github.com/marketplace&quot;&gt;GitHub Marketplace&lt;/a&gt; for a ready-made action to create a new feature branch in the repo receiving the copied file, there were a few to choose from, but I wanted more control over what was happening than they offered.&lt;/p&gt;
&lt;p&gt;I wanted an action that would:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new branch in the Notehub JS receiving repo if it didn&apos;t exist, add the copied file, and then push that branch to GitHub.&lt;/li&gt;
&lt;li&gt;Check out the already existing branch in the Notehub JS repo, overwrite any previous file changes in the branch, and then push the new file changes in that branch back to GitHub.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&apos;s the bash script that I came up with to handle those two scenarios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;push-openapi-to-notehub-js.sh&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/env bash
# bash boilerplate
readonly SCRIPT_NAME=&quot;$(basename &quot;$0&quot;)&quot;
readonly SCRIPT_DIR=&quot;$( cd &quot;$( dirname &quot;${BASH_SOURCE[0]}&quot; )&quot; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&amp;amp; pwd )&quot;
function l { # Log a message to the terminal.
    echo
    echo -e &quot;[$SCRIPT_NAME] ${1:-}&quot;
}

# move to the root the notehub-js repo
cd &quot;./notehub-js&quot;
echo &quot;Open root of Notehub JS repo&quot;

# check if there&apos;s already a currently existing feature branch in notehub-js for this branch
# i.e. the altered openapi.yaml file&apos;s already been copied there at least once before
echo &quot;Check if feature branch $BRANCH already exists in Notehub JS&quot;
git ls-remote --exit-code --heads origin $BRANCH &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
EXIT_CODE=$?
echo &quot;EXIT CODE $EXIT_CODE&quot;

if [[ $EXIT_CODE == &quot;0&quot; ]]; then
  echo &quot;Git branch &apos;$BRANCH&apos; exists in the remote repository&quot;
  # fetch branches from notehub-js
  git fetch
  # stash currently copied openapi.yaml
  git stash
  # check out existing branch from notehub-js
  git checkout $BRANCH 
  # overwrite any previous openapi.yaml changes with current ones
  git checkout stash -- .
else
  echo &quot;Git branch &apos;$BRANCH&apos; does not exist in the remote repository&quot;
  # create a new branch in notehub-js 
  git checkout -b $BRANCH
fi

git add -A .
git config user.name github-actions
git config user.email github-actions@github.com
git commit -am &quot;feat: Update OpenAPI file replicated from Notehub&quot;
git push --set-upstream origin $BRANCH

echo &quot;Updated OpenAPI file successfully pushed to notehub-js repo&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once more, the first 9 lines of code are boilerplate for Bash; no comments necessary.&lt;/p&gt;
&lt;p&gt;The first thing this script does is situate itself in the root of the Notehub JS folder just as you would when navigating around a computer via the command line: &lt;code&gt;cd &quot;./notehub-js&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once there, it checks if the feature branch environment variable passed in by the GitHub Action &lt;code&gt;$BRANCH&lt;/code&gt; already exists in the Notehub JS repo with this one-liner.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git ls-remote --exit-code --heads origin $BRANCH &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Essentially, this code is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Getting a list of references in the remote repository with &lt;code&gt;git ls-remote&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Checking if env var &lt;code&gt;$BRANCH&lt;/code&gt; (passed from the GitHub Action) exists &lt;em&gt;only&lt;/em&gt; in the &lt;code&gt;refs/heads&lt;/code&gt; of the origin remote with &lt;code&gt;--heads&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;(i.e. does the branch name already exist in the GitHub repo where it keeps track of the names of all of its branches),&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;And returning an &lt;code&gt;--exit-code&lt;/code&gt; with status &lt;code&gt;&quot;2&quot;&lt;/code&gt; when no matching refs are found in the remote repo and a status of &lt;code&gt;&quot;0&quot;&lt;/code&gt; if a matching ref is found.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the exit code is returned, it&apos;s set equal to the variable &lt;code&gt;$EXIT_CODE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, an &lt;code&gt;if/else&lt;/code&gt; statement checks what &lt;code&gt;$EXIT_CODE&lt;/code&gt; equals.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EXIT_CODE = &quot;0&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the exit code is &lt;code&gt;0&lt;/code&gt;, that means the branch already exists in the repository; this could happen if multiple changes are made to the &lt;code&gt;openapi.yaml&lt;/code&gt; file before the feature branch in Notehub JS gets merged in and deleted.&lt;/p&gt;
&lt;p&gt;When that happens the following steps take place:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The branches for the Notehub JS repo are fetched via &lt;code&gt;git fetch&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;The current changes (the freshly copied &lt;code&gt;openapi.yaml&lt;/code&gt; file) are stashed with &lt;code&gt;git stash&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;The existing branch of the same name as the &lt;code&gt;$BRANCH&lt;/code&gt; env var is checked out locally,&lt;/li&gt;
&lt;li&gt;The stashed changes are applied to that branch overwriting whatever was there before with &lt;code&gt;git checkout stash -- .&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;EXIT_CODE = &quot;2&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;$EXIT_CODE&lt;/code&gt; is equal to &lt;code&gt;2&lt;/code&gt;, that means the branch doesn&apos;t already exist remotely in GitHub and the script can simply checkout a new branch with the name in &lt;code&gt;$BRANCH&lt;/code&gt; via &lt;code&gt;git checkout -b $BRANCH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, after all this is completed, a standard set of git commands follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;git-add -A .&lt;/code&gt; to stage all changes in the working directory,&lt;/li&gt;
&lt;li&gt;Configure a username and email address for who&apos;s doing the commit with &lt;code&gt;git config user.name&lt;/code&gt; and &lt;code&gt;git config user.email&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Add a commit message with &lt;code&gt;git commit -am &quot;Standard commit message here&quot;&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Lastly, push it to GitHub with &lt;code&gt;git push --set-upstream origin $BRANCH&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point, you should be good to go. The file should be successfully copied over to the other repository.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Inspiration for this second Bash script was initially based on this &lt;a href=&quot;https://remarkablemark.org/blog/2022/09/25/check-git-branch-exists-in-remote-repository/&quot;&gt;blog post&lt;/a&gt; by Remarkable Mark.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Check that the workflow runs&lt;/h3&gt;
&lt;p&gt;The simplest way to test this new functionality is just to keep an eye out for changes in the main branch of the repo that would trigger the workflow to run and see if it works.&lt;/p&gt;
&lt;p&gt;When you name the workflow a descriptive name, it&apos;s easy to find it amongst the various GitHub Action workflows the repo may have.&lt;/p&gt;
&lt;p&gt;Here&apos;s a screenshot of the workflow runs of the &lt;code&gt;Copy updated OpenAPI file&lt;/code&gt; job inside the GitHub repo&apos;s &lt;strong&gt;Actions&lt;/strong&gt; page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-copy-files/gh-actions-workflow.png&quot; alt=&quot;Multiple runs of a particular workflow in the GitHub Actions page of a repository&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And if you want to dig in further to any of the runs to check the logs and job steps (especially handy for debugging purposes), just click on a workflow run, then the name of the job, and inside the job you can expand out each step.&lt;/p&gt;
&lt;p&gt;Here&apos;s another screenshot of the &lt;code&gt;Push to notehub-js repo&lt;/code&gt; step expanded to see exactly what the Bash script in that step is logging to the console via &lt;code&gt;echo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-copy-files/gh-actions-job-details.png&quot; alt=&quot;Details of a particular step inside of a GitHub Actions job expanded for review&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And you&apos;re done! The workflow&apos;s running, the steps are successfully completing, and, most importantly, the file from the Notehub repo is successfully copied to the Notehub JS repo. Mission accomplished.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;My first foray into building an open source software library on behalf of one of my company&apos;s APIs was a unique challenge that taught me a lot. Especially as I got to leverage GitHub Action workflows to automate as many parts of the process as I could to make ongoing maintenance and upkeep easier.&lt;/p&gt;
&lt;p&gt;One such task that I automated involved copying a file from one repo into another whenever a change was made to that particular file. And while I was able to leverage a few pre-existing GitHub Actions, I also had to write a couple custom Bash scripts for some of the trickier, more-unique-to-my-use-case steps.&lt;/p&gt;
&lt;p&gt;Fortunately, GitHub Action workflows allows for both types of steps to be combined in a workflow, making for some very powerful, turnkey solutions that did just what I needed.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning to copy a file from one repo to another automatically with GitHub Actions workflows is as helpful for you as it has been for me. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Previous OSS article &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;using GH Actions to publish a package to npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Previous OSS article &lt;a href=&quot;./automatically-create-a-pull-request-against-a-feature-branch-with-git-hub-actions&quot;&gt;using GH Actions to create a new PR branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS&lt;/a&gt; GitHub repo&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>github</category><category>git</category><category>bash</category><category>devops</category></item><item><title>Automatically Create a Pull Request Against a Feature Branch with GitHub Actions</title><link>https://www.paigeniedringhaus.com/blog/automatically-create-a-pull-request-against-a-feature-branch-with-github-actions/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/automatically-create-a-pull-request-against-a-feature-branch-with-github-actions/</guid><description>Keep up with code reviews programmatically using workflows.</description><pubDate>Sun, 11 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-pr/typewriter-hero.jpg&quot; alt=&quot;Old school typewriter&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This blog post is the second in a &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;short series&lt;/a&gt; I&apos;m writing about the many things I learned in the course of building my first open source API library for the IoT startup I work for, &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;Blues&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was a great learning experience for me and a new, unique challenge because I needed to do the following things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make a copy of the &lt;code&gt;openapi.yaml&lt;/code&gt; file from the Blues cloud&apos;s repository, &lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;Notehub&lt;/a&gt;, whenever the file was updated.&lt;/li&gt;
&lt;li&gt;Open a new pull request against the &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS repo&lt;/a&gt; with the copy of the &lt;code&gt;openapi.yaml&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Generate a fresh version of the Notehub JS API library based on the that file via the &lt;a href=&quot;https://openapi-generator.tech/docs/installation&quot;&gt;OpenAPI Generator CLI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;And publish the updated Notehub JS library to &lt;a href=&quot;https://www.npmjs.com/package/@blues-inc/notehub-js&quot;&gt;npm&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I wanted to automate as many of these steps as possible through the use of GitHub Actions workflows.&lt;/p&gt;
&lt;p&gt;Since I didn&apos;t know how often the Notehub&apos;s &lt;code&gt;openapi.yaml&lt;/code&gt; file would be updated, I needed a way to notify myself when a new version of the Notehub&apos;s API file needed review in the Notehub JS repository. The best solution I could think of was to open a new pull request in the Notehub JS repo after copying the updated &lt;code&gt;openapi.yaml&lt;/code&gt; file into a feature branch and tagging myself to review it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll walk through how to use a GitHub Actions workflow to create (or update) a pull request whenever a new feature branch is made in that repository.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Notehub JS&lt;/h2&gt;
&lt;p&gt;Before we get to the actual GitHub Actions workflow, let me give you just a little background on the &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;&lt;strong&gt;Notehub JS&lt;/strong&gt;&lt;/a&gt; project because it&apos;s a bit different than most.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This section helps explain the folder structure for the repo in case you want to explore it in GitHub, if you just want the solutions, feel free to jump down to the next section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Notehub JS is a JavaScript-based library for interacting with the native &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/api-introduction/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;&lt;strong&gt;Notehub API&lt;/strong&gt;&lt;/a&gt;, and it&apos;s generated from the Notehub project&apos;s own &lt;code&gt;openapi.yaml&lt;/code&gt; file, which follows the &lt;a href=&quot;https://swagger.io/specification/&quot;&gt;OpenAPI specification&lt;/a&gt; standards.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;(https://openapi-generator.tech/docs/installation)&quot;&gt;OpenAPI Generator CLI&lt;/a&gt; is a tool that can use the &lt;code&gt;openapi.yaml&lt;/code&gt; file to create an entire library complete with documentation, models, endpoints, and scripts to package it up for publishing as an npm module. The end library that I care about publishing to npm is a &lt;em&gt;subfolder&lt;/em&gt; inside of the main Notehub JS repo. At the root of the project are the &lt;code&gt;openapi.yaml&lt;/code&gt; file, the GitHub Actions workflows, and a few other config files.&lt;/p&gt;
&lt;p&gt;Here&apos;s a simplified view of the &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS repo&lt;/a&gt;&apos;s folder structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root/
├── .github/ 
| ├── workflows/
| | ├── create-pr.yml 
| ├── PULL_REQUEST_TEMPLATE.md
├── src/ &amp;lt;- this is the folder generated by the OpenAPI Generator CLI
| ├── dist/
| ├── docs/
| ├── src/ 
| | ├── api/ 
| | ├── model/
| | ├── index.js 
| openapi.yaml
| config.json
| package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see in the diagram above, the &lt;code&gt;openapi.yaml&lt;/code&gt; file that this library is generated from lives at the root of the repo, and the &lt;code&gt;src/&lt;/code&gt; folder is what actually holds all the Notehub API JavaScript code that powers the &lt;a href=&quot;https://www.npmjs.com/package/@blues-inc/notehub-js&quot;&gt;Notehub JS library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;openapi.yaml&lt;/code&gt; file is what gets copied from the Notehub repo when changes are made to it. And changes are made to the file whenever the Notehub API is updated with new features and functionality, so making sure that the Notehub JS library keeps up with the new additions to the API it&apos;s based on is important.&lt;/p&gt;
&lt;p&gt;Now that I&apos;ve explained a bit more about the Notehub JS repo and why keeping it in sync with the Notehub API is important, we can get down to the business of automating PRs for this repo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Looking for more details about Notehub JS?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Check out my &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;previous blog post&lt;/a&gt; about how to use GitHub Actions to automatically publish new releases to npm - I do a fairly deep dive on Notehub JS there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Create a standard PR template for the repo&lt;/h3&gt;
&lt;p&gt;When I was just a few years into my own web development career, I was introduced to &lt;a href=&quot;https://betterprogramming.pub/github-templates-the-smarter-way-to-formalize-pull-requests-among-development-teams-89f8d6a204f&quot;&gt;GitHub PR templates&lt;/a&gt;, an easier way to keep pull requests uniform for a repository worked on by multiple developers. It made the task of creating decent PRs so much better.&lt;/p&gt;
&lt;p&gt;There is not a team or repo I join now without adding a &lt;code&gt;./github/&lt;/code&gt; directory folder and  &lt;code&gt;PULL_REQUEST_TEMPLATE.md&lt;/code&gt; file if it doesn&apos;t already exist.&lt;/p&gt;
&lt;p&gt;For the Notehub JS repo, as it&apos;s mostly autogenerated, I included a couple of sections to fill in: &lt;code&gt;Problem Context&lt;/code&gt;: a brief description of the updates in the PR, and &lt;code&gt;Changes&lt;/code&gt;: what code changes were actually made in the PR. Simple enough for any dev to fill out.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/.github/PULL_REQUEST_TEMPLATE.md&quot;&gt;&lt;strong&gt;&lt;code&gt;PULL_REQUEST_TEMPLATE.md&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Problem Context

## Changes

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s all I wanted to add to the repo before focusing on the GitHub Actions workflow itself. We&apos;ll get to it next.&lt;/p&gt;
&lt;h3&gt;Set up a GitHub Actions workflow to automatically create pull requests&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Need a refresher on GitHub Actions?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want a quick primer on what GitHub Actions are, I recommend you check out a previous article I wrote about them &lt;a href=&quot;./use-secret-environment-variables-in-git-hub-actions#what-is-github-actions&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For this particular workflow, I was able to string together a few premade &lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt; to do just what I needed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new pull request whenever a new feature branch was pushed to the GitHub repository.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;PULL_REQUEST_TEMPLATE.md&lt;/code&gt; file to format the PR.&lt;/li&gt;
&lt;li&gt;Notify me when a PR is there for review.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&apos;s what the final &lt;code&gt;create-pr.yml&lt;/code&gt; file looks like inside of the &lt;code&gt;./github/workflows/&lt;/code&gt; directory. I&apos;ll dissect it below.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/.github/workflows/create-pr.yml&quot;&gt;&lt;strong&gt;&lt;code&gt;create-pr.yml&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Automatically create / update pull request

# run this workflow only on new feature branches, not when they&apos;re merged to main
on:
  push:
    branches-ignore:
      - &quot;main&quot;

jobs:
  create_pr_repo_sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Create pull request
        id: open-pr
        uses: repo-sync/pull-request@v2
        with:
          destination_branch: &quot;main&quot;
          pr_title: &quot;feat: PLACEHOLDER TITLE&quot;
          pr_template: &quot;.github/PULL_REQUEST_TEMPLATE.md&quot;
          pr_reviewer: &quot;paigen11&quot;
          pr_draft: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each workflow file needs a &lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt;, so I chose to name this one: &lt;code&gt;Automatically create / update pull request&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This workflow should be triggered whenever a new branch is pushed to the repo &lt;em&gt;but&lt;/em&gt; it should ignore the &lt;code&gt;&quot;main&quot;&lt;/code&gt; branch. &lt;code&gt;&quot;main&quot;&lt;/code&gt; is the main branch of this repo that gets published to npm and doesn&apos;t need a PR to be created for it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;on:
  push:
    branches-ignore:
      - &quot;main&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on&quot;&gt;&lt;strong&gt;&lt;code&gt;on&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is how a workflow is triggered.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushbranchestagsbranches-ignoretags-ignore&quot;&gt;&lt;strong&gt;&lt;code&gt;push&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is the event that triggers the workflow.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-excluding-branches-and-tags&quot;&gt;&lt;strong&gt;&lt;code&gt;branches-ignore&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is how to exclude the workflow from running on certain branch patterns. This gives us more fine-grained control of when the workflow should run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then the &lt;strong&gt;&lt;code&gt;jobs&lt;/code&gt;&lt;/strong&gt; section runs inside of the workflow. This particular script only has one job, &lt;code&gt;create_pr_repo_sync&lt;/code&gt;, but if there&apos;s multiple jobs, they&apos;ll run sequentially unless otherwise specified.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;create_pr_repo_sync&lt;/code&gt; job defines that it runs on the latest version of Ubuntu in &lt;strong&gt;&lt;code&gt;runs-on&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Finally, I get to the &lt;strong&gt;&lt;code&gt;steps&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The steps are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check out the code so the workflow can access it using the GitHub Action &lt;a href=&quot;https://github.com/actions/checkout&quot;&gt;&lt;code&gt;actions/checkout@v3&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a pull request using the GitHub Action &lt;a href=&quot;https://github.com/repo-sync/pull-request&quot;&gt;&lt;code&gt;repo-sync/pull-request@v2&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pass the PR action a custom &lt;code&gt;pr_title&lt;/code&gt;, &lt;code&gt;pr_template&lt;/code&gt;, and &lt;code&gt;pr_reviewer&lt;/code&gt;. Set it to be created as a &lt;code&gt;pr_draft&lt;/code&gt; (I like PRs to be drafts until I&apos;ve looked them over and know they&apos;re ready for review), and open the PR branch against the &lt;code&gt;destination_branch: &quot;main&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the &lt;code&gt;pr_template&lt;/code&gt; section, I pass the path to the PR template file I made in the previous section, and for the &lt;code&gt;pr_reviewer&lt;/code&gt; I add my own GitHub username so that I get an email notification when the new PR is created in GitHub.&lt;/p&gt;
&lt;h3&gt;Test out the workflow&lt;/h3&gt;
&lt;p&gt;If you want to test this functionality out, create a new local branch of the repo, make a change in the branch, and push it to GitHub. When that new branch registers, the GitHub Actions workflow will be triggered to run.&lt;/p&gt;
&lt;p&gt;If you visit the &lt;strong&gt;Actions&lt;/strong&gt; page in the GitHub repo, you should see the &quot;Automatically create / update pull request&quot; job running.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-pr/gh-action-workflow.png&quot; alt=&quot;GitHub Actions workflow running in Notehub JS repo&apos;s Actions tab&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And after the action finishes running, there should be an email sent to the folks tagged as the PR reviewers in the GitHub Action (me, in this case).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-pr/gh_action_email.png&quot; alt=&quot;Notification email from GitHub to review the newly created PR&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And with that, the workflow working has been confirmed, and the reviewers know it&apos;s time to take action in that repo.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When I built my first open source software library, I learned a lot. My software is a JavaScript library based on my company&apos;s API, Notehub, so every time the Notehub API gets updated, the JS library based off of it, needs to be updated too.&lt;/p&gt;
&lt;p&gt;I needed a programmatic way to let myself know whenever new changes were made to the JS repo that needed to be reviewed.&lt;/p&gt;
&lt;p&gt;The easiest way I could think to accomplish this was by automating the pull request creation so that when a new feature branch was pushed to the repo, it opened a PR and tagged myself as the reviewer.&lt;/p&gt;
&lt;p&gt;Luckily, a GitHub Action existed for just such a scenario, allowing for designating a PR template, a PR reviewer, giving the PR a placeholder title, and a whole host of other configurations. The workflow made it quite straightforward, and gave me the peace of mind that whenever changes are made that I need to review, I get an email to look at what&apos;s changed.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about the useful things I learned while building this project in addition to other topics on JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning to use GitHub Actions workflows to automate a new PR when a feature branch is pushed to a repository proves useful. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Previous OSS article &lt;a href=&quot;./use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library&quot;&gt;using GH Actions to publish a package to npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS&lt;/a&gt; GitHub repo&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository&quot;&gt;GitHub PR templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/repo-sync/pull-request&quot;&gt;Pull request&lt;/a&gt; GitHub Action&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>github</category><category>git</category><category>npm</category><category>devops</category></item><item><title>Use GitHub Actions to Automatically Publish a Repo Subfolder as an npm Library</title><link>https://www.paigeniedringhaus.com/blog/use-github-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/use-github-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library/</guid><description>Publish a project subfolder to npm with just a package.json and a GitHub Actions workflow.</description><pubDate>Wed, 12 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-npm/workflow-hero.jpg&quot; alt=&quot;Person diagramming out a website workflow&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I&apos;ve said it before, and I&apos;ll say it again, working as a software engineer for a startup is fun and challenging because of the sheer number of different things I get to do on a regular basis.&lt;/p&gt;
&lt;p&gt;I work for an Internet of Things startup called &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;Blues&lt;/a&gt; which specializes in getting IoT data from devices in the real world into the cloud via cellular. To help show our customers all the possibilities of what they can do with our hardware (Notecards) and our cloud (Notehub), a group of my coworkers and I have been building &lt;a href=&quot;https://dev.blues.io/accelerators/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;lots of JavaScript-based web apps&lt;/a&gt; to monitor and display IoT data for a variety of different use cases.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A little more about Notecards and Notehub.io&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blues.io/products/notecard/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;&lt;strong&gt;Notecards&lt;/strong&gt;&lt;/a&gt; are low-power, 30mm x 35mm, prepaid cellular-connected devices designed to integrate with any IoT device, and Notecards know, out of the box, how to connect with the Notehub cloud to send as well as receive data from it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;&lt;strong&gt;Notehub.io&lt;/strong&gt;&lt;/a&gt; is a cloud-based service for securely connecting to Notecard devices and storing data from them before sending it on to your cloud application of choice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It quickly became apparent that rewriting the same HTTP calls in multiple projects to fetch data from the native Notehub API endpoints wasn’t easy to reuse or keep up to date as the API continues to grow and evolve.&lt;/p&gt;
&lt;p&gt;So we created our own open source, &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;JavaScript-based library&lt;/a&gt; for the Notehub API and published it on &lt;a href=&quot;https://www.npmjs.com/package/@blues-inc/notehub-js&quot;&gt;npm&lt;/a&gt; for anyone to use for free. Notehub JS is designed to get you connected to the Notehub API quickly, and allow you to access all of the API routes relevant to interacting with Notehub in a JavaScript-friendly way.&lt;/p&gt;
&lt;p&gt;Figuring out how to build an open source library like this and publish it to npm was a first for me, and I learned a lot of interesting things along the way that I&apos;d like to share with you all over the course of a few blog posts in the hope that it might help you if you decide to undertake a similar effort.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this blog, I&apos;ll show you how to set up a GitHub Actions workflow to automatically publish a new release of a GitHub repo to npm - no muss, no fuss, no manual input required.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Notehub JS&lt;/h2&gt;
&lt;p&gt;Ok, before we get to the GitHub Actions workflow, I want to give you a little background on the Notehub JS project because it&apos;s a bit unusual.&lt;/p&gt;
&lt;p&gt;As I mentioned above, Notehub JS is a JavaScript-based library for interacting with the native &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/api-introduction/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=notehub-js&quot;&gt;Notehub API&lt;/a&gt;, and it&apos;s actually generated from the Notehub project&apos;s own &lt;code&gt;openapi.yaml&lt;/code&gt; file, which follows the &lt;a href=&quot;https://swagger.io/specification/&quot;&gt;OpenAPI specification&lt;/a&gt; standards.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;OpenAPI Specification&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to HTTP APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.&lt;/p&gt;
&lt;p&gt;An OpenAPI definition can then be used by documentation generation tools to display the API, code generation tools to generate servers and clients in various programming languages, testing tools, and many other use cases.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;OpenAPI Generator CLI&lt;/h3&gt;
&lt;p&gt;Because the Notehub API has an &lt;code&gt;openapi.yaml&lt;/code&gt; file that is updated regularly, I was able to use the &lt;a href=&quot;https://openapi-generator.tech/docs/installation&quot;&gt;&lt;strong&gt;OpenAPI Generator CLI&lt;/strong&gt;&lt;/a&gt; to automatically generate a JavaScript-based library to interact with the Notehub API in just a few commands from a terminal.&lt;/p&gt;
&lt;p&gt;The catch is, when the new folder is generated which has all the API endpoints and models, the documents, and the &lt;code&gt;dist/&lt;/code&gt; folder that packages everything up for consumption as an npm module, it&apos;s stored as a &lt;em&gt;subfolder&lt;/em&gt; inside of the main Notehub JS repo.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;openapi.yaml&lt;/code&gt; file lives at the root level of the project along with its &lt;code&gt;config.json&lt;/code&gt; file, a &lt;code&gt;package.json&lt;/code&gt; file, and a few other other bits and bobs (license, contribution guidelines, code of conduct, etc.), but the real meat of the library lives inside of the &lt;code&gt;src/&lt;/code&gt; subfolder.&lt;/p&gt;
&lt;p&gt;Here&apos;s a simplified view of the &lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS repo&lt;/a&gt;&apos;s folder structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root/
├── .github/ 
| ├── workflows/
| | ├── publish-npm.yml 
├── src/ &amp;lt;- this is the folder generated by the OpenAPI Generator CLI
| ├── dist/
| ├── docs/
| ├── src/ 
| | ├── api/ 
| | ├── model/
| | ├── index.js 
| openapi.yaml
| config.json
| package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the diagram above you can see the &lt;code&gt;openapi.yaml&lt;/code&gt; file that this library is generated from lives at the root of the repo, and the &lt;code&gt;src/&lt;/code&gt; folder is what actually holds all the Notehub API JavaScript code that powers the Notehub JS library.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;src/&lt;/code&gt; folder is what needs to be published to npm - not the root of the repo as is the case with most projects in GitHub. But not to worry, publishing just this subfolder can be done, and better yet, it can be automated.&lt;/p&gt;
&lt;h3&gt;Configure the root &lt;code&gt;package.json&lt;/code&gt; to point to the subfolder where the Notehub JS library code lives&lt;/h3&gt;
&lt;p&gt;So now that I&apos;ve covered &lt;em&gt;why&lt;/em&gt; I only need to publish the subfolder of the Notehub JS repo to npm, let&apos;s get on to the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;First thing: add a few extra configuration details to the &lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/package.json&quot;&gt;&lt;code&gt;package.json&lt;/code&gt; at the root of the project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update the &lt;code&gt;main&lt;/code&gt; field to point to the subfolder&apos;s &lt;code&gt;index.js&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;According to the npm docs, the &lt;a href=&quot;https://docs.npmjs.com/cli/v9/configuring-npm/package-json#main&quot;&gt;&lt;code&gt;main&lt;/code&gt;&lt;/a&gt; field points to the primary entry point of an app, and when it&apos;s not specifically defined it defaults to &lt;code&gt;index.js&lt;/code&gt; at the root of the project.&lt;/p&gt;
&lt;p&gt;Since the &lt;code&gt;src/dist/&lt;/code&gt; folder is where the &lt;code&gt;index.js&lt;/code&gt; file lives for Notehub JS library code that should be uploaded to npm, &lt;code&gt;main&lt;/code&gt; needs to be updated to point to it instead.&lt;/p&gt;
&lt;p&gt;Now the &lt;code&gt;package.json&lt;/code&gt;&apos;s &lt;code&gt;main&lt;/code&gt; field should read:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;main&quot;: &quot;./src/dist/index.js&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update &lt;code&gt;repository&lt;/code&gt; to include a &lt;code&gt;directory&lt;/code&gt; field&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Next, the &lt;a href=&quot;https://docs.npmjs.com/cli/v9/configuring-npm/package-json#repository&quot;&gt;&lt;code&gt;repository&lt;/code&gt;&lt;/a&gt; field in a &lt;code&gt;package.json&lt;/code&gt; specifies where the code lives, and it&apos;s generally helpful for people who want to contribute to the project.&lt;/p&gt;
&lt;p&gt;It has another benefit though: if the &lt;code&gt;package.json&lt;/code&gt; for the npm package is not in the root directory (like for us, where the auto-generated &lt;code&gt;src/&lt;/code&gt; folder has its own &lt;code&gt;package.json&lt;/code&gt;), you can specify the directory in which that file lives.&lt;/p&gt;
&lt;p&gt;Here&apos;s what the &lt;code&gt;repository&lt;/code&gt; field should look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;repository&quot;: {
  &quot;type&quot;: &quot;git&quot;,
  &quot;url&quot;: &quot;https://github.com/blues/notehub-js.git&quot;,
  &quot;directory&quot;: &quot;src&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What this translates to on the npm package page is a handy link that points back to root of the GitHub folder (see image below).&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions-npm/npm-repo-link.png&quot; alt=&quot;Notehub JS npm page highlighting repository link on the page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Add the &lt;code&gt;publishConfig&lt;/code&gt; field to specify &lt;code&gt;directory&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Typically, the &lt;a href=&quot;https://docs.npmjs.com/cli/v9/configuring-npm/package-json#publishconfig&quot;&gt;&lt;code&gt;publishConfig&lt;/code&gt;&lt;/a&gt; field is used to set config values that will be used at publish time like tags, registries, or access.&lt;/p&gt;
&lt;p&gt;Another field that can be added here is &lt;code&gt;directory&lt;/code&gt;, which customizes the published subdirectory relative to the current &lt;code&gt;package.json&lt;/code&gt;. This ensures npm knows the &lt;code&gt;package.json&lt;/code&gt; it needs to read from (and display) in the npm package page is inside of the auto-generated &lt;code&gt;src/&lt;/code&gt; folder, not at the root of the project.&lt;/p&gt;
&lt;p&gt;Add the following &lt;code&gt;publishConfig&lt;/code&gt; code to the &lt;code&gt;package.json&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;publishConfig&quot;: {
  &quot;registry&quot;: &quot;https://registry.npmjs.org&quot;,
  &quot;directory&quot;: &quot;./src&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the end, the whole &lt;code&gt;package.json&lt;/code&gt; at the root of the Notehub JS repo looks like the code snippet below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I&apos;ve omitted parts of the &lt;code&gt;package.json&lt;/code&gt; for clarity, but if you&apos;d like to see the whole file, you can click the file name below. It&apos;s linked to the actual file in the repo in GitHub.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/package.json&quot;&gt;&lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;notehub-js&quot;,
  &quot;description&quot;: &quot;JavaScript library for accessing the Blues Wireless Notehub API endpoints&quot;,
  &quot;main&quot;: &quot;./src/dist/index.js&quot;,
  &quot;repository&quot;: {
    &quot;type&quot;: &quot;git&quot;,
    &quot;url&quot;: &quot;https://github.com/blues/notehub-js.git&quot;,
    &quot;directory&quot;: &quot;src&quot;
  },
  &quot;publishConfig&quot;: {
    &quot;registry&quot;: &quot;https://registry.npmjs.org&quot;,
    &quot;directory&quot;: &quot;./src&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great, the changes to the &lt;code&gt;package.json&lt;/code&gt; to publish just the &lt;code&gt;src/&lt;/code&gt; folder to npm are complete, let&apos;s move on to the GitHub Actions workflow to make publishing a new version of the Notehub JS library to npm as automated as possible.&lt;/p&gt;
&lt;h3&gt;Create a GitHub Actions workflow to publish to npm&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Need a refresher on GitHub Actions?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want a quick primer on what GitHub Actions are, I recommend you check out a previous article I wrote about them &lt;a href=&quot;./use-secret-environment-variables-in-git-hub-actions#what-is-github-actions&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I decided that for my use case, creating a new &lt;a href=&quot;https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases&quot;&gt;&lt;strong&gt;release&lt;/strong&gt;&lt;/a&gt; made the most sense to trigger a GitHub Actions workflow to publish the Notehub JS &lt;code&gt;src/&lt;/code&gt; subfolder to npm.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GitHub specifically defines a &lt;strong&gt;release&lt;/strong&gt; as a deployable software iteration that you can package and make available for a wider audience to download and use, which is exactly what I want.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once I had settled on this as the trigger for my GitHub Actions workflow, it was a pretty straightforward set of steps to publish to npm.&lt;/p&gt;
&lt;p&gt;Here&apos;s what the finished &lt;code&gt;publish-npm.yml&lt;/code&gt; file will look like inside of the &lt;code&gt;./github/workflows/&lt;/code&gt; folder - I&apos;ll break it all down afterwards.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/notehub-js/blob/main/.github/workflows/publish-npm.yml&quot;&gt;&lt;strong&gt;&lt;code&gt;publish-npm.yml&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Publish notehub-js to npm

on:
  release:
    types: [created]

jobs:
  npm:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./src
    steps:
      - name: Check out code
        uses: actions/checkout@v3

      - name: Setup .npmrc file to publish to npm
        uses: actions/setup-node@v3
        with:
          node-version: &quot;16.x&quot;
          registry-url: &quot;https://registry.npmjs.org&quot;

      - name: Install dependencies
        run: npm ci

      - name: Publish to npm
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each workflow file needs a &lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt;, so I chose a descriptive one: &lt;code&gt;Publish notehub-js to npm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, as I already explained above, this workflow is triggered whenever a new release is created in GitHub, which is where&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;on:
  release: 
    types: [created]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;comes into play.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on&quot;&gt;&lt;strong&gt;&lt;code&gt;on&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is how a workflow is triggered.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release&quot;&gt;&lt;strong&gt;&lt;code&gt;release&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is the event that triggers the workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;types: [created]&lt;/code&gt;&lt;/strong&gt; is the activity type for a &lt;code&gt;release&lt;/code&gt; event that triggers the workflow. This gives us more fine-grained control of when the workflow should run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then the &lt;strong&gt;&lt;code&gt;jobs&lt;/code&gt;&lt;/strong&gt; section runs inside of the workflow. This particular script only has one job, &lt;code&gt;npm&lt;/code&gt;, but if there&apos;s multiple jobs, they&apos;ll run sequentially unless otherwise specified.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;npm&lt;/code&gt; job defines that it runs on the latest version of Ubuntu in &lt;strong&gt;&lt;code&gt;runs-on&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#defaultsrun&quot;&gt;&lt;strong&gt;&lt;code&gt;defaults.run&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is an important part of the script because it&apos;s where I specify that the working directory for all the following steps is the &lt;code&gt;src/&lt;/code&gt; folder (because I don&apos;t need any of the files from the root of the repo, just what&apos;s inside the &lt;code&gt;src/&lt;/code&gt; folder, I can define this at the job level).&lt;/p&gt;
&lt;p&gt;Finally, I get to the &lt;strong&gt;&lt;code&gt;steps&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The steps are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check out the code so the workflow can access it using the GitHub Action &lt;a href=&quot;https://github.com/actions/checkout&quot;&gt;&lt;code&gt;actions/checkout@v3&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Download a Node.js version to build the package before publishing it to npm using the GitHub Action &lt;a href=&quot;https://github.com/actions/setup-node&quot;&gt;&lt;code&gt;actions/setup-node@v3&lt;/code&gt;&lt;/a&gt; (specify the &lt;code&gt;node-version&lt;/code&gt; and &lt;code&gt;registry-url&lt;/code&gt; for npm here).&lt;/li&gt;
&lt;li&gt;Install the project&apos;s dependencies stored in the &lt;code&gt;src/&lt;/code&gt; folder&apos;s &lt;code&gt;package.json&lt;/code&gt; file using &lt;a href=&quot;https://github.com/actions/setup-node&quot;&gt;&lt;code&gt;npm ci&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Publish to npm by running the command &lt;a href=&quot;https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages#publishing-packages-to-the-npm-registry&quot;&gt;&lt;code&gt;npm publish&lt;/code&gt;&lt;/a&gt; and supplying it with an &lt;a href=&quot;https://docs.npmjs.com/creating-and-viewing-access-tokens&quot;&gt;&lt;code&gt;NPM_TOKEN&lt;/code&gt;&lt;/a&gt; (generated in npm) to verify this workflow has permissions to publish to the specified npm package registry.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And there you have it: each time a new release is created in the Notehub JS repo, this GitHub Actions workflow will run and deploy the updated code to npm.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Working as an engineer for a startup company is cool because no two days are alike for me. One day I&apos;m building web apps and updating documentation on our developer experience site, the next I&apos;m reading up on best practices for npm packages and how to automate tasks with GitHub Actions.&lt;/p&gt;
&lt;p&gt;Venturing into the realm of open source software and publishing my first JavaScript package to npm was quite a learning experience for me, but I&apos;m so grateful I had the chance to push myself into this space and create something useful for my team (and hopefully our users as well!).&lt;/p&gt;
&lt;p&gt;One thing I knew I wanted, right from the start, was to automate the tasks I knew I&apos;d be repeating fairly regularly over time: namely, regenerating the JavaScript library as the Notehub API continued to evolve, and redeploying a new version of the library to npm with the latest updates.&lt;/p&gt;
&lt;p&gt;With some extra configurations in the Notehub JS repo&apos;s &lt;code&gt;package.json&lt;/code&gt;, I was able to focus in on the auto-generated subfolder that contains the useful JavaScript-based code for easily interacting with the Notehub API, and with a few GitHub Actions inside of a workflow, I was able to build the code for the package and publish it to npm with the click of a button. Not too bad for an end result.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about the useful things I learned while building this project in addition to other topics on JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning how to target a specific folder inside of a project and automating deployments to npm through GitHub Actions workflows come in handy for you in the future. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blues/notehub-js&quot;&gt;Notehub JS&lt;/a&gt; GitHub repo&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@blues-inc/notehub-js&quot;&gt;notehub-js&lt;/a&gt; npm library&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openapi-generator.tech/docs/installation&quot;&gt;OpenAPI Generator CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>github</category><category>git</category><category>npm</category><category>devops</category></item><item><title>Tips and Tricks for Using the Prisma ORM</title><link>https://www.paigeniedringhaus.com/blog/tips-and-tricks-for-using-the-prisma-orm/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/tips-and-tricks-for-using-the-prisma-orm/</guid><description>Implicit relational databases, JSON values, fetching the latest record from a table, handling no data scenarios - it&apos;s all doable with Prisma.io.</description><pubDate>Wed, 22 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prisma-tips-tricks/prism-hero.jpg&quot; alt=&quot;Crystal pyramid&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Recently, my team and I were building an application that monitored the flow rate of liquid through pipes and remotely controlled valves to enable or disable these flows.&lt;/p&gt;
&lt;p&gt;I work for the Internet of Things company &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=nf&amp;amp;utm_content=nf9&quot;&gt;Blues&lt;/a&gt; which specializes in getting IoT data from devices in the real world into the cloud via cellular, and we were demonstrating how our tech could be used by facilities managers to monitor liquid and gas transfers and remotely toggle valves throughout a piping system via a web app.&lt;/p&gt;
&lt;p&gt;Without going into too much detail, the way the project works is: the device sends the current flow rate data and valve state to the cloud, the cloud then forwards that information to our web application, and the application saves that data into a PostgreSQL database and displays it in the browser for the user. From the UI, the user can monitor the flow rate, checking for anomalies, and open or close a valve at will.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;re interested to learn more about our flow rate monitoring project, you can see the full tutorial for building your own &lt;a href=&quot;https://www.hackster.io/blues-wireless/open-close-valves-and-monitor-flow-rate-remotely-9ac9fc&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The web app dashboard looks like this:
&lt;img src=&quot;../images/prisma-tips-tricks/valve-monitor-dashboard.png&quot; alt=&quot;Dashboard UI for valve monitor project&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For the web app, we were using &lt;a href=&quot;https://nextjs.org/&quot;&gt;Next.js&lt;/a&gt; to display our IoT data dashboard, and &lt;a href=&quot;https://www.prisma.io/&quot;&gt;Prisma&lt;/a&gt; (an object relational mapper or ORM) to interact with our PostgreSQL database. Because of the project requirements, which I&apos;ll get into shortly, we ended up doing some pretty interesting things with Prisma including upsert transactions, querying for the most recent record in a table, fetching related data from multiple tables in one query, handling raw JSON data, and more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;m going to share with you some of the more advanced and complex solutions I learned to solve with Prisma.io in hopes of making it easier when you run into similar scenarios in your own application development.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: This article is not an introduction to working with Prisma. If you&apos;re new to it, I highly recommend checking out their &lt;a href=&quot;https://www.prisma.io/docs/getting-started&quot;&gt;getting started documentation&lt;/a&gt; first to get familiar.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Prisma primer&lt;/h2&gt;
&lt;p&gt;Rarely do web developers today write raw SQL queries in their applications. Instead, we tend to rely on object relational mapping libraries (ORMs) like &lt;a href=&quot;https://mongoosejs.com/&quot;&gt;Mongoose&lt;/a&gt;, &lt;a href=&quot;https://sequelize.org/&quot;&gt;Sequelize&lt;/a&gt;, &lt;a href=&quot;https://knexjs.org/&quot;&gt;Knex&lt;/a&gt;, or &lt;a href=&quot;https://www.prisma.io/&quot;&gt;Prisma&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ORMs provide a host of benefits like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time saved writing raw queries,&lt;/li&gt;
&lt;li&gt;Compatibility with multiple types of databases,&lt;/li&gt;
&lt;li&gt;Schema definitions,&lt;/li&gt;
&lt;li&gt;Type-safety,&lt;/li&gt;
&lt;li&gt;And more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.prisma.io/&quot;&gt;&lt;strong&gt;Prisma&lt;/strong&gt;&lt;/a&gt;, in particular, has become the latest, open source favorite when it comes to ORMs because it provides all the benefits I mentioned above plus:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VS Code integration,&lt;/li&gt;
&lt;li&gt;TypeScript type-safety,&lt;/li&gt;
&lt;li&gt;Pagination and transactions,&lt;/li&gt;
&lt;li&gt;Serverless support,&lt;/li&gt;
&lt;li&gt;And a visual database browser, to name a just few.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is really slick to work with and makes interacting with a database in a JavaScript application feel much more intuitive and natural and much less like two different languages being mashed together.&lt;/p&gt;
&lt;p&gt;But even with all this going for it, there are still some things that are just plain complex to do, so let&apos;s cover some of them now so they&apos;re less daunting when you run into them in your next project.&lt;/p&gt;
&lt;h3&gt;Define implicit many-to-many data relationships&lt;/h3&gt;
&lt;p&gt;The majority of the tips I want to share have to do with tables of related data, so the first thing we&apos;ll cover is how to define those type of relationships.&lt;/p&gt;
&lt;p&gt;For our project, we had two Prisma models that were related to one another:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Device&lt;/strong&gt; - each individual flow rate and valve control device,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fleet&lt;/strong&gt; - a particular group of these devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; For any of the code snippets listed below, click the titles of the snippets to see the working code in GitHub repo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;Device&lt;/code&gt; model in Prisma schema looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/schema.prisma&quot;&gt;&lt;strong&gt;&lt;code&gt;Device&lt;/code&gt; model&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model Device {
  id            Int         @id @default(autoincrement())

  // unique device uid in notehub
  deviceID     String      @unique @map(&quot;device_id&quot;) @db.VarChar(64)

  // device serial number (cached)
  name          String?     @db.VarChar(80)
  lastSeenAt    DateTime?   @map(&quot;last_seen_at&quot;) // the last time an event was heard from this device

  // the project the device belongs to
  project       Project     @relation(fields: [projectID], references: [projectID])
  projectID    String

  @@map(&quot;device&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Fleet&lt;/code&gt; model in the Prisma schema looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/schema.prisma&quot;&gt;&lt;strong&gt;&lt;code&gt;Fleet&lt;/code&gt; model&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model Fleet {
  id          Int      @id @default(autoincrement())

  // unique fleet id
  fleeID    String   @unique

  // the project the fleet belongs to
  project     Project   @relation(fields: [projectID], references: [projectID])
  projectID  String

  @@map(&quot;fleet&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each device can belong to no fleets or multiple fleets, and each fleet can contain no devices or many devices. This is a classic example of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Many-to-many_(data_model)&quot;&gt;many-to-many (m:n) relationship&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Prisma offers two ways to handle these sorts of relationships:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-schema/relations/many-to-many-relations#explicit-many-to-many-relations&quot;&gt;&lt;strong&gt;Explicit&lt;/strong&gt; many-to-many relationships&lt;/a&gt; - in explicit m:n relationships, the relation table is represented as its own model in the Prisma schema and can be used in queries. Explicit many-to-many relations define three models: Two models that have a many-to-many relation: &lt;code&gt;Device&lt;/code&gt; and &lt;code&gt;Fleet&lt;/code&gt;, and one model that represents the relation table: &lt;code&gt;DevicesInFleets&lt;/code&gt; (sometimes called the &lt;code&gt;JOIN&lt;/code&gt;, link or pivot table) in the underlying database.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-schema/relations/many-to-many-relations#implicit-many-to-many-relations&quot;&gt;&lt;strong&gt;Implicit&lt;/strong&gt; many-to-many relationships&lt;/a&gt; - in implicit m:n relationships, the table exists in the underlying database, but it is managed by Prisma and does not manifest in the Prisma schema (i.e. you don&apos;t have to define the &lt;code&gt;DevicesInFleets&lt;/code&gt; model and table yourself, Prisma just knows it&apos;s a thing).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is a typical JSON &lt;code&gt;Device&lt;/code&gt; data event that might get routed to the web app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example event routed to the app&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;projectID&quot;: &quot;app:a8beb5bd-622e-46a6-866a-ae4528c7c201&quot;,
  &quot;deviceID&quot;: &quot;dev:864622040363787&quot;,
  &quot;eventID&quot;: &quot;490006f7-80f8-4314-8b5e-5ff587f07fba&quot;,
  &quot;lastSeenAt&quot;: &quot;2023-01-23T18:29:16.000Z&quot;,
  &quot;eventBody&quot;: { &quot;flow_rate&quot;: 810, &quot;valve_state&quot;: &quot;open&quot; },
  &quot;fleetIDs&quot;: [ &quot;fleet:f660d491-8830-420f-be7a-c8f91c460813&quot; ],
  &quot;name&quot;: &quot;Pipe Section A&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For convenience, we chose to take advantage of Prisma&apos;s implicit many-to-many relationship option to associate devices and fleets with one another. In order to let Prisma know that devices and fleets are related , in the &lt;code&gt;Device&lt;/code&gt; and &lt;code&gt;Fleet&lt;/code&gt; models defined in the &lt;code&gt;schema.prisma&lt;/code&gt; file, simply add each related model to the other&apos;s schema.&lt;/p&gt;
&lt;p&gt;So the &lt;code&gt;Device&lt;/code&gt; model has &lt;code&gt;Fleet&lt;/code&gt; added to it:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/schema.prisma&quot;&gt;&lt;strong&gt;&lt;code&gt;Device&lt;/code&gt; model&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model Device {
  id            Int         @id @default(autoincrement())

  // unique device uid in notehub
  deviceID     String      @unique @map(&quot;device_id&quot;) @db.VarChar(64)

  // extra device-specific data here

  // fleets a device belongs to (implicit many-to-many relationship)
  fleets        Fleet[]

  @@map(&quot;device&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the &lt;code&gt;Fleet&lt;/code&gt; model has &lt;code&gt;Device&lt;/code&gt; added to it:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/schema.prisma&quot;&gt;&lt;strong&gt;&lt;code&gt;Fleet&lt;/code&gt; model&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model Fleet {
  id          Int      @id @default(autoincrement())

  // unique fleet id
  fleeID    String   @unique

  // more fleet-specific data

  // devices assigned to fleet (implicit many-to-many relationship)
  devices     Device[]

  @@map(&quot;fleet&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s all you need to do to establish an implicit many-to-many relationship with Prisma. No explicit tables, no SQL queries, no extra work to handle a relatively complex, yet very commonplace, relationship. I can tell you, implicitly defining these sorts of relationships amongst a number of related tables in this project really saved us a ton of time during development.&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve defined the related data, it&apos;s time to handle creating or updating related data in one function.&lt;/p&gt;
&lt;h3&gt;Accurately update related records across multiple tables with Prisma&lt;/h3&gt;
&lt;p&gt;Building off the previous example, we&apos;ll cover here how to correctly update related data across multiple tables at once.&lt;/p&gt;
&lt;p&gt;As I said before, each device can belong to zero or more fleets, and each fleet can contain zero or more devices at any given time.&lt;/p&gt;
&lt;p&gt;As new &lt;code&gt;Device&lt;/code&gt; events flow into our PostgreS database from individual devices, each event includes a field with a list of fleet IDs for whichever fleets that device belongs to at the time (if any).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example event routed to the app&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;projectID&quot;: &quot;app:a8beb5bd-622e-46a6-866a-ae4528c7c201&quot;,
  &quot;deviceID&quot;: &quot;dev:864622040363787&quot;,
  &quot;eventID&quot;: &quot;490006f7-80f8-4314-8b5e-5ff587f07fba&quot;,
  &quot;lastSeenAt&quot;: &quot;2023-01-23T18:29:16.000Z&quot;,
  &quot;eventBody&quot;: { &quot;flow_rate&quot;: 810, &quot;valve_state&quot;: &quot;open&quot; },
  &quot;fleetIDs&quot;: [ &quot;fleet:f660d491-8830-420f-be7a-c8f91c460813&quot; ],
  &quot;name&quot;: &quot;Pipe Section A&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;According to Prisma&apos;s docs, the &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#connect-or-create-a-record&quot;&gt;&lt;strong&gt;&lt;code&gt;connectOrCreate API&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; function is the way to create a &quot;related record&quot; that may or may not exist, which is perfect for adding new devices to the &lt;code&gt;Device&lt;/code&gt; table and new, related fleets to the &lt;code&gt;Fleet&lt;/code&gt; table at the same time via a &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#nested-writes&quot;&gt;&lt;strong&gt;&lt;code&gt;create()&lt;/code&gt; with nested write function&lt;/strong&gt;&lt;/a&gt;. However, when attempting to update a device&apos;s fleets when a new event came in, I encountered a slight problem with the &lt;code&gt;update()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;When an event arrives for an existing device and the fleets are completely different, only having the &lt;code&gt;connectOrCreate()&lt;/code&gt; function present in the &lt;code&gt;update()&lt;/code&gt; failed to delete the old fleets and replace them with new fleets in the &lt;code&gt;Fleet&lt;/code&gt; table. The new fleets were instead associated with the device &lt;em&gt;along with&lt;/em&gt; the old fleets, and the device looked as if it was associated with more fleets than it truly was.&lt;/p&gt;
&lt;p&gt;In order to accurately update both the &lt;code&gt;Device&lt;/code&gt; table and the related records in the &lt;code&gt;Fleet&lt;/code&gt; table in the same query, we have to do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Disconnect all related fleet records using the &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#disconnect-all-related-records&quot;&gt;&lt;strong&gt;&lt;code&gt;set()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; method.&lt;/li&gt;
&lt;li&gt;Call the &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#connect-or-create-a-record&quot;&gt;&lt;strong&gt;&lt;code&gt;connectOrCreate()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; function to insert the new fleet data into the &lt;code&gt;Fleet&lt;/code&gt; table.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Deleting specific related records with &lt;strong&gt;&lt;code&gt;deleteMany()&lt;/code&gt;&lt;/strong&gt; function does not work&lt;/p&gt;
&lt;p&gt;Another option for altering related records that I tried was to delete all related records using the &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#delete-specific-related-records&quot;&gt;&lt;code&gt;deleteMany()&lt;/code&gt; function&lt;/a&gt;. This didn&apos;t work correctly though because it deleted the fleet IDs from &lt;em&gt;all the devices&lt;/em&gt; in the &lt;code&gt;Device&lt;/code&gt; table, not just the &lt;code&gt;deviceID&lt;/code&gt; the event specified.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is what the final &lt;code&gt;upsertDevice()&lt;/code&gt; query looks like: it correctly updates the device data in the &lt;code&gt;Device&lt;/code&gt; table, and the associated fleet IDs in the &lt;code&gt;Fleet&lt;/code&gt; table without altering the fleets associated with any other device in the process.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/PrismaDatastoreEventHandler.ts&quot;&gt;&lt;strong&gt;&lt;code&gt;upsertDevice()&lt;/code&gt; query&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; /**
   * Insert or update the device based on the unique device ID.
   *
   * @param project
   * @param deviceID
   * @param name
   * @param lastSeenAt
   * @param fleetIDs
   * @param location
   * @returns
   */
  private upsertDevice(
    project: Project,
    deviceID: string,
    name: string | undefined,
    lastSeenAt: Date,
    fleetIDs: string[],
    location?: NotehubLocation
  ) {
    const args = arguments;

    const formatConnectedFleetData = fleetIDs.map((fleet) =&amp;gt; ({
      create: {
        fleetID: fleet,
        projectID: project.projectID,
      },
      where: {
        fleetID: fleet,
      },
    }));

    return this.prisma.device
      .upsert({
        where: {
          deviceID,
        },
        create: {
          name,
          deviceID,
          locationName,
          fleets: {
            connectOrCreate: formatConnectedFleetData,
          },
          project: {
            connect: {
              id: project.id,
            },
          },
          lastSeenAt,
        },
        update: {
          name,
          locationName,
          fleets: {
            set: [],
            connectOrCreate: formatConnectedFleetData,
          },
          project: {
            connect: {
              id: project.id,
            },
          },
          lastSeenAt,
        },
      })
      .catch((cause) =&amp;gt; {
        throw new ErrorWithCause(
          `error upserting device ${deviceID} ${JSON.stringify(args)}`,
          { cause }
        );
      });
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Be aware that the &lt;code&gt;set()&lt;/code&gt; function does not actually delete the fleet ID from the &lt;code&gt;Fleet&lt;/code&gt; table - it just disconnects it from the device, however, as long as you don&apos;t have large amounts of fleet ID records filling up your related table, this shouldn&apos;t pose any major performance problems for your app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unfortunately there&apos;s currently no single related record &lt;code&gt;upsert()&lt;/code&gt; function that will both delete previously related records and create newly related records, but maybe one day Prisma will include this use case. Until then, I hope this helps you handle accurately updating your related records.&lt;/p&gt;
&lt;p&gt;Ok, let&apos;s move on to the next complex Prisma tip: including relational data in a &lt;code&gt;READ&lt;/code&gt; query.&lt;/p&gt;
&lt;h3&gt;Return relational data from another table in Prisma READ query&lt;/h3&gt;
&lt;p&gt;Just like updating related tables can be done in a single transaction with Prisma, querying multiple tables for related data can also be done in a single action.&lt;/p&gt;
&lt;p&gt;Taking the web app we&apos;ve been talking about, for display purposes in the UI, it&apos;s necessary to have both the individual device ID and the fleet IDs that each device belongs to. If you&apos;ve been following along with this article, you&apos;ll know already that the device details reside in the &lt;code&gt;Device&lt;/code&gt; table and the fleet details for fleets that device is part of reside in their own separate &lt;code&gt;Fleet&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;When storing device and related fleet data in their proper tables, we can use the &lt;code&gt;connectOrCreate&lt;/code&gt; API function.&lt;/p&gt;
&lt;p&gt;To perform a &quot;nested read&quot; and fetch both the device details &lt;em&gt;and&lt;/em&gt; the associated fleet details, we use Prisma&apos;s &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#include-all-fields-for-a-specific-relation&quot;&gt;&lt;strong&gt;&lt;code&gt;include&lt;/code&gt; API&lt;/strong&gt;&lt;/a&gt; function.&lt;/p&gt;
&lt;p&gt;To get all the fleet data associated with a particular device, the &lt;code&gt;fetchDevice()&lt;/code&gt; query in our code base looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/PrismaDataProvider.ts&quot;&gt;&lt;strong&gt;&lt;code&gt;fetchDevice()&lt;/code&gt; function&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async fetchDevice(deviceID: DeviceID) {
    const device = await this.prisma.device.findUnique({
      where: {
        deviceID: deviceID,
      },
      include: {
        fleets: true,
      },
    });
    return device;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use Prisma&apos;s standard &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/crud#get-record-by-id-or-unique-identifier&quot;&gt;&lt;strong&gt;&lt;code&gt;findUnique&lt;/code&gt; API&lt;/strong&gt;&lt;/a&gt; query on the &lt;code&gt;Device&lt;/code&gt; table to find the specific device based on its device ID, and then inside of that &lt;code&gt;findUnique()&lt;/code&gt; query, we add &lt;code&gt;include: { fleets: true }&lt;/code&gt; to get all the fleet details that are related to that device.&lt;/p&gt;
&lt;p&gt;Here is what the data that comes back from the query looks like:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example device data with fleet info returned from query&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  [
   {
      &quot;id&quot;:1,
      &quot;deviceID&quot;:&quot;dev:864622040363787&quot;,
      &quot;name&quot;:&quot;Pipe Section A&quot;,
      &quot;lastSeenAt&quot;:&quot;2023-01-23T18:29:16.000Z&quot;,
      &quot;projectUID&quot;:&quot;app:a8beb5bd-622e-46a6-866a-ae4528c7c201&quot;,
      &quot;fleets&quot;:[
         {
            &quot;id&quot;:1,
            &quot;fleetID&quot;:&quot;fleet:f660d491-8830-420f-be7a-c8f91c460813&quot;,
            &quot;projectID&quot;:&quot;app:a8beb5bd-622e-46a6-866a-ae4528c7c201&quot;
         }
      ]
   }
 ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see from the code above, all the relevant device info is provided &lt;em&gt;along with&lt;/em&gt; the fleet data for its related fleet. Pretty sweet.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you only wanted to return certain fields for related data, you could use the &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#select-specific-relation-fields&quot;&gt;&lt;strong&gt;&lt;code&gt;select&lt;/code&gt; API&lt;/strong&gt;&lt;/a&gt; to choose a subset of related fields to return.&lt;/p&gt;
&lt;p&gt;For example, if you &lt;em&gt;only&lt;/em&gt; wanted related fleet IDs, you&apos;d update the &lt;code&gt;include&lt;/code&gt; query to be: &lt;code&gt;include: { fleets: { select: { fleetID: true } } } }&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Get most recent data record from a table&lt;/h3&gt;
&lt;p&gt;Right, let&apos;s move on to reading the most recent data record from a table.&lt;/p&gt;
&lt;p&gt;In the UI of the valve flow rate monitor, we need to get the most recently added &lt;code&gt;flow-rate&lt;/code&gt; and &lt;code&gt;valve&lt;/code&gt; state data for a device to correctly show the user what&apos;s happening.&lt;/p&gt;
&lt;p&gt;Prisma provides a &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/crud#get-the-first-record-that-matches-a-specific-criteria&quot;&gt;&lt;strong&gt;&lt;code&gt;findFirst&lt;/code&gt; API&lt;/strong&gt;&lt;/a&gt; query that returns the first created data record, but it doesn&apos;t provide a similarly named &lt;code&gt;findLast&lt;/code&gt; API query.&lt;/p&gt;
&lt;p&gt;Instead, there are two ways we can get the most recent record out of a table:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use a combination of the &lt;code&gt;findFirst&lt;/code&gt; API and the &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/crud#get-the-first-record-that-matches-a-specific-criteria&quot;&gt;&lt;strong&gt;&lt;code&gt;orderBy&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; filter to sort the records by something like the record&apos;s date.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;findMany&lt;/code&gt; API and use the &lt;a href=&quot;https://github.com/prisma/prisma/releases/tag/2.0.0-beta.7&quot;&gt;&lt;strong&gt;&lt;code&gt;take&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; function to grab just the last value from the query.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&apos;ll cover both options:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;findFirst and orderBy example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first way to get the most recent event from a table is to use &lt;code&gt;findFirst&lt;/code&gt; combined with &lt;code&gt;orderBy&lt;/code&gt; where the records are sorted in descending order from newest to oldest. In the app, there are alarms that are triggered when a device&apos;s flow rate falls below or above thresholds set by the user; the alarm is displayed by highlighting the device&apos;s row in red in a table showing all the devices.&lt;/p&gt;
&lt;p&gt;Since the device row can&apos;t be highlighted more than once, we don&apos;t need to know if the device has more than one alarm event for it - we only need to know the most recent alarm event, so we&apos;ll use the &lt;code&gt;findFirst&lt;/code&gt; query and sort all the alarm events in the &lt;code&gt;Notification&lt;/code&gt; table for a device in descending order by their &lt;code&gt;lastSeenAt&lt;/code&gt; date.&lt;/p&gt;
&lt;p&gt;Here&apos;s how the final query looks.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/PrismaDataProvider.ts&quot;&gt;&lt;strong&gt;getLatestDeviceAlarm()&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  async getLatestDeviceAlarm(deviceID: DeviceID): Promise&amp;lt;Notification&amp;gt; {
    const latestAlarmFromDevice = await this.prisma.notification.findFirst({
      where: {
        AND: {
          type: &quot;alarm&quot;,
        },
        content: {
          path: [&quot;deviceID&quot;],
          equals: deviceID,
        },
      },
      orderBy: {
        lastSeenAt: &quot;desc&quot;,
      },
    });

    return latestAlarmFromDevice || undefined;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice in the query that in the end, the &lt;code&gt;getLatestDeviceAlarm()&lt;/code&gt; function either returns the most recent alarm for a device or it returns &lt;code&gt;undefined&lt;/code&gt; because there&apos;s a chance the device has not had an alarm go off. Something to keep in mind, which I&apos;ll cover in more detail later in this article.&lt;/p&gt;
&lt;p&gt;Now let&apos;s look at the other option to get the most recent record from the &lt;code&gt;Event&lt;/code&gt; table using &lt;code&gt;findMany&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;findMany and take example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/PrismaDataProvider.ts&quot;&gt;&lt;strong&gt;getLatestDeviceEvent()&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async getLatestDeviceEvent(deviceID: DeviceID, file: string): Promise&amp;lt;Event&amp;gt; {
    const latestDeviceEvent = await this.prisma.event.findMany({
      where: {
        AND: {
          deviceUID: deviceID,
        },
        eventName: file,
      },
      take: -1,
    });
    return latestDeviceEvent[0];
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this function, we just want to get the latest regular event for a device: the latest flow rate and valve state reading - again, it&apos;s used to display the device&apos;s current status in the web app dashboard.&lt;/p&gt;
&lt;p&gt;To get the most recent event with Prisma&apos;s &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/crud#get-all-records&quot;&gt;&lt;strong&gt;&lt;code&gt;findMany&lt;/code&gt;&lt;/strong&gt; API&lt;/a&gt;, we use the &lt;code&gt;deviceID&lt;/code&gt; to narrow down all the events and use &lt;code&gt;take: -1&lt;/code&gt; to grab the last record in the table. &lt;code&gt;take: -1&lt;/code&gt; was introduced to Prisma back in v2 to simplify paginating through lots of data, but it can also be used just to return one record as well as a list of records, just remember to extract the single record from the array when accessing the data.&lt;/p&gt;
&lt;h3&gt;Read and write JSON data to a table&lt;/h3&gt;
&lt;p&gt;All right, now we&apos;ll cover a very useful and flexible thing you might want to do: write JSON data into a table column or read it out again.&lt;/p&gt;
&lt;p&gt;JSON fields are super useful when you need to store data that doesn&apos;t have a consistent structure (i.e. you&apos;re not sure what properties will be present or not), or you&apos;re importing data from another system and don&apos;t want to map that data to Prisma models.&lt;/p&gt;
&lt;p&gt;For our project, we chose to use JSON fields for event objects because we weren&apos;t always certain what data an event might contain. Here&apos;s what an event routed to the app might look like, the &lt;code&gt;eventBody&lt;/code&gt; property is what we want to store as raw JSON data because it&apos;s the field most subject to change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example event routed to the app&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;projectID&quot;: &quot;app:a8beb5bd-622e-46a6-866a-ae4528c7c201&quot;,
  &quot;deviceID&quot;: &quot;dev:864622040363787&quot;,
  &quot;eventID&quot;: &quot;490006f7-80f8-4314-8b5e-5ff587f07fba&quot;,
  &quot;lastSeenAt&quot;: &quot;2023-01-23T18:29:16.000Z&quot;,
  &quot;eventBody&quot;: { &quot;flow_rate&quot;: 810, &quot;valve_state&quot;: &quot;open&quot; },
  &quot;fleetIDs&quot;: [ &quot;fleet:f660d491-8830-420f-be7a-c8f91c460813&quot; ],
  &quot;name&quot;: &quot;Pipe Section A&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get our data table prepared to accept any old JSON data as a column, we just need to tell the model that&apos;s the case. So in our &lt;code&gt;schema.prisma&lt;/code&gt; file where we define all our Prisma models, we set the properties for an &lt;code&gt;Event&lt;/code&gt; like so:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/schema.prisma&quot;&gt;&lt;strong&gt;&lt;code&gt;Event&lt;/code&gt; model&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model Event {
  id           Int         @id @default(autoincrement())

  eventName    String      @map(&quot;file&quot;)
  eventID     String      @map(&quot;event&quot;) @unique

// the device that produced the event
  device       Device      @relation(fields: [deviceID], references: [deviceID], onDelete: Cascade)
  deviceID    String 

// when the event occurred
  when         DateTime
  value        Json

  @@map(&quot;event&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The property to pay special attention to is the &lt;code&gt;value&lt;/code&gt; property - that&apos;s the field we&apos;re giving a type of &lt;code&gt;Json&lt;/code&gt; to, which is all we need to do to make the model happy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Write JSON into a Prisma field&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After the model&apos;s defined, when a new event comes in (like the example above), a Prisma &lt;code&gt;upsert()&lt;/code&gt; function can be called on the &lt;code&gt;Event&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/blues/app-accelerators/blob/main/09-valve-monitor/web-app/src/services/prisma-datastore/PrismaDatastoreEventHandler.ts&quot;&gt;&lt;strong&gt;&lt;code&gt;upsertEvent()&lt;/code&gt; function&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  /**
   * Insert or update the event
   *
   * @param deviceID
   * @param when
   * @param eventName
   * @param eventID
   * @param value
   * @returns
   */
  private upsertEvent(
    deviceID: string,
    when: Date,
    eventName: string,
    eventUID: string,
    value: object
  ) {
    const args = arguments;

    return this.prisma.event
      .upsert({
        where: {
          eventID,
        },
        create: {
          deviceID,
          when,
          eventName,
          eventID,
          value,
        },
        update: {
          // reading already exists
          // no-op
        },
      })
      .catch((cause) =&amp;gt; {
        throw new ErrorWithCause(
          `error upserting event ${deviceUID} ${JSON.stringify(args)}`,
          { cause }
        );
      });
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&apos;re using TypeScript like we are in our project, just define the JSON field &lt;code&gt;value&lt;/code&gt; as an &lt;code&gt;object&lt;/code&gt; and then simply pass it in as one of the values in the Prisma &lt;code&gt;upsert()&lt;/code&gt; function. Pretty straightforward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read JSON from a Prisma table&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Reading the JSON field out with Prisma is pretty straightforward as well. If you recall in the previous tip we looked at the &lt;code&gt;getLatestDeviceEvent()&lt;/code&gt; query, this query returns the data from the &lt;code&gt;Event&lt;/code&gt; table, including the JSON field &lt;code&gt;value&lt;/code&gt;. When the data is returned it looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example event data returned from &lt;code&gt;getLatestDeviceEvent()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {
    &quot;id&quot;: 1,
    &quot;eventName&quot;: &quot;data.qo&quot;,
    &quot;eventID&quot;: &quot;490006f7-80f8-4314-8b5e-5ff587f07fbc&quot;,
    &quot;deviceID&quot;: &quot;dev:864622040363787&quot;,
    &quot;when&quot;: &quot;2023-01-23T18:29:16.000Z&quot;,
    &quot;value&quot;: { &quot;flow_rate&quot;: 810, &quot;valve_state&quot;: &quot;open&quot; }
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From here, just like with any other field of data returned by a Prisma query, we can access the &lt;code&gt;value&lt;/code&gt; field (and any data contained therein) and do with it what we want. So to get the &lt;code&gt;flow_rate&lt;/code&gt;, you&apos;d simply do something like &lt;code&gt;const flowRate = data[0].value.flow_rate;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Trust me, this ability to easily read and write any sort of JSON data into a field in a database via a Prisma model is really, really handy to have.&lt;/p&gt;
&lt;h3&gt;Handle undefined data&lt;/h3&gt;
&lt;p&gt;Last Prisma tip for this article: be prepared to handle &lt;code&gt;undefined&lt;/code&gt; values returned from Prisma.&lt;/p&gt;
&lt;p&gt;As I alluded to in the earlier tip where I showed the &lt;code&gt;getLatestDeviceAlarm()&lt;/code&gt; query, there is a chance in some scenarios where there are no records that match the parameters in the Prisma query. When this happens, &lt;code&gt;undefined&lt;/code&gt; will be returned by Prisma and if you&apos;re not prepared to handle it, it can throw you for a loop.&lt;/p&gt;
&lt;p&gt;If you&apos;re calling a particular Prisma query for an array of items (like checking which devices have alarm events), be ready to filter out any returned alarm data that is actually &lt;code&gt;undefined&lt;/code&gt; so it doesn&apos;t give you false positives.&lt;/p&gt;
&lt;p&gt;And with that, we&apos;ve covered the majority of the hard won knowledge I gained about Prisma while working with it.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Prisma.io is a very powerful, very popular, JavaScript-friendly ORM for interacting with all sorts of databases. Although the learning curve for it can be a little steep, once you start to get the hang of it, you realize just how fine-grained the control is and how much nicer it is to use when interacting with databases instead of raw SQL queries.&lt;/p&gt;
&lt;p&gt;When my team and I were using it to help us build a valve and flow rate monitoring application, we learned a lot about using some of Prisma&apos;s more advanced features like relational data tables, handling raw JSON fields, and even filtering and sorting results. With Prisma, very quickly you can start to do some amazing stuff that used to be quite complex and required good SQL knowledge.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you learned some new ways to use Prisma on top of your own database-driven web apps. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.prisma.io/&quot;&gt;Prisma.io ORM&lt;/a&gt; site&lt;/li&gt;
&lt;li&gt;Valve flow rate monitor &lt;a href=&quot;https://www.hackster.io/blues-wireless/open-close-valves-and-monitor-flow-rate-remotely-9ac9fc&quot;&gt;Hackster tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Valve flow rate monitor &lt;a href=&quot;https://github.com/blues/app-accelerators/tree/main/09-valve-monitor&quot;&gt;GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Many-to-many_(data_model)&quot;&gt;Many-to-many (m:n) data relationship&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>typescript</category><category>nextjs</category><category>react</category><category>prisma</category></item><item><title>Use CSS to Reveal a Child Element in the DOM by Interacting with the Parent</title><link>https://www.paigeniedringhaus.com/blog/use-css-to-reveal-a-child-element-in-the-dom-by-interacting-with-the-parent/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/use-css-to-reveal-a-child-element-in-the-dom-by-interacting-with-the-parent/</guid><description>When you want to trigger a change in a nested component, just move the :hover higher.</description><pubDate>Sun, 18 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-child-parent-hover/neon-hero.jpg&quot; alt=&quot;Abstract neon lights&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Building &lt;a href=&quot;/&quot;&gt;my own personal site&lt;/a&gt; was a lot of fun because I got to spend time on the little details and subtle touches to give it that little something extra - I know I always appreciate when I see them on other sites. One such detail that I wanted to add was a little arrow that appears right next to the &quot;Read more&quot; link on cards for each of my blog posts when a user hovers over it.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-child-parent-hover/read-more-card.png&quot; alt=&quot;Blog post card with read more arrow visible during hover&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;See this little arrow next to read more? It&apos;s only there when a user mouses over the card.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;At first glance, it sounds like a relatively simple matter for the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:hover&quot;&gt;CSS &lt;code&gt;:hover&lt;/code&gt;&lt;/a&gt; selector, but what I actually wanted to happen was when a user hovered over &lt;em&gt;any&lt;/em&gt; part of my card, the arrow would appear - not just the &quot;Read more&quot; link in the bottom left corner of the card. What I really wanted was for the larger &lt;em&gt;parent container&lt;/em&gt; to trigger a CSS change in a &lt;em&gt;child element&lt;/em&gt;. Getting this to work proved a little trickier to figure out how. But I persevered, and in the end, had a little arrow that appears and disappears depending on a user&apos;s mouse. It&apos;s an understated addition and I like it - almost like an Easter egg.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will show you how to use an interaction that a user takes on a parent element (like hovering over it) in the DOM to make a change in a child element via CSS.&lt;/strong&gt; (I can see lots of situations where something like this could come in pretty handy.)&lt;/p&gt;
&lt;p&gt;Below is a video showing how the arrow next to the &quot;Read more&quot; text on the card appears no matter where a user mouses within the card: title, body, tags - anywhere in the card makes the arrow appear, not just when a user mouses over the link itself.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=gepDm1x5rJQ&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Make a blog post card&apos;s HTML (or JSX)&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-child-parent-hover/blog-post-card-normal.png&quot; alt=&quot;Blog post card normal state&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Before we get to the CSS portion of this post, we first need to set up the general outline of a blog post card&apos;s HTML.&lt;/p&gt;
&lt;p&gt;My site is built with React using the &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby framework&lt;/a&gt;. In my code examples, you&apos;ll see a smidge of React and JSX instead of traditional HTML, but the CSS is really where our focus will be for the majority of this article so don&apos;t worry too much about it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I&apos;ve omitted most of the React-specific code like Hooks, state, functions, etc. to better focus the scope of this article, but if you want to see the full code, you can click the title of any of the code examples to see my full repo files in &lt;a href=&quot;https://github.com/paigen11/paigeniedringhaus.com/tree/master&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is a simplified look at the &lt;code&gt;LatestPosts&lt;/code&gt; component which fetches all the blog posts available on my site, and takes the most recent four to display in a list of cards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/paigeniedringhaus.com/blob/master/src/components/LatestPosts/LatestPosts.js&quot;&gt;&lt;code&gt;LatestPosts.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// other imports for React, components, constants, etc.
import &apos;./LatestPosts.scss&apos;;

const LatestPosts = () =&amp;gt; {
  // state variables here

  // logic to fetch all blog posts, take the most recent 4 posts and format the data to display

  return (
    &amp;lt;div className=&quot;latest-posts-wrapper&quot;&amp;gt;
      {posts.length
        ? posts.map((post, index) =&amp;gt; (
            &amp;lt;div className=&quot;post&quot; key={index}&amp;gt;
                &amp;lt;Link
                  className=&quot;post-link&quot;
                  to={`/blog${post.path}`}
                  key={post.title}
                &amp;gt;
                  &amp;lt;p className=&quot;post-title&quot;&amp;gt;{post.title}&amp;lt;/p&amp;gt;
                  &amp;lt;p className=&quot;post-sub-title&quot;&amp;gt;{post.subTitle}&amp;lt;/p&amp;gt;
                  &amp;lt;PostTags tags={post.tags} /&amp;gt;
                  &amp;lt;p className=&quot;read-more&quot;&amp;gt;
                    Read more &amp;lt;span className=&quot;arrow&quot;&amp;gt;&amp;amp;gt;&amp;lt;/span&amp;gt;
                  &amp;lt;/p&amp;gt;
                &amp;lt;/Link&amp;gt;
            &amp;lt;/div&amp;gt;
          ))
        : null}
      &amp;lt;h2&amp;gt;
        &amp;lt;Link to=&quot;/blog&quot;&amp;gt;View all articles &amp;amp;gt;&amp;lt;/Link&amp;gt;
      &amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
  )
};

export default LatestPosts;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this component code, there&apos;s a single &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; (as required by all React components) that contains all the posts displayed in this list: it&apos;s the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with the &lt;code&gt;latest-posts-wrapper&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;Then, the list of &lt;code&gt;posts&lt;/code&gt; is iterated over with &lt;code&gt;.map()&lt;/code&gt; and each individual post is rendered as an element in the DOM that looks like a card. Each card has a link to the post, the blog title, subtitle, tags, and the text &lt;code&gt;Read more&lt;/code&gt; encouraging users to click through.&lt;/p&gt;
&lt;p&gt;Take note that the &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; element wraps the majority of the blog post content - that will be key soon enough.&lt;/p&gt;
&lt;p&gt;Inside of the final &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag with the class of &lt;code&gt;read-more&lt;/code&gt; is a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tag that surrounds the &lt;code&gt;&amp;amp;gt;&lt;/code&gt; - this is the &lt;a href=&quot;https://www.compart.com/en/unicode/U+003E&quot;&gt;HTML for the greater than sign (&amp;gt;)&lt;/a&gt; which I&apos;m using as a right arrow symbol.&lt;/p&gt;
&lt;p&gt;Finally, there&apos;s another header tag at the bottom of the component, &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, inviting users to go the site page with &lt;a href=&quot;/blog&quot;&gt;all the blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ok, now that the HTML groundwork&apos;s been laid, let&apos;s get on with the CSS and making these arrows appear appear and disappear as required.&lt;/p&gt;
&lt;h2&gt;Add the CSS to the component&lt;/h2&gt;
&lt;p&gt;Now there&apos;s a bit more SCSS associated with the &lt;code&gt;&amp;lt;LatestPosts&amp;gt;&lt;/code&gt; component, but for clarity I&apos;ve omitted the bits not relevant to the blog. If you&apos;d like to see the unabridged version of the code, you can click the name of the file and see it in GitHub.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The code below is actually &lt;a href=&quot;https://sass-lang.com/&quot;&gt;SCSS&lt;/a&gt; instead of pure CSS because I greatly appreciate the additional features like class nesting that it provides, but it should be pretty simple for you to translate this as needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ok, here&apos;s the CSS: now let&apos;s talk about what&apos;s happening.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/paigeniedringhaus.com/blob/master/src/components/LatestPosts/LatestPosts.scss&quot;&gt;&lt;code&gt;LatestPosts.scss&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.latest-posts-wrapper {
  display: flex;
  flex-direction: column;

  .post {
    margin: 10px 20px;
    padding: 20px 30px;
    background-color: white;
    box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px;
    border-radius: 5px;

    .post-link {
      // post-related css

      .arrow {
        opacity: 0;
      }
    }

    .post-link:hover {
      // more post-related css

      .arrow {
        opacity: 1;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you look at this code, take special note of the classes &lt;code&gt;.post-link&lt;/code&gt; and &lt;code&gt;.arrow&lt;/code&gt; - they&apos;re the keys here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.post-link&lt;/code&gt; is the class that surrounds all the content within each card. &lt;code&gt;arrow&lt;/code&gt; is the class that goes with the greater than arrow.&lt;/p&gt;
&lt;p&gt;In order to keep the arrow hidden from view until a user hovers over the card, we&apos;ll set the &lt;code&gt;arrow&lt;/code&gt; class to &lt;code&gt;opacity: 0;&lt;/code&gt;  inside of the &lt;code&gt;post-link&lt;/code&gt; class. Even though it&apos;s still there in the HTML, it&apos;s not visible onscreen.&lt;/p&gt;
&lt;p&gt;Then, when a user hovers over a card, we actually invoke the CSS pseudo class &lt;code&gt;:hover&lt;/code&gt; on the &lt;code&gt;post-link&lt;/code&gt; class and switch the &lt;code&gt;arrow&lt;/code&gt; class&apos; opacity to &lt;code&gt;opacity: 1;&lt;/code&gt;, and that makes the arrow show up as soon as a mouse enters anywhere inside the card.&lt;/p&gt;
&lt;p&gt;Instead of adding the &lt;code&gt;:hover&lt;/code&gt; to the &lt;code&gt;read-more&lt;/code&gt; class that would only make the arrow show when a user mouses over the &quot;Read more&quot; link, we add the &lt;code&gt;:hover&lt;/code&gt; higher up in the card element which makes the arrow show up almost anywhere the user&apos;s mouse is on the card. Voila!&lt;/p&gt;
&lt;p&gt;And that&apos;s all there is to it: simply shifting the &lt;code&gt;:hover&lt;/code&gt; pseudo class that surrounds the child element further up in the larger parent component can make it happen.&lt;/p&gt;
&lt;p&gt;Once more, here&apos;s what the finished product looks like: hover almost anywhere on the card the arrow appears, mouse off of it, the arrow disappears again.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=gepDm1x5rJQ&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;One of the coolest parts of being a web developer is bringing things to life online, and even though I am not a designer, it was really fun to flex my design muscles as I built my own site, and add all sorts of little touches that I liked.&lt;/p&gt;
&lt;p&gt;Things like gradients here and there, subtle animations, and the like: nothing too dramatic mind you, but small things that I always appreciate when I see it on other sites.&lt;/p&gt;
&lt;p&gt;Not too long ago, a touch I wanted to add was when a user moused over one of my blog cards they&apos;d see a little arrow next to the &quot;Read more&quot; prompt pop up. But I wanted the arrow to pop up anywhere a mouse might hover over the card - not just when they got the &quot;Read more&quot; link in the bottom of the card.&lt;/p&gt;
&lt;p&gt;By employing the &lt;code&gt;:hover&lt;/code&gt; pseudo-class on one of the card&apos;s classes that wraps all of the card&apos;s content (and not just the &quot;Read more&quot; link), I was able to achieve this effect and it didn&apos;t take very much effort at all. Pretty sweet.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope this trick to affect a child element&apos;s CSS by interacting with a parent or grandparent element comes in as handy for you as it does for me.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/paigeniedringhaus.com/tree/master&quot;&gt;Personal site, GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:hover&quot;&gt;MDN Docs, CSS hover pseudo-class&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>react</category><category>gatsby</category><category>css</category></item><item><title>Create Upsert Yourself for Amazon Redshift Databases</title><link>https://www.paigeniedringhaus.com/blog/create-upsert-yourself-for-amazon-redshift-databases/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/create-upsert-yourself-for-amazon-redshift-databases/</guid><description>With a separate staging table, inserting and updating data in PostgreSQL is straightforward.</description><pubDate>Sat, 19 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/upsert-redshift/database-hero.jpg&quot; alt=&quot;Digital sign boards displaying data hanging from the ceiling&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;One of the many things I enjoy about working at a startup is the variety of people I get to work with across the company and the interesting problems I get to solve. A few months back, the marketing team was working on improving our analytics reporting and wanted to store data in our Amazon Redshift database that could then be used to build more detailed reports.&lt;/p&gt;
&lt;p&gt;While this would normally be a relatively straightforward &lt;code&gt;INSERT&lt;/code&gt; SQL request if all the data was brand new, one thing that made it a little tricky was that I needed to update certain rows in the data table AND insert new rows as well. Normally, I&apos;d use an &lt;code&gt;UPSERT&lt;/code&gt; SQL statement to do both things at once, but Redshift doesn&apos;t support &lt;code&gt;UPSERT&lt;/code&gt; statements, so I had to get a little more creative to make this happen manually. With some research and a lot of testing, I learned that by using a temporary data table and a few SQL statements strung together it was possible, and it wasn&apos;t as complicated as I thought it would be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let&apos;s look at how to create our own version of an &lt;code&gt;UPSERT&lt;/code&gt; SQL statement in a PostgreSQL-based Amazon Redshift database, updating data that already exists and adding new data as well.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Amazon Redshift&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/dg/c_redshift-sql.html&quot;&gt;Redshift&lt;/a&gt; is Amazon Web Service&apos;s PostgreSQL-based cloud data warehouse built with added functionality to manage very large datasets and support high-performance analysis and reporting of those data.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It&apos;s similar to Google&apos;s BigQuery or Microsoft&apos;s Azure cloud data warehouses, if you&apos;ve ever used either of those in the past.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And although Redshift is based on &lt;a href=&quot;https://www.postgresql.org/&quot;&gt;PostgreSQL&lt;/a&gt; it does have some &lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/dg/c_redshift-and-postgres-sql.html&quot;&gt;differences&lt;/a&gt;, one of those being: a lack of &lt;code&gt;UPSERT&lt;/code&gt; functionality.&lt;/p&gt;
&lt;h3&gt;No built in UPSERT functionality&lt;/h3&gt;
&lt;p&gt;Amazon acknowledges this shortcoming readily enough, and suggests using a &lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/dg/c_best-practices-upsert.html&quot;&gt;staging table to perform a merge&lt;/a&gt;. This sounds sensible, but the &lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/dg/t_updating-inserting-using-staging-tables-.html&quot;&gt;AWS documentation&lt;/a&gt; on how exactly to do this is a little sparse.&lt;/p&gt;
&lt;p&gt;So after I figured it out, I wanted to share it, with code examples, for each step. Let&apos;s get to it.&lt;/p&gt;
&lt;h2&gt;Create your own UPSERT&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This tutorial assumes you&apos;re familiar with basic SQL syntax. If you wish to reference any of the commands in the article, I recommend checking the &lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/dg/c_SQL_commands.html&quot;&gt;Redshift SQL command docs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If there&apos;s no native &lt;code&gt;UPSERT&lt;/code&gt;, we&apos;ll make our own. There&apos;s more than one way to recreate &lt;code&gt;UPSERT&lt;/code&gt; but the option I chose to go with essentially deletes all the existing rows in the production table that match rows in the temporary table, then inserts all the data from the temporary table into the production table.&lt;/p&gt;
&lt;p&gt;It sounds complex (because it is a bit), but it&apos;s not as bad once each step in the process is broken down.&lt;/p&gt;
&lt;p&gt;For this article, I&apos;ll set up a table (USER_UPDATES) that&apos;s a copy of a fictitious USERS table. In USER_UPDATES, I&apos;ll modify some existing data in the table (updates), and create some new data in the table (inserts), then we&apos;ll get to updating that newly modified data into the USERS table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisite data modification setup&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Create a sample table as a copy of the fake USERS table 

CREATE TABLE user_updates AS
SELECT * FROM users;

-- Change every third row so we have updated users

UPDATE user_updates
SET 
    firstname = upper(firstname),
    lastname = upper(lastname),
    lastseen = &apos;2022-11-13&apos;
AND mod(userid, 3) = 0;;

-- Add some new rows of users so we have insert examples 
-- This example creates a duplicate of every fifth row of user data

INSERT INTO user_updates
SELECT 
      (userid + 127) AS userid, 
      firstname, 
      lastname, 
      getdate() AS lastseen,
FROM user_updates
AND mod(userid, 5) = 0;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that there&apos;s some updated user data, it&apos;s time to add it back to the USERS table, while ensuring the user data for users already in the table gets overwritten and updated, and the new user data gets added.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Make a staging table&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first thing we&apos;ll need to do is write a SQL command that creates a temporary table that is an exact copy of the production table the data will eventually be written into.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Create temporary table that&apos;s a duplicate of the production users table

CREATE TEMP TABLE temp_users (LIKE users);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating a temporary table is almost the same as creating a regular table in SQL (just add &lt;code&gt;TEMP&lt;/code&gt;), and instead of having to list out each column in detail, we can simply use &lt;code&gt;LIKE &amp;lt;table_name&amp;gt;&lt;/code&gt; to tell SQL to make this table&apos;s columns a copy of the table it will eventually add its data to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Insert the new data into the temp table&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With our temp table now created, it&apos;s time to insert the modified data in the prerequisite setup step into that temp table. In this INSERT statement, we&apos;ll take all the data from the USER_UPDATES table and insert it into the temporary TEMP_USERS table.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Take all the data from the user_updates table and insert it into the temporary table

INSERT INTO temp_users
SELECT
       userid,
       firstname,
       lastname,
       lastseen,
FROM user_updates;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, all the data from USER_UPDATES is put in the TEMP_USERS table for the moment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Begin the transaction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;transaction&lt;/strong&gt; is a unit of work done in a database - the work can be anything from creating tables to deleting them. The transaction taking place here, will be deleting particular rows of user data from the production table USERS (these are existing users who have updated data in the temp table) before adding their new data into the table.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Start the work of deleting existing user data from the table and adding the new data instead

BEGIN TRANSACTION;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The thing about transactions in PostgreSQL is that a commit is implicitly performed at the end of the statement as long as the execution is successful. If the execution fails, a rollback is done instead. This becomes especially convenient because if new user data fails to get added to the USERS table, it will rollback and automatically replace the old user data back in the table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Delete the rows in the permanent table that need to be replaced with new data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once the transaction&apos;s begun, the first thing to do is delete any rows from the permanent table (USERS) where the user ID matches a user ID in the TEMP_USERS table.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Delete the users from the database whose data needs to be updated

DELETE FROM users 
USING 
    temp_users 
WHERE users.userid = temp_users.userid;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By doing this &lt;code&gt;DELETE&lt;/code&gt; first, we ensure that there will be no duplicate user data when the new data is added to the USERS table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Insert all the data from the temp table to the permanent table&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now it&apos;s safe to insert everything from the TEMP_USERS table into the USERS table, without fear of duplicating existing user data.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Add all the user data from the temp table to the prod table 

INSERT INTO users
SELECT * FROM temp_users;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;6. End the transaction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once all the parts of the transaction have completed successfully, it can be ended just like it began.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- End the work

END TRANSACTION;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&apos;s one last thing to do now: a little clean up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7. Delete the temp table&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Finally, since the TEMP_USERS table has done its job and there&apos;s no further need for it, it&apos;s dropped (deleted).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Delete the temporary table now that its job is done

DROP TABLE temp_users;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating our own &lt;code&gt;UPSERT&lt;/code&gt;&apos;s not so bad once each of the steps are broken down and explained.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Amazon Redshift is a popular, powerful data warehouse, but even though it&apos;s based on PostgreSQL, it lacks some of the nicer features like &lt;code&gt;UPSERT&lt;/code&gt;, which is exactly the feature I needed to help out one of the teams at work.&lt;/p&gt;
&lt;p&gt;Since I needed to update a data table with new information and update existing data in that table, I needed something more than a simple SQL &lt;code&gt;INSERT&lt;/code&gt;. Lucky for me, creating &lt;code&gt;UPSERT&lt;/code&gt; functionality wasn&apos;t as difficult as I thought it would be with the help of a temporary table and a couple of targeted &lt;code&gt;DELETE&lt;/code&gt; and &lt;code&gt;INSERT&lt;/code&gt; queries. Not too shabby.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you find it helpful to see how to create your own SQL &lt;code&gt;UPSERT&lt;/code&gt; function. This probably won&apos;t be the first or the last time you need to insert and update data into a table, and it&apos;s nice to have options for how best to accomplish it.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/dg/t_updating-inserting-using-staging-tables-.html&quot;&gt;AWS Redshift Docs, Updating and Inserting New Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/dg/c_redshift-and-postgres-sql.html&quot;&gt;AWS Redshift Docs, Amazon Redshift and PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/&quot;&gt;PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>sql</category><category>postgresql</category><category>aws</category></item><item><title>Rely on JavaScript&apos;s Intersection Observer to Execute Code When in View (or Not)</title><link>https://www.paigeniedringhaus.com/blog/rely-on-javascripts-intersection-observer-to-execute-code-when-in-view-or-not/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/rely-on-javascripts-intersection-observer-to-execute-code-when-in-view-or-not/</guid><description>Stop a video playing or animate an element onscreen - the Intersection Observer API is highly versatile.</description><pubDate>Sun, 23 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/intersection-observer/intersection-hero.jpg&quot; alt=&quot;Overhead time lapse image of intersection at night&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;It&apos;s the small things that matter&lt;/h2&gt;
&lt;p&gt;When dealing with the business of building websites on a daily basis, I can&apos;t help but start to notice that what separates the good sites from the great ones, is that the great ones pay close attention to the small details.&lt;/p&gt;
&lt;p&gt;Little page animations, a button that disables after form submission, or when elements on the page only reveal themselves when the user scrolls to that portion of the page. You might not immediately recognize that this sort of nicety is there to improve the user experience, but it becomes more obvious when it&apos;s missing: a video that won&apos;t stop playing even after you&apos;ve scrolled away, an error message that you can&apos;t see until you scroll up the page from the submit button that failed, there&apos;s a million little annoyances like this.&lt;/p&gt;
&lt;p&gt;Recently, I was building a new About Us page for my company&apos;s marketing site, and in the mockup the designer gave me, there were some cool animations that showed a series of cards toward the bottom of the page that slid into view only when the user had scrolled far enough down the page to see them. It looked really slick, and it turns out that nowadays just a little CSS and JavaScript was all that was needed to make this possible, and a host of other handy interactions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how the JavaScript Intersection Observer API can easily control how elements react based on their visibility in the viewport.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Below is a video showing how the cards at the bottom of this page don&apos;t animate and slide into view until the viewer has reached them: that&apos;s one example of Intersection Observer at work.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=hGoPT3gLRyw&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Intersection Observer&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;Intersection Observer API&lt;/a&gt;&lt;/strong&gt;, if you&apos;re not familiar with it, provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or a top-level document&apos;s viewport.&lt;/p&gt;
&lt;p&gt;Put simply: it can tell if an element is in view or not, and cause things to act accordingly.&lt;/p&gt;
&lt;p&gt;Before Intersection Observer existed this type of intersection detection was clunky with lots of event handlers and loops in the main thread, potentially causing performance problems as well as cluttered code.&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;intersectionObserver&lt;/code&gt;, on the other hand, is created and assigned a callback function that runs whenever a threshold is crossed in one direction or the other for a particular element in the DOM that it is assigned to &quot;observe.&quot;&lt;/p&gt;
&lt;p&gt;It can also be given an optional series of &lt;code&gt;options&lt;/code&gt; that tell it when to invoke the callback function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;root&lt;/code&gt; - the element used as the viewport for checking visibility of the target.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;rootMargin&lt;/code&gt; - a set of values around the root element&apos;s bounding box to grow or shrink before computing intersections.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;threshold&lt;/code&gt; - a number that indicates at what percentage of the target&apos;s visibility the observer&apos;s callback function should be executed. (For example, the default 0 means as soon as even one pixel is visible the callback will run, and 1.0 means the threshold isn&apos;t considered passed until every pixel of an element is visible).&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;There&apos;s plenty more nuance to how the intersection observer can be fine tuned and leveraged to cool effect, but what I&apos;ve covered above should be enough to help you follow the examples I&apos;ll be demoing. If you&apos;d like to learn more, I&apos;d recommend reading the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;docs from Mozilla&lt;/a&gt;, which include some great code examples to play with.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All of this writing may not make perfect sense yet, so let&apos;s look at some code examples where you can see intersection observers in action.&lt;/p&gt;
&lt;h2&gt;Intersection Observer code examples&lt;/h2&gt;
&lt;p&gt;There&apos;s a couple of different scenarios where intersection observer is being used on the marketing site in unique ways, and I&apos;m going to show both of them to you to help demonstrate how flexible it can be.&lt;/p&gt;
&lt;h3&gt;Run animations only when the user will see the result&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/intersection-observer/quote-cards.png&quot; alt=&quot;The cards with customer quotations designed to slide into view with the help of intersection observer&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;These cards slide into view once the user can see them on screen with the help of intersection observer.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The first example I&apos;ll show you is the one I described in the introduction to this blog: it animates a series of cards on-screen, but only when the user has scrolled down the page far enough to view the cards.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The site code I&apos;m referencing is written in &lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt;, a popular, open source, static site generator written in Go. Like many SSGs, it relies on &lt;a href=&quot;https://gohugo.io/templates/introduction/&quot;&gt;templates&lt;/a&gt; to render the majority of the site&apos;s HTML, and for the purposes of clarity in this article, I&apos;ve replaced Go variables injected into the template with the generated HTML.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&apos;s look first at the HTML and JavaScript for the three cards being rendered in the page. This code snippet shows just one of the cards, but it&apos;s the same for all of them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;quote-cards.html&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;row&quot;&amp;gt;
    &amp;lt;div class=&quot;col-lg-4 card-group customer-quote-card&quot;&amp;gt;
      &amp;lt;div class=&quot;card&quot;&amp;gt;
        &amp;lt;div class=&quot;card-body&quot;&amp;gt;
          &amp;lt;p class=&quot;customer-quote-text&quot;&amp;gt;
            &amp;lt;img 
              class=&quot;customer-quote-img&quot; 
              src=&quot;/images/about/quote-left-solid.svg&quot; 
              alt=&quot;decorative left quotation mark&quot;
            /&amp;gt;
            &quot;This is a quote here.&quot;
            &amp;lt;img
              class=&quot;customer-quote-img&quot;
              src=&quot;/images/about/quote-right-solid.svg&quot; 
              alt=&quot;decorative right quotation mark&quot;
            /&amp;gt;
          &amp;lt;/p&amp;gt;
          &amp;lt;p class=&quot;customer-quote-source&quot;&amp;gt;
            Source of the quote
          &amp;lt;/p&amp;gt;
          &amp;lt;p class=&quot;customer-quote-source-role&quot;&amp;gt;
            Role and company the source works for
          &amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    /* this code keeps the cards from animating into view until a user&apos;s scrolled down far enough to see them */
    var quoteCard = document.querySelectorAll(&quot;.customer-quote-card&quot;);

    var observerOptions = {
      threshold: 0.7,
    };

    var callback = (entries) =&amp;gt; {
      entries.forEach((entry) =&amp;gt; {
        if (entry.isIntersecting) {
          entry.target.classList.add(&quot;animated&quot;);
        }
      });
    };

    var quoteCardObserver = new IntersectionObserver(callback, observerOptions);

   // loop through each card available and add this observer to it
    quoteCard.forEach((card) =&amp;gt; {
      quoteCardObserver.observe(card);
    });
  &amp;lt;/script&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The HTML in the snippet outlines the &lt;code&gt;card&lt;/code&gt; element and the details contained within that card: the quote, the name, and the company and role of the person being quoted.&lt;/p&gt;
&lt;p&gt;The JavaScript at the bottom of the snippet is where intersection observer comes into play. First, a variable named &lt;code&gt;quoteCard&lt;/code&gt; is created to target the &lt;code&gt;customer-quote-card&lt;/code&gt; CSS class on the &lt;code&gt;div&lt;/code&gt; that surrounds each card.&lt;/p&gt;
&lt;p&gt;Then, the &lt;code&gt;observerOptions&lt;/code&gt; variable is declared with a &lt;code&gt;threshold&lt;/code&gt; of &lt;code&gt;0.7&lt;/code&gt; - this will be passed to the &lt;code&gt;IntersectionObserver&lt;/code&gt; object shortly, and will require that at least 70% of the card be visible before animating it into view.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;callback()&lt;/code&gt; function is defined, which loops through a list of items and for each item, if the item &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry/isIntersecting&quot;&gt;&lt;code&gt;isIntersecting&lt;/code&gt;&lt;/a&gt; (a boolean value which is true if the target element intersects with the intersection observer&apos;s root), the &lt;code&gt;animated&lt;/code&gt; class is added to that item&apos;s CSS classes. Essentially, this function will add the CSS class to each card necessary to trigger the animation and bring them into view on the page when the &lt;code&gt;isIntersecting&lt;/code&gt; threshold is reached.&lt;/p&gt;
&lt;p&gt;Next, a &lt;code&gt;new IntersectionObserver&lt;/code&gt; instance is instantiated as &lt;code&gt;quoteCardObserver&lt;/code&gt; and the &lt;code&gt;callback()&lt;/code&gt; and &lt;code&gt;observerOptions&lt;/code&gt; are passed in.&lt;/p&gt;
&lt;p&gt;Finally, for each &lt;code&gt;quoteCard&lt;/code&gt; object, the &lt;code&gt;quoteCardObserver&lt;/code&gt; function is attached to the card.&lt;/p&gt;
&lt;p&gt;With the HTML and JavaScript is set up, it&apos;s time to add the CSS (remember that &lt;code&gt;animated&lt;/code&gt; CSS class mentioned earlier?) to animate the cards on screen when the intersection observer&apos;s &lt;code&gt;callback()&lt;/code&gt; function fires.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;about.scss&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card-group {
  opacity: 0;
}

.animated {
  animation: slideLeft 1.5s;
  animation-delay: 0s;
  animation-fill-mode: backwards;
  opacity: 1;
}

@keyframes slideLeft {
  0% {
    transform: translateX(100%);
    opacity: 0;
  }

  100% {
    transform: translateX(0);
    opacity: 1;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the SCSS code, the &lt;code&gt;card-group&lt;/code&gt; class starts out with an opacity of 0 to keep the cards hidden from view.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;animated&lt;/code&gt; class is created with an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;&lt;code&gt;animation&lt;/code&gt; property&lt;/a&gt; designating the &lt;code&gt;slideLeft&lt;/code&gt; keyframe with a duration of 1.5 seconds.&lt;/p&gt;
&lt;p&gt;In addition to the &lt;code&gt;animation&lt;/code&gt; property, the &lt;code&gt;animation-delay&lt;/code&gt;, &lt;code&gt;animation-fill-mode&lt;/code&gt; and &lt;code&gt;opacity&lt;/code&gt; are also defined on this class.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;animation-delay: 0;&lt;/code&gt; ensures the animation will play immediately,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;animation-fill-mode: backwards;&lt;/code&gt; means the element will apply the values defined in the &lt;code&gt;0%&lt;/code&gt; keyframe as soon as it is applied to the target (i.e. the card will stay hidden with an opacity of 0 as soon as it&apos;s rendered in the DOM).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opacity: 1;&lt;/code&gt; once the &lt;code&gt;slideLeft&lt;/code&gt; keyframe animation has ended, the card will have 100% visibility on-screen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And last but not least, the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes&quot;&gt;&lt;code&gt;@keyframes&lt;/code&gt;&lt;/a&gt; animation sequence is defined. There are only two keyframes defined (&lt;code&gt;0%&lt;/code&gt; and &lt;code&gt;100%&lt;/code&gt;) to indicate the cards start with no opacity (&lt;code&gt;opacity: 0;&lt;/code&gt;) and 100% off the screen to the right (&lt;code&gt;transform: translateX(100%);&lt;/code&gt;, and when it ends they&apos;ll be completely visible (&lt;code&gt;opacity: 1;&lt;/code&gt;) and on screen (&lt;code&gt;transform: translateX(0);&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In the end, it produces this effect:&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=hGoPT3gLRyw&quot; /&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CSS animations are beyond the scope of this tutorial, but if want to study them in more depth, I&apos;d recommend starting &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot;&gt;here&lt;/a&gt; - they&apos;re very cool!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great! That&apos;s one example of how intersection observer can be used to control animation timing so a user will see it. Now let&apos;s consider another option.&lt;/p&gt;
&lt;h3&gt;Play a video only when the user can see it&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/intersection-observer/notehub-video.png&quot; alt=&quot;Video modal that only plays the video while the modal is visible in the viewport.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This video will only play when it is visible to the user and they click the play button. If user dismisses the modal by clicking somewhere else on the page, the modal will hide and video stop playing.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The second example I&apos;ll share concerns a video modal that stops playing when the modal is not visible. When a button is clicked, the modal does a full page takeover where the video player sits at the center of the viewport. If the user clicks somewhere besides the video while it&apos;s playing, the modal is dismissed and hidden from view and the video will stop playing. This is possible because of intersection observer.&lt;/p&gt;
&lt;p&gt;Let&apos;s take a look at the code that makes this happen.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;video_modal.html&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;modal&quot;&amp;gt;
  &amp;lt;div class=&quot;modal-dialog&quot;&amp;gt;
    &amp;lt;div class=&quot;modal-content&quot;&amp;gt;
      &amp;lt;div class=&quot;modal-header&quot;&amp;gt;
        &amp;lt;button
          type=&quot;button&quot;
          class=&quot;close&quot;
          data-dismiss=&quot;modal&quot;
          aria-label=&quot;Close&quot;
        &amp;gt;
          &amp;lt;span aria-hidden=&quot;true&quot;&amp;gt;&amp;amp;times;&amp;lt;/span&amp;gt;
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;modal-body embed-responsive-16by9&quot;&amp;gt;
        &amp;lt;iframe
          width=&quot;560&quot;
          height=&quot;315&quot;
          src=&quot;https://www.youtube.com/embed/4q1qqzDzJeQ&quot;
          title=&quot;YouTube video player&quot;
          frameborder=&quot;0&quot;
          allowfullscreen
        &amp;gt;&amp;lt;/iframe&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    var iframe = document.querySelector(&quot;iframe&quot;);
    var ytsrc = iframe.src;

    var observer = new IntersectionObserver(
      function (entries) {
        // isIntersecting is true when element and viewport are overlapping
        // isIntersecting is false when element and viewport don&apos;t overlap
        if (entries[0].isIntersecting === false) iframe.src = &quot;&quot;;
        else iframe.src = ytsrc;
      }
    );

    observer.observe(iframe);
  &amp;lt;/script&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, a video modal and an iframe video embed from YouTube are created in the HTML.&lt;/p&gt;
&lt;p&gt;In the JavaScript directly below it, an &lt;code&gt;iframe&lt;/code&gt; variable is defined focused on the &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; HTML element, and a &lt;code&gt;ytsrc&lt;/code&gt; variable is defined to keep track of the the iframe&apos;s video source - this will be used inside the intersection observer&apos;s callback.&lt;/p&gt;
&lt;p&gt;Next, a new intersection observer is initialized (&lt;code&gt;observer&lt;/code&gt;), and this one&apos;s callback function iterates through the list of &lt;code&gt;entries&lt;/code&gt; it receives, and if the first &lt;code&gt;entry&lt;/code&gt; in the list is &lt;em&gt;not&lt;/em&gt; intersecting (i.e. the video iframe and the viewport aren&apos;t overlapping, or rather, the modal&apos;s not visible to the viewer), the iframe&apos;s &lt;code&gt;src&lt;/code&gt; is set to an empty string so no video URL is available to play. If the &lt;code&gt;entry&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; intersecting (i.e. the video modal is visible in the viewport), the iframe&apos;s &lt;code&gt;src&lt;/code&gt; is set to the &lt;code&gt;ytsrc&lt;/code&gt; variable: the actual YouTube video URL.&lt;/p&gt;
&lt;p&gt;Finally, the new &lt;code&gt;observer&lt;/code&gt; object is told to observe the &lt;code&gt;iframe&lt;/code&gt; variable, so whenever the &lt;code&gt;iframe&lt;/code&gt; is in the viewport (e.g. when a user clicks a button to open the modal), its video source is the YouTube video. Whenever that changes (and the modal is hidden from view), the video URL is set to an empty string.&lt;/p&gt;
&lt;p&gt;And this results in no video continuing to play when the video modal is dismissed.&lt;/p&gt;
&lt;p&gt;To see how it works, watch this video with the sound on to hear how the audio ceases when the modal is dismissed and hidden from view.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=sKUxi9RTya8&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;Pretty useful, huh?&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Small details can make for great user experiences, whether it&apos;s a video that stops playing once a user&apos;s scrolled past it or an animation that only happens when the elements are in view for a user.&lt;/p&gt;
&lt;p&gt;While these little interactions once required a good deal of extra code and awareness of how long the main thread might be blocked, the introduction of the Intersection Observer API simplified things dramatically. Now, a single object allows a developer to specify an element to observe, a callback function to do something, and even fine tuned the function to only fire when certain conditions are met. It&apos;s quite useful in many scenarios, actually.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope this demo of how to use the Intersection Observer API helps you out in your future endeavors. I know I really appreciate great website experiences, and it&apos;s always good to have another tool in the arsenal to make them possible.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;MDN Docs, Intersection Observer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;MDN Docs, CSS Animations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>css</category><category>javascript</category></item><item><title>Change SVG Color with Help from CSS Filter</title><link>https://www.paigeniedringhaus.com/blog/change-svg-color-with-help-from-css-filter/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/change-svg-color-with-help-from-css-filter/</guid><description>We no longer need to bother designers when the SVG&apos;s color is slightly off: just filter it.</description><pubDate>Mon, 05 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/svg-color-css-filter/filter.jpg&quot; alt=&quot;A hand holding a tinted lens that changes the color of the sea beyond from blue to purple&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Working with talented designers is such a pleasure as a web developer. Not only do they come up with beautiful layouts for pages and simplify complex concepts into easy to understand visuals, but oftentimes they provide me the opportunity to learn a new web development technique to bring their visions to life.&lt;/p&gt;
&lt;p&gt;I recently had such an opportunity while building a new About Us page for my company&apos;s marketing site. In the mockup, the page had a large quote by our founder, and the quotation marks around the text were stylized SVG images. When the designer gave me the SVGs, however, they came in a standard black color which didn&apos;t match the blue color in the design.&lt;/p&gt;
&lt;p&gt;Before I asked my designer to recreate new SVGs to match the color in the design (or attempt to alter the SVG&apos;s color myself), I did a little digging online and found a useful CSS technique: &lt;code&gt;filter&lt;/code&gt;. With &lt;code&gt;filter&lt;/code&gt;, I was able to change the SVG&apos;s color myself - and change it to any hue I desired - no bothering my designer required.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this post, we&apos;ll explore CSS &lt;code&gt;filter&lt;/code&gt; and see how it can be used to alter SVG image colors to match colors in mockups.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ll even share a handy website that will generate &lt;code&gt;filter&lt;/code&gt; combinations to exactly replicate CSS hex colors.&lt;/p&gt;
&lt;p&gt;Below is a video showing how the CSS filter affects the color of quotation mark SVGs - note how they change from black to light blue.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=yvoxS52JyoM&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;CSS Filter&lt;/h2&gt;
&lt;p&gt;Before I share the solution, let&apos;s take a closer look at CSS &lt;code&gt;filter&lt;/code&gt; - it wasn&apos;t a technique that I was familiar with prior to this.&lt;/p&gt;
&lt;p&gt;According to the MDN documents about &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter&quot;&gt;CSS &lt;code&gt;filter&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, it&apos;s used to apply graphical effects like blur or color shift to an element. Some standard CSS functions include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;blur&lt;/code&gt; -  make the image fuzzier or sharper.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contrast&lt;/code&gt; - adjust the contrast of an image&apos;s colors.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grayscale&lt;/code&gt; - convert an image to grayscale.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drop-shadow&lt;/code&gt; - apply a blurred, offset version of the image, drawn in a specific color and composited below the image.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to these standard functions, an SVG can also be referenced with a URL to an SVG filter element - essentially, a custom filter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This article doesn&apos;t go into great detail about how the filter functions work because they&apos;re quite complex. If you want a full rundown of what they are and how they work, I recommend checking out the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter#functions&quot;&gt;Mozilla documentation&lt;/a&gt; for more info.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now what the documents fail to highlight is that multiple of these functions can be combined &lt;em&gt;together&lt;/em&gt; in a single function to great effect - like, say, changing an SVG&apos;s color, which is what we&apos;re going to cover next.&lt;/p&gt;
&lt;h2&gt;Filters in action&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/svg-color-css-filter/svg-color-hero.png&quot; alt=&quot;The quote complete with SVG quotation marks colored using CSS filter&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The final quote with its light blue SVG quotation marks.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Ok, let me show you how we can use these filter functions in your own code. The first thing you&apos;ll need is some HTML elements to apply this CSS to.&lt;/p&gt;
&lt;h3&gt;Set up the HTML, SVGs, and the img-quote class&lt;/h3&gt;
&lt;p&gt;The site I was working on happens to be made with &lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt;, a popular, open source, static site generator written in Go. Although it&apos;s written in Go, it relies on &lt;a href=&quot;https://gohugo.io/templates/introduction/&quot;&gt;templates&lt;/a&gt; to render the majority of the site&apos;s HTML, so the example code below should look relatively familiar to you if you know HTML.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on templates:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;ve ever used React&apos;s JSX components, Node.js with Pug or Handlebars, or Jekyll - Hugo&apos;s templates are similar: HTML elements with Go variables and functions sprinkled in with &lt;code&gt;{{ }}&lt;/code&gt; to render the correct information wherever the template&apos;s injected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&apos;s the code below for the quote section. For the purposes and clarity of this post, I&apos;ve replaced the Go variables injected into the template with the generated HTML.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;quote-template.html&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;section class=&quot;quote-section&quot;&amp;gt;
      &amp;lt;div class=&quot;container&quot;&amp;gt;
        &amp;lt;div class=&quot;row&quot;&amp;gt;
          &amp;lt;div class=&quot;col-12&quot;&amp;gt;
            &amp;lt;h2 class=&quot;text-center quote-text&quot;&amp;gt;
              &amp;lt;img
                class=&quot;quote-img&quot;
                src=&quot;/images/about/quote-left-solid.svg&quot;
                alt=&quot;decorative left quotation mark&quot;
              /&amp;gt;
              Complexity kills. It sucks the life out of developers.
              &amp;lt;div /&amp;gt;
              It makes products difficult to plan, build, test, deliver, and support.
              &amp;lt;img
                class=&quot;quote-img&quot;
                src=&quot;/images/about/quote-right-solid.svg&quot;
                alt=&quot;decorative right quotation mark&quot;
              /&amp;gt;
            &amp;lt;/h2&amp;gt;
            &amp;lt;div class=&quot;text-center&quot;&amp;gt;
              &amp;lt;h4 class=&quot;text-center quote-source&quot;&amp;gt;
                Ray Ozzie
                &amp;lt;span class=&quot;quote-source-role&quot;&amp;gt;
                  Founder &amp;amp; CEO, Blues Wireless
                &amp;lt;/span&amp;gt;
              &amp;lt;/h4&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this section of code is relatively small, it still deserves discussion. In addition to the HTML elements, there&apos;s quite a few CSS classes present, many of which are courtesy of &lt;strong&gt;&lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt;&lt;/strong&gt;, one of the original open source CSS frameworks for responsive web development.&lt;/p&gt;
&lt;p&gt;Among the custom classes like &lt;code&gt;quote-section&lt;/code&gt; and &lt;code&gt;quote-img&lt;/code&gt;, which I used for custom styling, there are ones like &lt;code&gt;container&lt;/code&gt;, &lt;code&gt;row&lt;/code&gt;, &lt;code&gt;col-12&lt;/code&gt;, and &lt;code&gt;text-center&lt;/code&gt;. All of the latter examples are Bootstrap classes and serve to do things like have the quote text take up the entire width of the page: &lt;code&gt;col-12&lt;/code&gt;, or center the text inside the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;: &lt;code&gt;text-center&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These classes are beside the point though, the one you want to focus on for this post is the &lt;strong&gt;&lt;code&gt;quote-img&lt;/code&gt;&lt;/strong&gt; class attached to the two &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; elements: these are the two quotation mark SVGs bookending the quote.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;quote-img&lt;/code&gt; class is how we&apos;re going to attach the CSS &lt;code&gt;filter&lt;/code&gt; functions to both quotation mark SVGs and make sure they&apos;re both the correct color to match the design.&lt;/p&gt;
&lt;h3&gt;Add the CSS filter to quote-img&lt;/h3&gt;
&lt;p&gt;As I mentioned above, the SVGs my designer gave me were standard black, but in the design mockup, the quotes were a lighter shade of blue: hex color &lt;code&gt;#94BBD0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When I started looking for a solution to change the color of these SVGs, I came across &lt;a href=&quot;https://stackoverflow.com/questions/22252472/how-to-change-the-color-of-an-svg-element/53336754#53336754&quot;&gt;this answer on StackOverflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While there were suggestions in the answer thread that amounted to modifying the SVG&apos;s source code directly (not something I was keen to do), but luckily I didn&apos;t have to.&lt;/p&gt;
&lt;p&gt;The solution I landed on not only illustrated how CSS &lt;code&gt;filter&lt;/code&gt; could be used to modify the SVG&apos;s color, it also linked to a &lt;strong&gt;&lt;a href=&quot;https://codepen.io/sosuke/pen/Pjoqqp&quot;&gt;helpful CodePen&lt;/a&gt;&lt;/strong&gt;, which allowed me to input the hex color I wanted (&lt;code&gt;#94BBD0&lt;/code&gt;), and it spit out the exact CSS filter combination to create it (plus an accuracy reading of just how close to perfect the CSS filter code was to matching the original hex color). And all I had to do was copy the code produced to use in my own CSS file. What an amazing timesaver!&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/svg-color-css-filter/css-svg-to-hex-converter.png&quot; alt=&quot;CodePen to translate any SVG to a particular hex color&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;CodePen to translate any SVG to a particular hex color: https://codepen.io/sosuke/pen/Pjoqqp. Bless the developer who went to the trouble of making this!&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;So in my own SCSS file that was added to help style the About Us page&apos;s HTML, add the following class and the code copied from the CSS filter code generator.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Even though this file shown in the example code is SCSS instead of pure CSS, for this post it shouldn&apos;t make a difference. It should be a direct 1:1 comparison.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;about.scss&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  .quote-img {
    height: 26px;
    filter: invert(84%) sepia(9%) saturate(1100%) hue-rotate(165deg)
      brightness(88%) contrast(83%);
    margin-bottom: 16px;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A careful combination of multiple filter functions like &lt;code&gt;invert&lt;/code&gt;, &lt;code&gt;sepia&lt;/code&gt; and others, and voila - the exact shade of blue to match the hex code.&lt;/p&gt;
&lt;p&gt;To make the image quotes the proper size and placement in relation to the text, in addition to changing their color, I also needed to set the height of the SVGs to &lt;code&gt;26px&lt;/code&gt; and give them a bottom margin of &lt;code&gt;16px&lt;/code&gt; to push them up to look like they were surrounding the text instead of sitting centered inline with the text.&lt;/p&gt;
&lt;p&gt;And now the SVGs are correct color to match the mockup without designer intervention required - and can easily be changed in the future, if need be. How convenient is that?&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Great designs have the power to capture people&apos;s attention and help them understand the benefits of a particular product or company - and many times they help the developers bringing these designs to life learn a new thing or two along the way.&lt;/p&gt;
&lt;p&gt;As I was building a new page for my company&apos;s website that featured a large quote from our company founder, I was faced with just such a scenario where the stylized quotation marks were given to me as black SVG images, but they were shown in the design as being blue.&lt;/p&gt;
&lt;p&gt;Before asking my designer to take the time recreate them in the appropriate color to match the design, I did some preliminary googling and found a much more flexible, code driven solution making great use of CSS &lt;code&gt;filter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And not only did the answer exist, but someone had also made a &lt;a href=&quot;https://codepen.io/sosuke/pen/Pjoqqp&quot;&gt;CodePen&lt;/a&gt; that could match any hex color! Just what I needed, and there for anyone to benefit from. The web development community can be so awesomely generous.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope this cool trick to convert SVGs from one color to another using CSS&apos;s &lt;code&gt;filter&lt;/code&gt; comes in handy for you like it did for me. It&apos;s a great feeling as a developer to have the power to make these sorts of changes through code.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter&quot;&gt;MDN Docs, CSS Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/22252472/how-to-change-the-color-of-an-svg-element/53336754#53336754&quot;&gt;StackOverflow thread&lt;/a&gt; for CSS filter solution&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/sosuke/pen/Pjoqqp&quot;&gt;CodePen site to match SVG to any hex color via CSS filter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>css</category></item><item><title>Render Multiple Colored Lines on a React Map with Polylines</title><link>https://www.paigeniedringhaus.com/blog/render-multiple-colored-lines-on-a-react-map-with-polylines/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/render-multiple-colored-lines-on-a-react-map-with-polylines/</guid><description>Need more than one color of line in a React Leaflet map? Polylines is the solution.</description><pubDate>Mon, 08 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/render-multiple-map-routes/sos-mode-enabled.png&quot; alt=&quot;Map displaying SOS mode lines in addition to normal tracking lines&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Last summer I started working for an Internet of Things startup, &lt;strong&gt;&lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Blues Wireless&lt;/a&gt;&lt;/strong&gt;, whose goal is to make IoT development easier by providing prepaid cellular Internet connectivity to any IoT device through the use of a &lt;strong&gt;&lt;a href=&quot;https://blues.io/products/notecard/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecard&lt;/a&gt;&lt;/strong&gt;, which transmits sensor data as JSON to a secure cloud, &lt;strong&gt;&lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notehub&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In a &lt;strong&gt;&lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;previous post&lt;/a&gt;&lt;/strong&gt;, I showed how I used Next.js and React Leaflet to build an asset tracker map to display where a moving Notecard was (inside my car) in near real time. This exercise ended up coming in more handy than I expected when &lt;a href=&quot;https://blues.io/blog/gps-asset-tracker-with-blues-wireless-and-react/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;my parents&apos; car was stolen out of their driveway&lt;/a&gt; over the Thanksgiving holiday and I&apos;d stuck a Notecard in the backseat while visiting.&lt;/p&gt;
&lt;p&gt;Although the Notecard was discovered shortly after the car was stolen and thrown out a window, for a short period of time we (and the police) were able to follow the car around town courtesy of my dashboard map, and this experience inspired me during a company-wide hackathon a few months later.&lt;/p&gt;
&lt;p&gt;One thing that would have been very helpful during the period when the car was stolen was if the lines between points on the map could have been in some color besides the standard blue for easier identification of where the car was after it was taken. So for the hackathon I created a new dashboard with an &quot;SOS mode&quot; to not only render lines in red on the map after the SOS mode was enabled, but also increase the frequency of the Notecard taking location readings for better accuracy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to create a map with React Leaflet in Next.js with the ability to render different colored lines at the touch of button for asset tracking under normal or emergency conditions.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Set up a map component in Next.js app&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This article will not go through setting up a brand new Next project or an in-depth explanation of fetching asset tracker data from a Blues Wireless Notecard, as I&apos;ve covered this already in &lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To see the finished code, you can view my GitHub repo &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Install map project dependencies&lt;/h3&gt;
&lt;p&gt;The first thing we&apos;ll do in this tutorial is add a map to a Next project. This is going to require a few new npm packages added to our project: &lt;strong&gt;&lt;a href=&quot;https://leafletjs.com/&quot;&gt;leaflet&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href=&quot;https://react-leaflet.js.org/&quot;&gt;react-leaflet&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://github.com/ghybs/leaflet-defaulticon-compatibility&quot;&gt;leaflet-defaulticon-compatibility&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Run the following lines in a terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install leaflet react-leaflet leaflet-defaulticon-compatibility
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; You&apos;ll also need &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-dom&lt;/code&gt; as peer dependencies if they&apos;re not already in your project as well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;TypeScript Note:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re using TypeScript in your project, you&apos;ll also want to want to install the follow dev dependency to avoid TypeScript errors:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install @types/leaflet --save-dev 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installing our new project dependencies we&apos;ll set up the component to use them.&lt;/p&gt;
&lt;h3&gt;Generate a Mapbox token for the map&apos;s display style and add it to the project&lt;/h3&gt;
&lt;p&gt;For the map display that the asset tracker will be on, I chose to use &lt;strong&gt;&lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox&lt;/a&gt;&lt;/strong&gt; styles. It has a variety of &lt;strong&gt;&lt;a href=&quot;https://docs.mapbox.com/api/maps/styles/&quot;&gt;styles&lt;/a&gt;&lt;/strong&gt; to choose from, and developers can create their own &lt;strong&gt;&lt;a href=&quot;https://docs.mapbox.com/help/getting-started/access-tokens/&quot;&gt;Mapbox API tokens&lt;/a&gt;&lt;/strong&gt; to access these styles by signing up for a free &lt;strong&gt;&lt;a href=&quot;https://account.mapbox.com/auth/signup/&quot;&gt;Mapbox account&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After you&apos;ve signed up and created a new API token, copy the token value. In the Next.js app&apos;s &lt;code&gt;next.config.js&lt;/code&gt; file at the root of the project, add the API token like so:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard/blob/main/next.config.js&quot;&gt;&lt;code&gt;next.config.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/** @type {import(&apos;next&apos;).NextConfig} */
module.exports = {
  reactStrictMode: true,
  env: {
    MAPBOX_ACCESS_TOKEN:
      &quot;[MAPBOX_TOKEN]&quot;,
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From this file, Next can access the token when it needs to call the Mapbox API endpoint. Now we can get on with creating the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component in our project.&lt;/p&gt;
&lt;h3&gt;Create the &lt;code&gt;&amp;lt;Map&amp;gt;&lt;/code&gt; component&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/render-multiple-map-routes/asset-tracker-map-peace-time.png&quot; alt=&quot;React-Leaflet map rendering the asset tracker&apos;s location during normal circumstances&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is how the map looks displaying asset locations during normal circumstances.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As this is a React project, individual, reusable components are the name of the game, so create a new file named &lt;code&gt;Map.tsx&lt;/code&gt; and paste in the following code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The actual code is available by clicking the file title below.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard/blob/main/src/components/Map.tsx&quot;&gt;&lt;code&gt;Map.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {
  MapContainer,
  TileLayer,
  Marker,
  Popup,
  CircleMarker,
  Polyline,
} from &quot;react-leaflet&quot;;
import &quot;leaflet/dist/leaflet.css&quot;;
import &quot;leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css&quot;;
import &quot;leaflet-defaulticon-compatibility&quot;;

const Map = ({
  coords,
  lastPosition,
  markers,
  latestTimestamp,
  sosCoords,
}: {
  coords: number[][];
  lastPosition: [number, number];
  markers: [number, number][];
  latestTimestamp: string;
  sosCoords?: number[][];
}) =&amp;gt; {
  const geoJsonObj: any = coords;
  const sosGeoJsonObj: any = sosCoords;

  const mapMarkers = markers.map((latLng, i) =&amp;gt; (
    &amp;lt;CircleMarker key={i} center={latLng} fillColor=&quot;navy&quot; /&amp;gt;
  ));

  return (
    &amp;lt;&amp;gt;
      &amp;lt;h2&amp;gt;Asset Tracker Map&amp;lt;/h2&amp;gt;
      &amp;lt;MapContainer
        center={lastPosition}
        zoom={14}
        style={{ height: &quot;100%&quot;, width: &quot;100%&quot; }}
      &amp;gt;
        &amp;lt;TileLayer
          url={`https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.MAPBOX_ACCESS_TOKEN}`}
        /&amp;gt;
        &amp;lt;Marker position={lastPosition} draggable={true}&amp;gt;
          &amp;lt;Popup&amp;gt;
            Last recorded position:
            &amp;lt;br /&amp;gt;
            {lastPosition[0].toFixed(6)}&amp;amp;#176;,&amp;amp;nbsp;
            {lastPosition[1].toFixed(6)}&amp;amp;#176;
            &amp;lt;br /&amp;gt;
            {latestTimestamp}
          &amp;lt;/Popup&amp;gt;
          &amp;lt;Polyline pathOptions={{ color: &quot;blue&quot; }} positions={geoJsonObj} /&amp;gt;
          &amp;lt;Polyline pathOptions={{ color: &quot;red&quot; }} positions={sosGeoJsonObj} /&amp;gt;
          {mapMarkers}
        &amp;lt;/Marker&amp;gt;
      &amp;lt;/MapContainer&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default Map;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s briefly discuss what&apos;s happening here.&lt;/p&gt;
&lt;p&gt;At the beginning of the file we import all the necessary React Leaflet components, the Leaflet CSS, and the Leaflet Default Icon Compatibility CSS and JS (this is &lt;a href=&quot;https://www.npmjs.com/package/leaflet-defaulticon-compatibility#usage&quot;&gt;recommended&lt;/a&gt; to get Leaflet&apos;s icons to work as expected).&lt;/p&gt;
&lt;p&gt;Then we see the props the &lt;code&gt;Map&lt;/code&gt; component expects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;coords&lt;/code&gt;&lt;/strong&gt; - a list of arrays that have GPS latitude and longitude: this draws the connecting lines between map markers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lastPosition&lt;/code&gt;&lt;/strong&gt; - the most recent GPS latitude and longitude to display in the popup when the user clicks the icon on the map.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;markers&lt;/code&gt;&lt;/strong&gt; - another list of arrays that have GPS latitude and longitude to display the blue circles of previous places on the map where the tracker was in the past.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;latestTimestamp&lt;/code&gt;&lt;/strong&gt; - the most recent timestamp of GPS coordinates received (also for displaying in the popup on the map).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sosCoords&lt;/code&gt;&lt;/strong&gt; - a separate list of GPS coordinates created when the &quot;SOS mode&quot; is enabled within the application: it will draw connecting lines between map markers in red.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now turn your attention down to the JSX further down in the file.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;&amp;lt;MapContainer /&amp;gt;&lt;/code&gt;&lt;/strong&gt; component is responsible for creating the Leaflet Map instance. Without this component, the map won&apos;t work, and we also define the map&apos;s &lt;code&gt;center&lt;/code&gt; coordinates, its default zoom level, and basic styling for the component.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;&amp;lt;TileLayer /&amp;gt;&lt;/code&gt;&lt;/strong&gt; component is where our Mapbox style and new API token come in. Choose whatever style suits you, replace the &lt;code&gt;streets-v11&lt;/code&gt; portion of the string, and make sure the Mapbox token is present in the &lt;code&gt;next.config.js&lt;/code&gt; file, which I showed in the previous step. Without this component no map background for the coordinates will render - instead it will just be a blank canvas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;Marker /&amp;gt;&lt;/code&gt;&lt;/strong&gt; takes in the &lt;code&gt;lastPosition&lt;/code&gt; prop to display the icon on the map of the tracker&apos;s last recorded position, and it wraps the &lt;code&gt;&amp;lt;Popup /&amp;gt;&lt;/code&gt; component, the &lt;code&gt;&amp;lt;Polyline /&amp;gt;&lt;/code&gt; components, and the list of &lt;code&gt;&amp;lt;CircleMarker /&amp;gt;&lt;/code&gt; components.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;&amp;lt;Popup /&amp;gt;&lt;/code&gt;&lt;/strong&gt; component is a nice looking tooltip that can display info. My &lt;code&gt;&amp;lt;Popup /&amp;gt;&lt;/code&gt; shows the tracker&apos;s last GPS coordinates and time it was reported when a user clicks it.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;&amp;lt;Polyline /&amp;gt;&lt;/code&gt;&lt;/strong&gt; components are where the &lt;code&gt;coords&lt;/code&gt; list or &lt;code&gt;sosCoords&lt;/code&gt; list of GPS coordinates are passed to draw the connecting lines between map markers. The &lt;code&gt;Polyline&lt;/code&gt; object takes in &lt;code&gt;positions&lt;/code&gt;, which in this case is either &lt;code&gt;geoJsonObj&lt;/code&gt; or &lt;code&gt;sosGeoJsonObj&lt;/code&gt;, and the &lt;code&gt;pathOptions&lt;/code&gt; determines the color of the line rendered.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; At first, I tried to use the &lt;code&gt;GeoJSON&lt;/code&gt; object to render the connecting lines, but there&apos;s no way to change line color midway through (as when SOS mode is enabled and lines need to go from blue to red), so multiple separate &lt;code&gt;Polyline&lt;/code&gt; objects was the best way to achieve this objective.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And last but not least, the &lt;strong&gt;&lt;code&gt;&amp;lt;CircleMarker &amp;gt;/&lt;/code&gt;&lt;/strong&gt; components, which are displayed in this component&apos;s JSX as &lt;code&gt;{mapMarkers}&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; In order to get all the &lt;code&gt;markers&lt;/code&gt; in the list to render as individual circles on the map, I had to create this little function to iterate over the list and generate all the circles, then inject that directly into the JSX.&lt;/p&gt;
&lt;p&gt;Trying to iterate over all the values inside the JSX wouldn&apos;t work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now our &lt;code&gt;Map&lt;/code&gt; component&apos;s been dissected, let&apos;s move on to populating the map with data and going from blue lines to red and back again.&lt;/p&gt;
&lt;h3&gt;Render the map in the Next.js app&lt;/h3&gt;
&lt;p&gt;The next step to getting this map working in our Next.js app is to import the &lt;code&gt;Map&lt;/code&gt; component with the option of &lt;code&gt;ssr: false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;react-leaflet&lt;/code&gt; library only works on the client side so Next&apos;s &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr&quot;&gt;&lt;code&gt;dynamic import()&lt;/code&gt; support with no SSR&lt;/a&gt;&lt;/strong&gt; feature must be employed to ensure the component doesn&apos;t try to render server-side.&lt;/p&gt;
&lt;p&gt;Below is the code for the &lt;code&gt;index.tsx&lt;/code&gt; file that this component will be displayed within, condensed for clarity. If you&apos;d like to see the full code in GitHub, click the file name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import dynamic from &quot;next/dynamic&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
  // needed to make the Leaflet map render correctly
  const MapWithNoSSR = dynamic(() =&amp;gt; import(&quot;../src/components/Map&quot;), {
    ssr: false,
  });

 // logic to enable/disable sos mode and transform data into items needed to pass to map

  return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;Notelink Tracker Dashboard&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
          &amp;lt;MapWithNoSSR
            coords={latLngMarkerPositions}
            lastPosition={lastPosition}
            markers={latLngMarkerPositions}
            latestTimestamp={latestTimestamp}
            sosCoords={sosCoords}
          /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// code to fetch tracker data: getStaticProps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&apos;t worry too much about the props being passed to the component yet - we&apos;ll set those up shortly.&lt;/p&gt;
&lt;p&gt;Now our &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component is being dynamically imported with Next&apos;s server-side rendering disabled, and the component can be used just like any other in the app.&lt;/p&gt;
&lt;h2&gt;Fetch data for the map&lt;/h2&gt;
&lt;p&gt;In my &lt;strong&gt;&lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;previous asset tracking dashboard article&lt;/a&gt;&lt;/strong&gt; I went into great detail about how to create your own asset tracker to generate real data for the app using Blues Wireless hardware and fetching that data to the app via the Notehub cloud&apos;s API.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to follow along there to build your own tracker and route data to Notehub, please be my guest.&lt;/p&gt;
&lt;p&gt;For this post, I&apos;ll jump ahead to the part where we&apos;re already pulling data into the app via a Next.js &lt;code&gt;getStaticProps&lt;/code&gt; API call. The JSON data from the Notehub cloud looks like this when it first arrives:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {
    &quot;uid&quot;: &quot;d7cf7475-45ff-4d8c-b02a-64de9f15f538&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T16:10:52Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T16:11:29Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 3,
      &quot;seconds&quot;: 90,
      &quot;motion&quot;: 76,
      &quot;temperature&quot;: 20.1875,
      &quot;time&quot;: 1636123230,
      &quot;voltage&quot;: 4.2578125
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T16:10:53Z&quot;,
      &quot;name&quot;: &quot;Sandy Springs, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.913747500000014,
      &quot;longitude&quot;: -84.35008984375
    }
  },
  {
    &quot;uid&quot;: &quot;3b1ef772-44da-455a-a846-446a85a70050&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T22:22:18Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T22:23:12Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 2,
      &quot;motion&quot;: 203,
      &quot;seconds&quot;: 174,
      &quot;temperature&quot;: 22,
      &quot;time&quot;: 1636150938,
      &quot;voltage&quot;: 4.2265625
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T22:22:19Z&quot;,
      &quot;name&quot;: &quot;Doraville, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.901052500000006,
      &quot;longitude&quot;: -84.27090234375
    }
  },
  {
    &quot;uid&quot;: &quot;e94b0c68-b1d0-49cb-8361-d622d2d0081e&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T22:40:04Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T22:46:30Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 1,
      &quot;motion&quot;: 50,
      &quot;seconds&quot;: 41,
      &quot;temperature&quot;: 21.875,
      &quot;time&quot;: 1636152004,
      &quot;voltage&quot;: 4.1875
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T22:40:05Z&quot;,
      &quot;name&quot;: &quot;Peachtree Corners, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.9828325,
      &quot;longitude&quot;: -84.21591015624999
    }
  },
  {
    &quot;uid&quot;: &quot;1344517c-adcb-4133-af6a-b1132ffc86ea&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-06T03:04:07Z&quot;,
    &quot;received&quot;: &quot;2021-11-06T03:10:51Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 1,
      &quot;motion&quot;: 126,
      &quot;seconds&quot;: 218,
      &quot;temperature&quot;: 12.5625,
      &quot;time&quot;: 1636167847,
      &quot;voltage&quot;: 4.1875
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-06T03:04:08Z&quot;,
      &quot;name&quot;: &quot;Norcross, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.937182500000006,
      &quot;longitude&quot;: -84.25278515625
    }
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each JSON object in this array is a separate &lt;code&gt;_track.qo&lt;/code&gt; motion event that displays the Notecard&apos;s current location and sensor readings. The part of the object that we care about in this particular post is the &lt;code&gt;gps_location&lt;/code&gt; values: &lt;code&gt;latitude&lt;/code&gt;, &lt;code&gt;longitude&lt;/code&gt;, and the &lt;code&gt;captured&lt;/code&gt; value. This is the data we&apos;ll need for the map.&lt;/p&gt;
&lt;p&gt;Shortly we&apos;ll work on transforming this data to fit our &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component&apos;s props - we&apos;ll handle that right after we create SOS mode for the app.&lt;/p&gt;
&lt;h3&gt;Configure SOS mode in the app&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/render-multiple-map-routes/sos-button.png&quot; alt=&quot;SOS button to toggle on/off SOS mode in the app&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The SOS button to toggle SOS mode in the app.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Before we transform this JSON data, we need to give our application the option to turn SOS mode on or off (which changes the color of the polylines rendered in the map).&lt;/p&gt;
&lt;p&gt;To build this, we&apos;ll need a new state variable, function, and button in our &lt;code&gt;index.tsx&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import { useState } from &quot;react&quot;;
// more imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
  // map component imported dynamically here

  const [isSosModeEnabled, setIsSosModeEnabled] = useState&amp;lt;boolean&amp;gt;(false);

  const toggleSosMode = () =&amp;gt; {
    const newSosState = !isSosModeEnabled;
    if (newSosState === true) {
      localStorage.setItem(&quot;sos-timestamp&quot;, new Date());
      setIsSosModeEnabled(newSosState);
    } else {
      localStorage.removeItem(&quot;sos-timestamp&quot;);
      setIsSosModeEnabled(newSosState);
    }
  };

 // logic to transform data into items needed to pass to map

  return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;Notelink Tracker Dashboard&amp;lt;/h1&amp;gt;
        &amp;lt;button onClick={toggleSosMode}&amp;gt;
          SOS Mode
        &amp;lt;/button&amp;gt;
        {isSosModeEnabled ? &amp;lt;p&amp;gt;SOS Mode Currently On&amp;lt;/p&amp;gt; : null}
        {/* other tracker components */}
          &amp;lt;MapWithNoSSR
            coords={latLngMarkerPositions}
            lastPosition={lastPosition}
            markers={latLngMarkerPositions}
            latestTimestamp={latestTimestamp}
            sosCoords={sosCoords}
          /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// code to fetch tracker data: getStaticProps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the file above, we&apos;re adding a new &lt;code&gt;isSosModeEnabled&lt;/code&gt; boolean: this will let the app know whether new location events are happening during an emergency tracking situation or not.&lt;/p&gt;
&lt;p&gt;Next, we create a new function called &lt;code&gt;toggleSosMode()&lt;/code&gt;. This function will change the state of the &lt;code&gt;isSosModeEnabled&lt;/code&gt; and also store a timestamp named &lt;code&gt;sos-timestamp&lt;/code&gt; in the browser&apos;s local storage. I&apos;m storing this timestamp in local storage so it can be compared to events that reach the app after SOS mode has been enabled and the app will know whether it needs to render the polylines on the map in red or blue. We&apos;ll get to the logic for this part in the following section.&lt;/p&gt;
&lt;p&gt;Lastly, in the JSX for the component, we&apos;ll make a new &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element and attach the &lt;code&gt;toggleSosMode()&lt;/code&gt; function to its &lt;code&gt;onClick()&lt;/code&gt; method. I also added a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag beneath the button to display when SOS Mode is in effect in the app.&lt;/p&gt;
&lt;p&gt;Pressing the button after app mode will turn it on, pressing it again will turn it off.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: In the &lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard&quot;&gt;actual repo&lt;/a&gt; there&apos;s also logic to update the Notecard via Notehub to take more frequent location readings, and handle if SOS mode was already enabled and the browser window was closed or app connection was lost, but for clarity in this tutorial, I&apos;ve eliminated both of those considerations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that we can turn SOS mode on and off in the browser at will, it&apos;s time to take our location data and transform it to render in our map.&lt;/p&gt;
&lt;h3&gt;Reshape the tracker event data&lt;/h3&gt;
&lt;p&gt;Our &lt;code&gt;index.tsx&lt;/code&gt; file is going to need some more state variables to fulfill all the different data props the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component needs. Once again, I&apos;ve condensed the logic to make this file easier to read, but you can always click the file name to see its full contents online.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import { useEffect, useState } from &quot;react&quot;;
import dayjs from &quot;dayjs&quot;; // for ease of date formatting 
// more imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
  // map component imported dynamically here

   const [lastPosition, setLastPosition] = useState&amp;lt;[number, number]&amp;gt;([
    33, -84,
  ]);
  const [latestTimestamp, setLatestTimestamp] = useState&amp;lt;string&amp;gt;(&quot;&quot;);
  const [latLngMarkerPositions, setLatLngMarkerPositions] = useState&amp;lt;
    [number, number][]
  &amp;gt;([]);

  // isSosEnabled boolean here
  const [sosCoords, setSosCoords] = useState&amp;lt;number[][]&amp;gt;([]);

  /* runs as soon as the location data is fetched from Notehub API 
    or when the sos mode is toggled on or off with the button */
  useEffect(() =&amp;gt; {
    const latLngArray: [number, number][] = [];
    const sosLatLngArray: [number, number][] = [];
    if (data &amp;amp;&amp;amp; data.length &amp;gt; 0) {
      data
        .sort((a, b) =&amp;gt; {
          return Number(a.captured) - Number(b.captured);
        })
        .map((event) =&amp;gt; {
          let latLngCoords: [number, number] = [];
          let sosLatLngCoords: [number, number] = [];
          if (!isSosModeEnabled) {
            latLngCoords = [
            event.gps_location.latitude,
            event.gps_location.longitude,
            ];
            latLngArray.push(latLngCoords);
          } else {
            const localSosTimestamp = localStorage.getItem(&quot;sos-timestamp&quot;);
            if (Date.parse(event.captured) &amp;gt;= Date.parse(localSosTimestamp)) {
                sosLatLngCoords = [
                  event.gps_location.latitude,
                  event.gps_location.longitude,
                ];
              sosLatLngArray.push(sosLatLngCoords);
            } else {
              latLngCoords = [
                event.gps_location.latitude,
                event.gps_location.longitude,
              ];
              latLngArray.push(latLngCoords);
            }
          }
        });
      const lastEvent = data.at(-1);
      let lastCoords: [number, number] = [0, 1];
      lastCoords = [
        lastEvent.gps_location.latitude,
        lastEvent.gps_location.longitude,
      ];
      setLastPosition(lastCoords);
      const timestamp = dayjs(lastEvent?.captured).format(&quot;MMM D, YYYY h:mm A&quot;);
      setLatestTimestamp(timestamp);
    }
    if (sosLatLngArray.length &amp;gt; 0) {
      setSosCoords(sosLatLngArray);
    }
    setLatLngMarkerPositions(latLngArray);
  }, [data, isSosModeEnabled]);

  // toggleSosMode function  

  return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;Notelink Tracker Dashboard&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
          &amp;lt;MapWithNoSSR
            coords={latLngMarkerPositions}
            lastPosition={lastPosition}
            markers={latLngMarkerPositions}
            latestTimestamp={latestTimestamp}
            sosCoords={sosCoords}
          /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// code to fetch tracker data: getStaticProps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our main component, once the data is fetched from Notehub, we set the following new React &lt;code&gt;useState&lt;/code&gt; variables to hold the data to pass to the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lastPosition&lt;/code&gt;, &lt;code&gt;latestTimestamp&lt;/code&gt;, &lt;code&gt;latLngMarkerPositions&lt;/code&gt;, and &lt;code&gt;sosCoords&lt;/code&gt;, are the new state variables we&apos;ll need at our disposal.&lt;/p&gt;
&lt;p&gt;After those states are declared, the &lt;code&gt;useEffect()&lt;/code&gt; function will run whenever data is fetched from Notehub (on component mount) or when the app&apos;s SOS mode is toggled. Inside the function, the events from Notehub are sorted and iterated through.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;isSosModeEnabled&lt;/code&gt; boolean is true, the &lt;code&gt;sos-timestamp&lt;/code&gt; is fetched out of the browser&apos;s local storage, and the date of that timestamp is compared to the &lt;code&gt;captured&lt;/code&gt; timestamp from each event so the event can be properly sorted into either the &lt;code&gt;sosLatLngArray&lt;/code&gt; list or the &lt;code&gt;latLngArray&lt;/code&gt; list.&lt;/p&gt;
&lt;p&gt;Once those local arrays are assembled inside of the &lt;code&gt;useEffect()&lt;/code&gt;, they&apos;re set equal to the state variables &lt;code&gt;latLngMarkerPositions&lt;/code&gt; and &lt;code&gt;sosCoords&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;isSosModeEnabled&lt;/code&gt; is false, then all the events are added to the &lt;code&gt;latLngArray&lt;/code&gt; list automatically.&lt;/p&gt;
&lt;p&gt;The other variables &lt;code&gt;lastPosition&lt;/code&gt; and &lt;code&gt;latestTimestamp&lt;/code&gt; are set simply by pulling the last event off of the sorted data array and extracting the properties from it.&lt;/p&gt;
&lt;p&gt;Then all these variables are passed to the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component, and it knows what do to from there regarding markers, popups, and line colors.&lt;/p&gt;
&lt;h2&gt;Test it out&lt;/h2&gt;
&lt;p&gt;Ok! I think we&apos;re reading to test out our map and multicolored lines!&lt;/p&gt;
&lt;p&gt;If you&apos;re using our mocked data instead of real-time data streaming in from the Notehub cloud, the easiest way to test the app is to toggle SOS mode on via the button in the browser, then adjust the timestamp in the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/storage/localstorage/&quot;&gt;browser&apos;s DevTool local storage&lt;/a&gt; to be before at least some of the events &lt;code&gt;captured&lt;/code&gt; timestamps.&lt;/p&gt;
&lt;p&gt;If everything goes according to plan, you should end up seeing a combination of colored lines depending on when the SOS mode&apos;s time is set to and when the event occurred.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/render-multiple-map-routes/sos-mode-enabled.png&quot; alt=&quot;Map displaying SOS mode lines in addition to normal tracking lines&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;When SOS mode is on, new events that occurred after it was enabled show up as red lines.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Please keep in mind, this app was built in a day so it&apos;s rough around the edges and certainly not ready for prime time. I&apos;d recommend forking it and giving it some extra polish and testing before putting it into prod, if you&apos;re so inclined.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And there you have it: multicolored lines in a map in a React application. Not too shabby for a day&apos;s work.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;After I joined an IoT startup last summer, I started building web apps to reflect the data being captured and transferred by our IoT devices in the real world and sent to the cloud, and during a company-wide hackathon I built a dashboard that not only displayed location data but also had the ability to change location lines from blue to red at will.&lt;/p&gt;
&lt;p&gt;It seemed like a nice feature to improve readability of the map in some sort of emergency situation.&lt;/p&gt;
&lt;p&gt;Next.js combined with the React Leaflet library made it all possible, and within the timeframe I had a working (if very rough) prototype to show my coworkers. It was a lot of fun to work on, and I learned a bunch of new things along the way. That&apos;s my idea of a successful hackathon.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you found it useful to see how to set up an interactive map in Next.js and render multicolored travel lines between different location points depending on the situation. Happy mapping!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hackster.io/paige-niedringhaus/low-code-gps-asset-tracker-and-map-display-b10419&quot;&gt;Hackster.io original asset tracker project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/notelink-tracker-dashboard&quot;&gt;SOS Asset Tracker GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leafletjs.com/&quot;&gt;Leaflet documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-leaflet.js.org/&quot;&gt;React Leaflet documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>react</category><category>javascript</category><category>maps</category><category>nextjs</category><category>typescript</category></item><item><title>Use Secret Environment Variables in GitHub Actions</title><link>https://www.paigeniedringhaus.com/blog/use-secret-environment-variables-in-github-actions/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/use-secret-environment-variables-in-github-actions/</guid><description>Setting up protected environment variables for GitHub Actions CI/CD workflows isn&apos;t so tough.</description><pubDate>Mon, 04 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions/blue-lock.jpg&quot; alt=&quot;Lock holding together two aqua blue doors&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Earlier this year, my development team and I were in the midst of building a new open source &lt;strong&gt;&lt;a href=&quot;https://github.com/blues/sparrow-starter&quot;&gt;application&lt;/a&gt;&lt;/strong&gt; to help our users get up and running faster with the hardware the Internet of Things (IoT) company I work for, sells.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I work for an IoT startup called &lt;strong&gt;&lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=secret-env-vars-github-actions&quot;&gt;Blues Wireless&lt;/a&gt;&lt;/strong&gt;, whose mission is to make IoT development simpler and easier through the use of &lt;a href=&quot;https://blues.io/products/notecard/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=secret-env-vars-github-actions&quot;&gt;Notecards&lt;/a&gt; - prepaid cellular devices that can be embedded into any IoT project to transmit sensor data to a secure cloud: &lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=secret-env-vars-github-actions&quot;&gt;Notehub&lt;/a&gt; - that can then forward that data on to any public cloud or application.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The idea is that once our users set up their new IoT devices, they can fork our starter repo, which is already designed to accept and display certain sensor data in charts and graphs, and then modify the code as they customize their devices further with new sensors or data visualizations.&lt;/p&gt;
&lt;p&gt;Keeping ease of setup and deployment in mind, we built the app using the self-contained &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/&quot;&gt;Next.js framework&lt;/a&gt;&lt;/strong&gt;, hosted a demo example of the app on &lt;strong&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;&lt;/strong&gt;, and used &lt;strong&gt;&lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt; to control the automated CI/CD workflows (build, test, deploy, etc.).&lt;/p&gt;
&lt;p&gt;One tricky thing I encountered when working with GitHub Actions was how to add sensitive environment variables that were used locally to run the app and its integration and end-to-end tests, while still keeping them secret (and out of GitHub&apos;s source control).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article, I&apos;ll teach you how to add &quot;secret&quot; environment variables to a GitHub Actions workflow so steps requiring dynamic, sensitive variables (like automated test suites) can successfully run in the CI/CD pipeline just as they do in a local development environment.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;What is GitHub Actions?&lt;/h2&gt;
&lt;p&gt;Let&apos;s step back for just a minute to talk about GitHub Actions in case you haven&apos;t had a need to work with them yet.&lt;/p&gt;
&lt;p&gt;Back in 2018, GitHub released a new feature called &lt;strong&gt;&lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions&quot;&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt;, designed to give developers the ability to automate their workflows across issues, pull requests, and other events.&lt;/p&gt;
&lt;p&gt;In 2019 it introduced &lt;a href=&quot;https://github.blog/2019-08-08-github-actions-now-supports-ci-cd/&quot;&gt;full continuous integration / continuous deployment (CI/CD)&lt;/a&gt; to GitHub Actions as well.&lt;/p&gt;
&lt;p&gt;These tools make it easier to automate how developers build, test, and deploy projects on any platform without the need for a devops expert on a development team. Among the advantage GH Actions has over other CI/CD tools is that if a repo is already in GitHub (which it probably is), it&apos;s very straightforward to set up workflows to handle all of these sorts of tasks (and more) in an automated fashion.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;ve ever used another CI/CD platform like &lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt;, &lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt;, &lt;a href=&quot;https://www.jetbrains.com/teamcity/&quot;&gt;TeamCity&lt;/a&gt;, or a handful of other tools, GitHub Actions should feel similar to you once you start working with it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&apos;s a sample diagram of what a simple CI/CD pipeline might look like.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions/ci-cd-workflow.png&quot; alt=&quot;Continuous integration workflow example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Continuous integration diagram courtesy of &amp;lt;a href=&quot;https://resources.github.com/ci-cd/&quot;&amp;gt;GitHub Resources: CI/CD&amp;lt;/a&amp;gt;&amp;lt;/figcation&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Going into all the specifics of how GH Actions works is beyond the scope of this blog, but hopefully I&apos;ve given you a good enough primer to understand the material we&apos;ll cover now.&lt;/p&gt;
&lt;h2&gt;In the Repo, Set the Environment Variables for GH Actions&lt;/h2&gt;
&lt;p&gt;The place to begin setting environment variables for GH Actions to use is inside the repo itself.&lt;/p&gt;
&lt;h3&gt;Identify the Local Environment Variables to Replicate in GitHub&lt;/h3&gt;
&lt;p&gt;In our particular &lt;strong&gt;&lt;a href=&quot;https://github.com/blues/sparrow-starter&quot;&gt;repo&lt;/a&gt;&lt;/strong&gt;, we have four dynamic environment variables that the app (and its test suites) require to run: &lt;code&gt;HUB_BASE_URL&lt;/code&gt;, &lt;code&gt;HUB_AUTH_TOKEN&lt;/code&gt;, &lt;code&gt;HUB_PROJECT_UID&lt;/code&gt;, and &lt;code&gt;HUB_PRODUCT_UID&lt;/code&gt;,&lt;/p&gt;
&lt;p&gt;All of these variables relate to unique project values that are discoverable in &lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=secret-env-vars-github-actions&quot;&gt;Notehub&lt;/a&gt;, the cloud application where IoT sensor data is delivered via the Notecard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HUB_BASE_URL&lt;/code&gt; is the URL to reach the Notehub API to fetch data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HUB_AUTH_TOKEN&lt;/code&gt; is an authorization token required to access data in Notehub.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HUB_PROJECT_UID&lt;/code&gt; is the project ID in Notehub where the sensor data is sent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HUB_PRODUCT_UID&lt;/code&gt; is the sensor device&apos;s unique ID - as one project can have many devices sending data to it.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Although not all of these environment variables are &quot;top secret&quot;, since there&apos;s just four of them, it made more sense to keep them all grouped together in the repo instead splitting them up into &quot;public&quot; and &quot;private&quot; variables located in separate places in the code base.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since this is a Next.js application, the way we locally store these sensitive variables that should not be checked in to source control (i.e. GitHub) is through the use of &lt;a href=&quot;https://nextjs.org/docs/basic-features/environment-variables&quot;&gt;&lt;code&gt;.env&lt;/code&gt; files&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the app, the following sample code controls the environment variables read by Next.js when it starts up locally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.env.local&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HUB_BASE_URL=https://api.notefile.net
HUB_AUTH_TOKEN=[YOUR_AUTH_TOKEN_HERE]
HUB_PROJECT_UID=[YOUR_NOTEHUB_PROJECT_UID_HERE]
HUB_PRODUCT_UID=[YOUR_NOTEHUB_PRODUCT_UID_HERE]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These variables are then accessed inside the application using the &lt;code&gt;process.env&lt;/code&gt; syntax. For instance, to get the &lt;code&gt;HUB_PROJECT_UID&lt;/code&gt; value inside of the app&apos;s running code, it&apos;s simply a matter of writing &lt;code&gt;process.env.HUB_PROJECT_UID&lt;/code&gt; in the JavaScript file where it&apos;s required.&lt;/p&gt;
&lt;p&gt;Ok, so we&apos;ve identified our environment variables that are dynamic and also should not be checked into GitHub, let&apos;s let GitHub Actions know it needs to look for them too when it runs its CI workflows.&lt;/p&gt;
&lt;h3&gt;Add the Environment Variables to the GitHub Actions YAML File&lt;/h3&gt;
&lt;p&gt;In order for GitHub to know it has a GitHub Action workflow to run for a repo, the following folders should exist at the root of the repo: &lt;code&gt;.github/workflows/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A YAML file will be contained therein: ours is named &lt;a href=&quot;https://github.com/blues/sparrow-reference-web-app/blob/main/.github/workflows/CI-PRs-and-main.yml&quot;&gt;&lt;code&gt;CI-PRs-and-main.yml&lt;/code&gt;&lt;/a&gt;, but you can name it anything that makes sense to you.&lt;/p&gt;
&lt;p&gt;Inside of the YAML file, there will be a variety of steps listed out and for the steps requiring these secrets, we&apos;ll add the needed environment variables like so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you&apos;d like to see the full GitHub Actions file in its repo, you can click the file title below.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/sparrow-reference-web-app/blob/main/.github/workflows/CI-PRs-and-main.yml&quot;&gt;&lt;code&gt;CI-PRs-and-main.yml&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# more GitHub Actions steps above...
- name: Run unit tests
  env:
    HUB_AUTH_TOKEN: ${{ secrets.HUB_AUTH_TOKEN }}
    HUB_BASE_URL: ${{ secrets.HUB_BASE_URL }}
    HUB_PROJECT_UID: ${{ secrets.HUB_PROJECT_UID }}
    HUB_PRODUCT_UID: ${{ secrets.HUB_PRODUCT_UID }}
  run: yarn test:coverage
- run: yarn lint
- name: Cypress run # our e2e tests
  uses: cypress-io/github-action@v2
  with:
    env: configFile=staging
    start: yarn start
  env:
    HUB_AUTH_TOKEN: ${{ secrets.HUB_AUTH_TOKEN }}
    HUB_BASE_URL: ${{ secrets.HUB_BASE_URL }}
    HUB_PROJECT_UID: ${{ secrets.HUB_PROJECT_UID }}
    HUB_PRODUCT_UID: ${{ secrets.HUB_PRODUCT_UID }}
# more GitHub Actions steps below...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you notice there are two &lt;code&gt;steps&lt;/code&gt; in this YAML file that require the sensitive environment variables: &lt;code&gt;Run unit tests&lt;/code&gt; and &lt;code&gt;Cypress run&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declare the &lt;code&gt;env&lt;/code&gt; property and each needed environment variable&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To tell GH Actions these custom environment variables should exist, we declare the &lt;strong&gt;&lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/environment-variables&quot;&gt;&lt;code&gt;env&lt;/code&gt; property&lt;/a&gt;&lt;/strong&gt; inside the steps that need the variables.&lt;/p&gt;
&lt;p&gt;Then indent and list each secret variable needed (and how the repo reads them). For example, since our repo reads the secret variable &lt;code&gt;HUB_AUTH_TOKEN&lt;/code&gt; locally, it makes sense to name the &lt;code&gt;env&lt;/code&gt; property to be read during the GitHub Actions workflow by the same name.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  env:
    HUB_AUTH_TOKEN:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Set the &lt;code&gt;${{ secrets.MY_SECRET }}&lt;/code&gt; value&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After listing out the environment variable names for GitHub Actions, use the syntax &lt;code&gt;${{ secrets.NAME_OF_SECRET_IN_GITHUB }}&lt;/code&gt; to assign a value stored in GitHub Actions by the same name.&lt;/p&gt;
&lt;p&gt;I&apos;ll go into how to set this value remotely in the next section.&lt;/p&gt;
&lt;h2&gt;In the GitHub Repo Set Those Sensitive Environment Variables&lt;/h2&gt;
&lt;p&gt;Now we&apos;re ready to move on to setting the secret variables in GitHub.&lt;/p&gt;
&lt;h3&gt;Access the Repo&apos;s Settings Tab&lt;/h3&gt;
&lt;p&gt;Head to your repo in GitHub that needs the variables and click on the &lt;strong&gt;Settings&lt;/strong&gt; tab.&lt;/p&gt;
&lt;p&gt;Inside of &lt;strong&gt;Settings&lt;/strong&gt;, go down the sidebar to the &lt;strong&gt;Secrets&lt;/strong&gt; dropdown and click on it to access the &lt;strong&gt;Actions&lt;/strong&gt; page. The page should look something like this image below.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions/access-github-action-secrets.png&quot; alt=&quot;GitHub Secrets Actions page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In my &lt;strong&gt;Actions Secrets&lt;/strong&gt; page, there are already a few Repository Secrets present - this is what we&apos;ll be adding to to run in the GH Actions workflow. Click on the &lt;strong&gt;New repository secret&lt;/strong&gt; button in the upper right corner of the screen.&lt;/p&gt;
&lt;h3&gt;Set New Environment Secrets&lt;/h3&gt;
&lt;p&gt;A new screen will appear to add new secrets to the repository. Here is where the environment variable names defined in the GitHub Actions YAML will be replicated and their values defined.&lt;/p&gt;
&lt;p&gt;Using our example variables from above, we&apos;d define a new variable named &lt;code&gt;HUB_PROJECT_UID&lt;/code&gt; as the secret&apos;s name in the &lt;code&gt;Name&lt;/code&gt; input, then add the actual project&apos;s value (as defined in Notehub, in this case) into the &lt;code&gt;Value&lt;/code&gt; text area.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This corresponds to the &lt;code&gt;${{ secrets.HUB_PROJECT_UID }}&lt;/code&gt; value in the YAML file.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions/add-new-secret.png&quot; alt=&quot;Set new secret in GitHub repo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Click the &lt;strong&gt;Add Secret&lt;/strong&gt; button after double checking the secret name and value are correct. Once the secret&apos;s saved it&apos;s encrypted in GitHub and you&apos;ll be hard pressed to see what its original value was.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you do realize later a secret is incorrect or needs to be updated, not to worry, secret values can be updated by clicking the &lt;strong&gt;Update&lt;/strong&gt; button next to the secret&apos;s name on the main &lt;strong&gt;Actions Secrets&lt;/strong&gt; page.&lt;/p&gt;
&lt;p&gt;You still won&apos;t be able to see what the old value of the secret was, but there is a path forward to make changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great! The GitHub Actions file knows what environment variables to inject for certain steps of the workflow, those environment variables and their values have been defined in the repo&apos;s settings tab, it&apos;s time to test it out.&lt;/p&gt;
&lt;h3&gt;Run Your GitHub Actions Workflow and Watch it Pass&lt;/h3&gt;
&lt;p&gt;For our repo, the GitHub Actions workflows are designed to run whenever a user pushes code to a pull request or to the &lt;code&gt;main&lt;/code&gt; branch, as defined here:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/sparrow-reference-web-app/blob/main/.github/workflows/CI-PRs-and-main.yml&quot;&gt;&lt;code&gt;CI-PRs-and-main.yml&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# more GitHub Actions code above
on:
  pull_request:
  push:
    branches:
      - main
# more GitHub Actions code below      
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have an already existing workflow that failed, simply go to the repo&apos;s &lt;strong&gt;Actions&lt;/strong&gt; tab, click on the failing workflow, and click the &lt;strong&gt;Re-run all jobs&lt;/strong&gt; button on the main workflow&apos;s screen.&lt;/p&gt;
&lt;p&gt;If not, perform whatever action is needed to trigger a new workflow to run.&lt;/p&gt;
&lt;p&gt;Either way, this is the end result you should see when the secret environment variables set are successfully read out.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-actions/github-actions-workflow-run.png&quot; alt=&quot;Successful GitHub Actions workflow where all steps pass&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Notice in the image that among all the steps listed out during the course of the workflow, the two that required the sensitive environment variables, &lt;code&gt;Run Unit Tests&lt;/code&gt; and &lt;code&gt;Cypress run&lt;/code&gt;, both successfully passed.&lt;/p&gt;
&lt;p&gt;No sensitive info or secrets revealed in the process.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With the introduction of GitHub Actions a few years ago, GitHub significantly reduced the complexity and expertise needed by development teams to take advantage of the benefits continuous integration / continuous deployment pipelines provide. One thing that&apos;s always been a problem though is how to handle environment variables that should be kept secret from the general code base for their sensitive nature - the very kinds of secrets required for apps (and automated test suites) to run.&lt;/p&gt;
&lt;p&gt;GitHub figured out a way to handle that though: secrets set in the repo&apos;s settings and encrypted as soon as they&apos;re set. Instead of having to figure out how to keep secrets safe through the use of &lt;code&gt;.gitignore&lt;/code&gt; JSON files, build pipeline vaults, or other, non-intuitive, difficult-to-manage systems, GitHub can simply store the variables and access them in any necessary workflow step using the &lt;code&gt;${{ secrets.MY_SECRET_HERE }}&lt;/code&gt; syntax. Much better!&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope this helps you out when building your own GitHub Actions workflows that require sensitive environment variables: CI/CD is the best way of building quality software today, and GitHub is making it easier and easier for everyone to achieve that.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions&quot;&gt;GitHub Actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://resources.github.com/ci-cd/&quot;&gt;GitHub&apos;s Ci/CD resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Full &lt;a href=&quot;https://github.com/blues/sparrow-starter&quot;&gt;GitHub project repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=secret-env-vars-github-actions&quot;&gt;website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=secret-env-vars-github-actions&quot;&gt;Notehub&lt;/a&gt; cloud&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>nextjs</category><category>github</category><category>git</category><category>devops</category></item><item><title>Merge JavaScript Objects in an Array with Different Defined Properties</title><link>https://www.paigeniedringhaus.com/blog/merge-javascript-objects-in-an-array-with-different-defined-properties/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/merge-javascript-objects-in-an-array-with-different-defined-properties/</guid><description>Array.reduce() is the solution to combine objects that share a key, but not necessarily properties.</description><pubDate>Mon, 06 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/merge-two-js-objects-in-array/converge.jpg&quot; alt=&quot;Convergence of gold threads&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;At work recently, I encountered an interesting problem: I needed to merge multiple JavaScript objects together in an array based on their matching keys.&lt;/p&gt;
&lt;p&gt;It sounds relatively straightforward at first, but there&apos;s more to the story that prevented me using the &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals&quot;&gt;spread operator&lt;/a&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign&quot;&gt;&lt;code&gt;Object.assign()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; to combine these objects.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Each of these objects &lt;em&gt;might&lt;/em&gt; share a common key - it wasn&apos;t guaranteed, and&lt;/li&gt;
&lt;li&gt;Although they all had the same properties in each object, not all of these properties were defined in every object - the object could have &lt;code&gt;property: value&lt;/code&gt; or it could be &lt;code&gt;property: undefined&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I needed to combine all the properties of objects that shared a common key along with their defined values into a new single object. And to make it just a smidge more difficult I needed it to work in TypeScript. 😅&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So today, I&apos;ll show you how to use JavaScript&apos;s &lt;code&gt;reduce()&lt;/code&gt; function to merge two (or more) objects in an array with different defined properties.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Background: &lt;code&gt;motion.qo&lt;/code&gt; and &lt;code&gt;air.qo&lt;/code&gt; events&lt;/h2&gt;
&lt;p&gt;For those of you curious as to when this sort of thing comes up in real life, here&apos;s a little more context about my situation.&lt;/p&gt;
&lt;p&gt;I work as a software engineer at an Internet of Things (IoT) startup named &lt;strong&gt;&lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=merge-js-objects&quot;&gt;Blues Wireless&lt;/a&gt;&lt;/strong&gt;. Our main mission is to make IoT development simpler, regardless of if there&apos;s a reliable Internet connection or not. Blues does this via &lt;strong&gt;&lt;a href=&quot;https://blues.io/products/notecard/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=merge-js-objects&quot;&gt;Notecards&lt;/a&gt;&lt;/strong&gt; - prepaid cellular devices that can be embedded into any IoT device &quot;on the edge&quot; to transmit that sensor data as JSON to a secure cloud: &lt;strong&gt;&lt;a href=&quot;https://blues.io/products/notehub/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=merge-js-objects&quot;&gt;Notehub&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In addition to producing this hardware and providing the secure cloud connection to send IoT data to, we also build software applications our users can connect their devices to and see the sensor data in charts and graphs.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/merge-two-js-objects-in-array/charts.png&quot; alt=&quot;Sample charts displaying sensor data&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here&apos;s an example of the charts displaying various sensor data.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;One of the web apps we were building involved sensors that reported two types of data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;air quality&lt;/strong&gt; readings like temperature, humidity, sensor voltage, and pressure, and&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;motion&lt;/strong&gt; readings like current count of motions detected and total motions detected over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So a single sensor is generating two different JSON payloads that are sent from a Notecard to Notehub, then Notehub routes them to our web app to get rendered in the charts.&lt;/p&gt;
&lt;p&gt;Here&apos;s a sample of some of the events delivered to the app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example sensor events&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const sensorEvents = [
  {
    sensorId: &apos;abc&apos;,
    id: &apos;1&apos;,
    humidity: undefined,
    pressure: undefined,
    temperature: undefined,
    voltage: undefined,
    count: 3,
    total: 32,
    lastActivity: &apos;2022-02-10T00:41:11Z&apos;
  },
  {
    sensorId: &apos;abc&apos;,
    id: &apos;2&apos;,
    humidity: 17.609375,
    pressure: 96.768734,
    temperature: 26.703125,
    voltage: 3.24,
    count: undefined,
    total: undefined,
    lastActivity: &apos;2022-02-15T21:59:18Z&apos;
  },
  {
    sensorId: &apos;def&apos;,
    id: &apos;3&apos;,
    humidity: undefined,
    pressure: undefined,
    temperature: undefined,
    voltage: undefined,
    count: 866,
    total: 1776,
    lastActivity: &apos;2022-02-15T22:00:03Z&apos;
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the first two objects in the array share the same &lt;code&gt;sensorId&lt;/code&gt; of &lt;code&gt;abc&lt;/code&gt;, but they have different defined properties.&lt;/p&gt;
&lt;p&gt;The first object has &lt;code&gt;motion&lt;/code&gt; properties (and undefined &lt;code&gt;air quality&lt;/code&gt; properties), the second object has defined &lt;code&gt;air quality&lt;/code&gt; properties (and undefined &lt;code&gt;motion&lt;/code&gt; properties), and the third object has a different &lt;code&gt;sensorId&lt;/code&gt; entirely; that is a &lt;code&gt;motion&lt;/code&gt; reading from another sensor.&lt;/p&gt;
&lt;p&gt;Which brought me to my problem: how to combine the objects with the same &lt;code&gt;sensorId&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; get all the defined properties from each object.&lt;/p&gt;
&lt;p&gt;So, let&apos;s get to it.&lt;/p&gt;
&lt;h3&gt;Merge like objects with a &lt;code&gt;mergeObject()&lt;/code&gt; function and &lt;code&gt;reduce()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;With the amount of times I&apos;ve said &quot;merge&quot; and &quot;combine&quot; in this post, you may already have figured out that the JavaScript array function &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot;&gt;&lt;code&gt;reduce()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; might come into play here, and it does.&lt;/p&gt;
&lt;p&gt;At its most basic, &lt;code&gt;reduce()&lt;/code&gt; goes through &lt;strong&gt;each element&lt;/strong&gt; in an array and adds it to an &lt;strong&gt;accumulator&lt;/strong&gt; of all the values preceding it, until just one value is returned at the end. The same thing can be done with an array of objects, with just a little more logic.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;d like a more thorough explanation of &lt;code&gt;reduce()&lt;/code&gt;, I encourage you to check out the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot;&gt;Mozilla documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Their examples are great, and I still visit it regularly for all sorts of topics.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Below is the TypeScript-flavored solution I came up with to take an array of objects, find the ones that share a common key, and return a new array with those objects combined.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface HasSensorId {
  sensorId: string;
}

// merge objects with different defined properties into a single obj
const mergeObject = &amp;lt;V&amp;gt;(A: any, B: any): V =&amp;gt; {
  let res: any = {};
  Object.keys({ ...A, ...B }).map((key) =&amp;gt; {
    res[key] = B[key] || A[key];
  });
  return res as V;
};

// use Map functions `get`, `set`, and `values`
// take each event, and make it into a new Map() obj where sensorId is the key
// regardless of if there&apos;s already a value for that key, run the merge function
// set the key and the new merge var as the key, value for the map
const reducer = &amp;lt;V extends HasSensorId&amp;gt;(
  groups: Map&amp;lt;string, V&amp;gt;,
  event: V
) =&amp;gt; {
  const key = event.sensorId;
  const previous = groups.get(key);
  const merged: V = mergeObject(previous || {}, event);
  groups.set(key, merged);
  return groups;
};

// run the sensor events through the reducer and then pull only their values into a new Map iterator obj
const reducedEventsIterator = sensorEvents
  .reduce(reducer, new Map())
  .values();

// transform the Map iterator obj back into an array
const reducedEvents = Array.from(reducedEventsIterator);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, I realize there&apos;s quite a few functions above, so an explanation is in order.&lt;/p&gt;
&lt;h3&gt;HasSensorId&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;HasSensorId&lt;/code&gt; interface is pretty direct: it means that wherever this interface is referenced, the object&apos;s must have a string of &lt;code&gt;sensorId&lt;/code&gt; among the properties.&lt;/p&gt;
&lt;p&gt;Now let&apos;s walk through the rest of these functions one by one.&lt;/p&gt;
&lt;h3&gt;mergeObject()&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const mergeObject = &amp;lt;V&amp;gt;(A: any, B: any): V =&amp;gt; {
  let res: any = {};
  Object.keys({ ...A, ...B }).map((key) =&amp;gt; {
    res[key] = B[key] || A[key];
  });
  return res as V;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;code&gt;mergeObject()&lt;/code&gt; function is the one that actually does the combining of objects.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; objects that this function takes in are the two objects with a common &lt;code&gt;sensorId&lt;/code&gt; property, and the &lt;code&gt;res&lt;/code&gt; variable will be the newly returned object of their properties (and values) combined.&lt;/p&gt;
&lt;p&gt;The first thing that happens is the two objects are combined using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals&quot;&gt;spread operator&lt;/a&gt;, and then just their keys are extracted into its own array using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign&quot;&gt;&lt;code&gt;Object.keys()&lt;/code&gt;&lt;/a&gt;. If you passed the sample &lt;code&gt;sensorEvents&lt;/code&gt; array into this function, the &lt;code&gt;Object.keys()&lt;/code&gt; array would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  &apos;sensorId&apos;,
  &apos;humidity&apos;,
  &apos;pressure&apos;,
  &apos;temperature&apos;,
  &apos;voltage&apos;,
  &apos;count&apos;,
  &apos;total&apos;,
  &apos;lastActivity&apos;
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the keys are extracted, each key is added to the new &lt;code&gt;res&lt;/code&gt; object as a key, and if the &lt;code&gt;B&lt;/code&gt; object&apos;s value at that key exists (&lt;code&gt;B[key]&lt;/code&gt;), it&apos;s added as the value for the &lt;code&gt;res&lt;/code&gt; object, otherwise, the &lt;code&gt;A&lt;/code&gt; object&apos;s value is added instead (even if it&apos;s &lt;code&gt;undefined&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The final &lt;code&gt;res&lt;/code&gt; object returned looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  sensorId: &apos;abc&apos;,
  humidity: 17.609375,
  pressure: 96.768734,
  temperature: 26.703125,
  voltage: 3.24,
  count: 3,
  total: 32,
  lastActivity: &apos;2022-02-15T21:59:18Z&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally the &lt;code&gt;V&lt;/code&gt; and &lt;code&gt;any&lt;/code&gt; references are part of the TypeScript implementation. From looking at the rest of the code, we can see &lt;code&gt;V&lt;/code&gt; is an extension of the &lt;code&gt;HasSensorId&lt;/code&gt; interface, which means any event object will have &lt;code&gt;sensorId&lt;/code&gt; as a property. And &lt;code&gt;any&lt;/code&gt; means the objects passed in to the function could have any properties (or not), so it&apos;s flexible.&lt;/p&gt;
&lt;p&gt;Ok, on to the next function!&lt;/p&gt;
&lt;h3&gt;reducer()&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const reducer = &amp;lt;V extends HasSensorId&amp;gt;(
  groups: Map&amp;lt;string, V&amp;gt;,
  event: V
) =&amp;gt; {
  const key = event.sensorId;
  const previous = groups.get(key);
  const merged: V = mergeObject(previous || {}, event);
  groups.set(key, merged);
  return groups;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;reducer()&lt;/code&gt; function makes excellent use of true &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map&quot;&gt;&lt;code&gt;Map&lt;/code&gt; objects&lt;/a&gt;&lt;/strong&gt; in JavaScript. It uses the &lt;code&gt;HasSensorId&lt;/code&gt; interface as well, ensuring that every object will have a &lt;code&gt;sensorId&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Each &lt;code&gt;event&lt;/code&gt; object passed into the function, has its &lt;code&gt;sensorId&lt;/code&gt; turned into a &lt;code&gt;key&lt;/code&gt; variable. The &lt;code&gt;previous&lt;/code&gt; variable relies on Map&apos;s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get&quot;&gt;&lt;code&gt;get()&lt;/code&gt; function&lt;/a&gt; to fetch any other Map objects that have that same &lt;code&gt;sensorId&lt;/code&gt; key, and if another object is found, the new &lt;code&gt;event&lt;/code&gt; is combined with it when the &lt;code&gt;mergeObject()&lt;/code&gt; function is called. If there&apos;s no matching &lt;code&gt;previous&lt;/code&gt; object, an empty object is passed to &lt;code&gt;mergeObject()&lt;/code&gt;, and a new &lt;code&gt;merged&lt;/code&gt; variable is still returned.&lt;/p&gt;
&lt;p&gt;Finally, the Map &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set&quot;&gt;&lt;code&gt;set()&lt;/code&gt; function&lt;/a&gt; adds the &lt;code&gt;key&lt;/code&gt; and &lt;code&gt;merged&lt;/code&gt; variable to the &lt;code&gt;groups&lt;/code&gt; Map object.&lt;/p&gt;
&lt;p&gt;If our three &lt;code&gt;sensorEvents&lt;/code&gt; are run through this function, the final &lt;code&gt;groups&lt;/code&gt; object that emerges looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map(2) {
  &apos;abc&apos; =&amp;gt; {
    sensorId: &apos;abc&apos;,
    humidity: 17.609375,
    pressure: 96.768734,
    temperature: 26.703125,
    voltage: 3.24,
    count: 3,
    total: 32,
    lastActivity: &apos;2022-02-15T21:59:18Z&apos;
  },
  &apos;def&apos; =&amp;gt; {
    sensorId: &apos;def&apos;,
    humidity: undefined,
    pressure: undefined,
    temperature: undefined,
    voltage: undefined,
    count: 866,
    total: 1776,
    lastActivity: &apos;2022-02-15T22:00:03Z&apos;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And so we move on to the penultimate part of this code example, &lt;code&gt;reducedEventsIterator&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;reducedEventsIterator&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const reducedEventsIterator = sensorEvents
  .reduce(reducer, new Map())
  .values();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;reducedEventsIterator&lt;/code&gt; variable is where we call &lt;code&gt;reduce()&lt;/code&gt; on the &lt;code&gt;sensorEvents&lt;/code&gt; array. The &lt;code&gt;reducer()&lt;/code&gt; function gets passed as the first argument each event in the array must run through, and a new &lt;code&gt;Map()&lt;/code&gt; object is passed as the accumulator object where they will all be gathered together at the end.&lt;/p&gt;
&lt;p&gt;Before the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values&quot;&gt;&lt;code&gt;Object.values()&lt;/code&gt;&lt;/a&gt; method is chained on to the end, the array looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  [
    &apos;abc&apos;,
    {
      sensorId: &apos;abc&apos;,
      humidity: 17.609375,
      pressure: 96.768734,
      temperature: 26.703125,
      voltage: 3.24,
      count: 3,
      total: 32,
      lastActivity: &apos;2022-02-15T21:59:18Z&apos;
    }
  ],
  [
    &apos;def&apos;,
    {
      sensorId: &apos;def&apos;,
      humidity: undefined,
      pressure: undefined,
      temperature: undefined,
      voltage: undefined,
      count: 866,
      total: 1776,
      lastActivity: &apos;2022-02-15T22:00:03Z&apos;
    }
  ]
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After &lt;code&gt;.values()&lt;/code&gt; is called, the final &lt;code&gt;reducedEventsIterator&lt;/code&gt; looks more like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Map Iterator] {
  {
    sensorId: &apos;abc&apos;,
    humidity: 17.609375,
    pressure: 96.768734,
    temperature: 26.703125,
    voltage: 3.24,
    count: 3,
    total: 32,
    lastActivity: &apos;2022-02-15T21:59:18Z&apos;
  },
  {
    sensorId: &apos;def&apos;,
    humidity: undefined,
    pressure: undefined,
    temperature: undefined,
    voltage: undefined,
    count: 866,
    total: 1776,
    lastActivity: &apos;2022-02-15T22:00:03Z&apos;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which brings us to the final step: transforming this Map of objects back to a proper JavaScript array of objects (and all the benefits that entails - arrays are much easier to manipulate).&lt;/p&gt;
&lt;h3&gt;The final merged array: reducedEvents&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const reducedEvents = Array.from(reducedEventsIterator);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Arguably the simplest part of this whole tutorial, the Map of objects is transformed back into an array simply by passing it into the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from&quot;&gt;&lt;code&gt;Array.from()&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Beware &lt;code&gt;Array.from()&lt;/code&gt; for copying deep objects&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have deeply nested objects in some sort of array-like structure that you need to copy, &lt;code&gt;Array.from()&lt;/code&gt; probably won&apos;t work for you. It only makes shallow-copied instances of arrays.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So if we pass the example sensor events displayed above into our &lt;code&gt;reducedEventsIterator()&lt;/code&gt; function here, this is what the final result looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {
    sensorId: &apos;abc&apos;,
    humidity: 17.609375,
    pressure: 96.768734,
    temperature: 26.703125,
    voltage: 3.24,
    count: 3,
    total: 32,
    lastActivity: &apos;2022-02-15T21:59:18Z&apos;
  },
  {
    sensorId: &apos;def&apos;,
    humidity: undefined,
    pressure: undefined,
    temperature: undefined,
    voltage: undefined,
    count: 866,
    total: 1776,
    lastActivity: &apos;2022-02-15T22:00:03Z&apos;
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there you have it: an array of freshly merged objects with all available properties present.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;One reason I enjoy being a software engineer is because of all the interesting problems I get to solve regularly. Lately, when I was building a web app to display data from IoT sensors at work, I ran into a more unique problem: taking an array of sensor events and merging the events together if they belonged to the same sensor. The catch was, all the events had the same properties, but depending on which event you were looking at, half the properties had values of &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So instead of being able to use the spread operator or &lt;code&gt;Object.assign()&lt;/code&gt; to get these events merged into one object, I had to get more creative with a few extra functions and the &lt;code&gt;reduce()&lt;/code&gt; method. But it worked - even with TypeScript in the mix.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope this little bit of JavaScript helps you out in future - who&apos;d have thought merging objects could be so interesting, right?&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals&quot;&gt;Spread operator&lt;/a&gt; Mozilla docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign&quot;&gt;Object.assign()&lt;/a&gt; Mozilla docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map&quot;&gt;Map object&lt;/a&gt; Mozilla docs&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=merge-js-objects&quot;&gt;website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JavaScript array method &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot;&gt;reduce()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>typescript</category></item><item><title>Use CSS Grid to Make a Fixed Sidebar with Scrollable Main Body</title><link>https://www.paigeniedringhaus.com/blog/use-css-grid-to-make-a-fixed-sidebar-with-scrollable-main-body/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/use-css-grid-to-make-a-fixed-sidebar-with-scrollable-main-body/</guid><description>Forget position: absolute and position: fixed , reach for CSS Grid instead.</description><pubDate>Sat, 14 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-grid-fixed-sidebar/hardware-handler-hero.png&quot; alt=&quot;Hardware Handler product list page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Last year I authored a web development course on &lt;a href=&quot;https://www.newline.co/courses/newline-guide-to-modernizing-an-enterprise-react-app&quot;&gt;modernizing enterprise React applications&lt;/a&gt;. It was a big undertaking, but I&apos;m proud to have put out a comprehensive guide to show developers just what it takes to build and maintain a large scale, long-running React application: tooling, testing, refactoring, design systems, and more.&lt;/p&gt;
&lt;p&gt;For this course, I built a React project similar to what you might find when joining an existing enterprise company: it&apos;s an internal application used by product managers to manage assortments of tools and other home improvement items and select which ones should be shipped to stores to be sold. I named it &quot;Hardware Handler&quot;.&lt;/p&gt;
&lt;p&gt;The project started out using an outdated version of React, having no tooling for easier setup, no automated tests, no React Hooks, no state management, no component library, and so on and so forth. As the course progressed through each module, I focused one aspect of the project and showed how to update the project to today&apos;s high quality software standards: adding React Testing Library and Jest for unit tests or refactoring class-based React components to use Hooks, for example.&lt;/p&gt;
&lt;p&gt;One interesting thing I encountered while building the sample project is that I wanted a product page that showed all the possible products available, but also have a fixed sidebar with filtering options, so users could filter down products by a particular department or a particular brand. Now you might expect that I would reach for some CSS like &lt;code&gt;position: fixed&lt;/code&gt; or &lt;code&gt;position: absolute&lt;/code&gt; to keep this sidebar in place and essentially remove the sidebar from the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flow_Layout/In_Flow_and_Out_of_Flow#taking_an_item_out_of_flow&quot;&gt;normal flow of the DOM&lt;/a&gt;, but I didn&apos;t need to. Instead, all I needed were a few simple &lt;strong&gt;CSS Grid&lt;/strong&gt; properties.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;re not familiar with CSS Grid, it&apos;s a relatively new addition to CSS, and it excels at dividing a page into major regions and enabling an author to align elements into columns and rows.&lt;/p&gt;
&lt;p&gt;I&apos;d highly recommend checking out the &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout&quot;&gt;MDN docs&lt;/a&gt;&lt;/strong&gt; and the &lt;strong&gt;&lt;a href=&quot;https://css-tricks.com/snippets/css/complete-guide-grid/&quot;&gt;CSS-Tricks &quot;A Complete Guide to Grid&quot;&lt;/a&gt;&lt;/strong&gt;, for more CSS Grid info.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to build your own fixed sidebar in an application while still allowing the main body content to scroll freely with the help of CSS Grid.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Below is a video of what the final page looks like: notice the page title and filters on the lefthand side stay in place while the product cards scroll down in the main content space.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=mXR8hBspl90&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Set up the &lt;code&gt;ProductList&lt;/code&gt; component&apos;s HTML (or JSX)&lt;/h2&gt;
&lt;p&gt;Before we can start applying the CSS Grid Layout to our page, we must actually &lt;em&gt;code&lt;/em&gt; a page full of HTML elements to apply the grid &lt;em&gt;to&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;My project was built with the React framework, so the example code I&apos;ll be walking through would normally contain React Hooks, state, functions, and JSX, but for this blog post, everything besides the JSX is largely unnecessary, so I&apos;ve cut it out.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It should be relatively straightforward to translate the remaining JSX into HTML or another JS-powered framework, if you so desire.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&apos;s a condensed version of the actual &lt;code&gt;ProductList&lt;/code&gt; component, please note I&apos;ve eliminated much of the React-specific code and things like error handling messages, loading components, etc. to focus on the HTML that our CSS will apply to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ProductList.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// other imports for React, components, constants, etc.
import &apos;./ProductList.css&apos;;

const ProductList = () =&amp;gt; {
  // all sorts of state variables here: products, loading, errors, etc.

  // logic to facilitate adding items to checkout

  // logic for filtering products based on brand name or department 

  return (
    &amp;lt;div className=&quot;product-list-container&quot;&amp;gt;
      &amp;lt;section className=&quot;filter-wrapper&quot;&amp;gt;
        &amp;lt;p className=&quot;filter-title&quot;&amp;gt;Filter by Department&amp;lt;/p&amp;gt;
        &amp;lt;div className=&quot;filter-data&quot;&amp;gt;
          {filtersByDepartment.map((filter) =&amp;gt; (
            &amp;lt;span key={filter.id} className=&quot;filter-item&quot;&amp;gt;
              &amp;lt;label htmlFor={filter.id}&amp;gt;{filter.name}&amp;lt;/label&amp;gt;
              &amp;lt;input
                className=&quot;filter-checkbox&quot;
                id={filter.id}
                type=&quot;checkbox&quot;
                checked={activeFilter.includes(filter.id)}
                onChange={() =&amp;gt; onFilterChange(filter.id)}
              /&amp;gt;
            &amp;lt;/span&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;
        &amp;lt;p className=&quot;filter-title&quot;&amp;gt;Filter by Brand&amp;lt;/p&amp;gt;
        &amp;lt;div className=&quot;filter-data&quot;&amp;gt;
          {filtersByBrand.map((filter) =&amp;gt; (
            &amp;lt;span key={filter.value} className=&quot;filter-item&quot;&amp;gt;
              &amp;lt;label htmlFor={filter.value}&amp;gt;{filter.name}&amp;lt;/label&amp;gt;
              &amp;lt;input
                className=&quot;filter-checkbox&quot;
                id={filter.value}
                type=&quot;checkbox&quot;
                checked={activeFilter.includes(filter.value)}
                onChange={() =&amp;gt; onFilterChange(filter.value)}
              /&amp;gt;
            &amp;lt;/span&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;
      &amp;lt;/section&amp;gt;
      &amp;lt;h1 className=&quot;product-list-header&quot;&amp;gt;My Products&amp;lt;/h1&amp;gt;
      &amp;lt;section className=&quot;products-container&quot;&amp;gt;
        &amp;lt;div className=&quot;product-list-product-wrapper&quot;&amp;gt;
          {filteredList.map((product) =&amp;gt; (
            &amp;lt;Product
              key={product.id}
              product={product}
              addItemToCheckout={addItemToCheckout}
            /&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;
      &amp;lt;/section&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default ProductList;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I cut out a lot of unneeded noise, but that&apos;s still plenty happening in this component to render both a list of all the products and two different filtering options, so let&apos;s talk through what&apos;s happening in this code snippet.&lt;/p&gt;
&lt;p&gt;The first &lt;code&gt;section&lt;/code&gt; tag is wrapping our various filters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One filtering option users have is to filter products by department, hence the array-based state variable titled &lt;code&gt;filtersByDepartment&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;And the other filtering option is to filter products by brand name: &lt;code&gt;filtersByBrand&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these arrays of data produces a set of checkboxes that users can check to narrow down the list of products being displayed on screen at any one time.&lt;/p&gt;
&lt;p&gt;Which brings us to the final &lt;code&gt;section&lt;/code&gt; of the JSX where the &lt;code&gt;filteredList&lt;/code&gt; variable is being rendered - that variable is a list of all the products that fit into the selected filter criteria.&lt;/p&gt;
&lt;p&gt;Also take note of the classes attached to many of these elements: &lt;code&gt;product-list-container&lt;/code&gt;, &lt;code&gt;filter-wrapper&lt;/code&gt;, &lt;code&gt;product-container&lt;/code&gt; - they&apos;ll come into play in the next section when we write the CSS.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;ve omitted the filtering logic that&apos;s also in this component because it isn&apos;t central to illustrating the point in this post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that&apos;s what&apos;s going on in this component.&lt;/p&gt;
&lt;h2&gt;Add CSS Grid to Our HTML&lt;/h2&gt;
&lt;p&gt;With our JSX (or HTML) set up, we can get to the CSS portion of this blog post. This is the entirety of the CSS contained in our &lt;code&gt;ProductList.css&lt;/code&gt; file - there are some things that are being inherited from other global CSS - things like &lt;code&gt;background-color&lt;/code&gt; or &lt;code&gt;font-size&lt;/code&gt;, but by and large, this is all you&apos;ll need to achieve the desired effect.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ProductList.css&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* styling for the whole product list container, including the filters on the side */
.product-list-container {
  display: grid;
  grid-template-rows: 55px calc(100vh - 55px);
  grid-template-columns: 220px auto;
  grid-template-areas:
    &apos;filter header&apos;
    &apos;filter products&apos;;
}

/* styling for just the main list of products displayed on screen */
.product-list-header {
  display: flex;
  align-items: center;
  justify-content: center;
  grid-area: header;
}

.products-container {
  grid-area: products;
  overflow: auto;
}

.product-list-product-wrapper {
  display: flex;
  flex-wrap: wrap;
  margin: auto;
}

/* styling for the filters */
.filter-wrapper {
  padding: 10px;
  background-color: #ffcfae;
  grid-area: filter;
  height: 100vh;
}

.filter-title {
  font-weight: 600;
}

.filter-data {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  border-top: 2px solid #012025;
}

.filter-item {
  margin: 8px 16px;
}

.filter-checkbox {
  margin-left: 10px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&apos;ll notice as you look through the CSS that I have two distinct sets of classes in here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ones that are &lt;code&gt;product&lt;/code&gt; based&lt;/li&gt;
&lt;li&gt;And ones that are &lt;code&gt;filter&lt;/code&gt; based.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It should be fairly self-explanatory what each set  of classes is responsible for styling in the JSX; aside from the &lt;code&gt;product-list-container&lt;/code&gt; that styles the whole page (and lays out our overall grid), &lt;code&gt;product&lt;/code&gt; classes are for the product cards displayed on the page.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-grid-fixed-sidebar/products.png&quot; alt=&quot;Hardware Handler products&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;An example of the page title and product cards displayed on the product list page&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And &lt;code&gt;filter&lt;/code&gt; classes are for the filters on the left hand side.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-grid-fixed-sidebar/filters.png&quot; alt=&quot;Hardware Handler filters on product list page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The filters to filter down the products displayed on the page&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s talk about some of the individual CSS classes in the code snippet now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;product-list-container&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.product-list-container {
  display: grid;
  grid-template-rows: 55px calc(100vh - 55px);
  grid-template-columns: 220px auto;
  grid-template-areas:
    &apos;filter header&apos;
    &apos;filter products&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;product-list-container&lt;/code&gt; CSS at the beginning of the file is the first thing we need to focus on here because it&apos;s where the CSS Grid is defined and laid out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;display: grid&lt;/code&gt;&lt;/strong&gt;: Just like when using CSS Flexbox, the first thing we must do to let our CSS know we intend to use Grid instead of &lt;code&gt;display: flex&lt;/code&gt; or &lt;code&gt;display: block&lt;/code&gt;, is set the &lt;code&gt;display&lt;/code&gt; property to &lt;code&gt;grid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grid-template-rows: 55px calc(100vh - 55px)&lt;/code&gt;&lt;/strong&gt;: Next, we define the rows we want our grid to have.
&lt;ul&gt;
&lt;li&gt;If you look at my page&apos;s layout below the nav bar which is always present, there&apos;s the page header that says &quot;My Products&quot; and then the body of the rows of product cards, so in our case there really only needs to be two rows: one for the header and another for the list of products.&lt;/li&gt;
&lt;li&gt;Looking at the code, I gave the page title &lt;code&gt;55px&lt;/code&gt; of room and then the cards the remaining portion of the viewport to the cards by using the CSS &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/calc&quot;&gt;&lt;code&gt;calc&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; function to subtract the &lt;code&gt;55px&lt;/code&gt; from whole height of the &lt;a href=&quot;https://css-tricks.com/fun-viewport-units/&quot;&gt;viewport&lt;/a&gt;: &lt;code&gt;100vh&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grid-template-columns: 220px auto&lt;/code&gt;&lt;/strong&gt;: As with defining rows, CSS Grid also allows us to define columns, and since this page has a side bar and a main content portion, 2 columns should do just fine. The sidebar portion will be &lt;code&gt;220px&lt;/code&gt; wide and the rest of the space will be taken up by the products, so &lt;code&gt;auto&lt;/code&gt; will suffice here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grid-template-areas: &apos;filter header&apos; &apos;filter products&apos;&lt;/code&gt;&lt;/strong&gt;: This last line is an interesting one. While there&apos;s multiple ways to lay out CSS Grid, one of the handiest features is the ability to use &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas&quot;&gt;&lt;code&gt;grid-template-areas&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; which let you name grid areas and then lay them out according to those names.
&lt;ul&gt;
&lt;li&gt;Oftentimes &lt;code&gt;grid-row&lt;/code&gt; and &lt;code&gt;grid-column&lt;/code&gt; will suffice to place things where they belong on the grid, but in this instance, &lt;code&gt;grid-template-areas&lt;/code&gt; makes it really easy to lay out everything exactly as it should be on the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see from looking at the code, the grid element named &lt;code&gt;filter&lt;/code&gt; will take up &lt;strong&gt;both grid rows&lt;/strong&gt;, and the &lt;strong&gt;first grid column&lt;/strong&gt; (the one that is &lt;code&gt;220px&lt;/code&gt; wide).&lt;/p&gt;
&lt;p&gt;The grid element &lt;code&gt;header&lt;/code&gt; will take up just the &lt;strong&gt;first row&lt;/strong&gt; of the grid (the &lt;code&gt;55px&lt;/code&gt; high row), and the &lt;strong&gt;second column&lt;/strong&gt;, and the grid element &lt;code&gt;products&lt;/code&gt; will take up the &lt;strong&gt;second row&lt;/strong&gt; and &lt;strong&gt;second column&lt;/strong&gt; of the grid (all the remaining space, basically).&lt;/p&gt;
&lt;p&gt;And now that the CSS grid is laid out and its columns and rows are defined, all that&apos;s left is to name the classes to match the grid elements defined.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;product-list-header&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.product-list-header {
  display: flex;
  align-items: center;
  justify-content: center;
  grid-area: header;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&apos;ll just work our way down the CSS, I think that&apos;s easiest here, and the first class we&apos;ll focus on after &lt;code&gt;product-list-container&lt;/code&gt; is &lt;code&gt;product-list-header&lt;/code&gt;. The name should give you a hint of what this class is for: it wraps the &quot;My Products&quot; title of the page.&lt;/p&gt;
&lt;p&gt;In addition to a little CSS Flexbox magic to align the &quot;My Products&quot; page title both horizontally and vertically within its space on the page, it also gets assigned a &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area&quot;&gt;&lt;code&gt;grid area&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grid-area: header&lt;/code&gt;&lt;/strong&gt;: The &lt;code&gt;grid-area&lt;/code&gt; is the property that tells an element where it should live within the parent grid container, so by giving this element the named grid area of &lt;code&gt;header&lt;/code&gt;, it knows it should fit into the &lt;code&gt;header&lt;/code&gt; space as defined in the &lt;code&gt;grid-template-area&lt;/code&gt; in the &lt;code&gt;product-list-container&lt;/code&gt; class.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;products-container&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.products-container {
  grid-area: products;
  overflow: auto;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next class we encounter on the way down the CSS file is the &lt;code&gt;products-container&lt;/code&gt; class. This element only needs two CSS properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grid-area: products&lt;/code&gt;&lt;/strong&gt;: Once more, we assign this element the &lt;code&gt;grid-area&lt;/code&gt; name of &lt;code&gt;products&lt;/code&gt;, telling it that it should occupy all the space in the grid defined as &lt;code&gt;products&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;overflow: auto&lt;/code&gt;&lt;/strong&gt;: We also need to add the property of &lt;code&gt;overflow: auto&lt;/code&gt; so that the list of products will scroll independently of the other elements on the page: the &lt;code&gt;header&lt;/code&gt; and the &lt;code&gt;sidebar&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;overflow: auto;&lt;/strong&gt; is a key ingredient to our fixed sidebar remaining fixed.&lt;/p&gt;
&lt;p&gt;Without it, if there&apos;s more products than can be displayed at once on screen, the products will still wrap and take up all the space they need but the whole grid will scroll to display them (including scrolling beyond the space the sidebar occupies). No bueno.&lt;/p&gt;
&lt;p&gt;Just don&apos;t forget to add this property to the &lt;code&gt;products-container&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;filter-wrapper&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.filter-wrapper {
  padding: 10px;
  background-color: #ffcfae;
  grid-area: filter;
  height: 100vh;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we have to skip down through a few classes that exist to organize the products so they lay out nicely in rows on the page, regardless of the amount of items, until we come to the &lt;code&gt;filter-wrapper&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;There&apos;s some standard &lt;code&gt;padding&lt;/code&gt;, and &lt;code&gt;background-color&lt;/code&gt; CSS properties at work, but the two properties to focus on are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;grid-area: filter&lt;/code&gt;&lt;/strong&gt;: Our final &lt;code&gt;grid-area&lt;/code&gt; designation has arrived. This class gets the &lt;code&gt;filter&lt;/code&gt; property, so it will know to fill up the left hand side of the screen for both grid rows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;height: 100vh&lt;/code&gt;&lt;/strong&gt;: The viewport height (&lt;code&gt;vh&lt;/code&gt;) unit makes another appearance for this element. Setting the filter element&apos;s height to &lt;code&gt;100vh&lt;/code&gt; ensures it will always go down to the bottom of the page (and look like a true sidebar) no matter how many actual filters are available or how far down the product list a user scrolls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then after this class there&apos;s a few additional ones to lay out all the filter checkboxes in a nice vertical row with some decent spacing between them.&lt;/p&gt;
&lt;p&gt;Again, not as important to this particular post as the four classes highlighted above.&lt;/p&gt;
&lt;p&gt;And that&apos;s it: a fixed sidebar with other elements on the page that can scroll freely.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building a sample application for users taking my course about how to modernize React applications helped me learn some cool new web development techniques along the way, not the least of which was how to build a page with a static sidebar and a scrolling center section using CSS Grid.&lt;/p&gt;
&lt;p&gt;While this tutorial used CSS Grid to build a fixed sidebar, it could be applied to so many different situations that call for something similar: a table of contents for a blog post, a set of store details alongside a map of their locations, food items already in a cart as a user adds more to the list - the possibilities go on.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you enjoyed seeing how just a few CSS Grid commands can eliminate the need to break the DOM flow with CSS like &lt;code&gt;position: fixed&lt;/code&gt; and still give fine grained control. It takes a little practice to get the hang of CSS Grid, but once you do, I guarantee you won&apos;t want to go back. I can&apos;t imagine doing web development today without CSS Flexbox and CSS Grid at my fingertips.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you enjoyed this post, you may also be interested in checking out my full course &lt;strong&gt;&lt;a href=&quot;https://www.newline.co/courses/newline-guide-to-modernizing-an-enterprise-react-app&quot;&gt;&quot;The newline Guide to Modernizing an Enterprise React App&quot;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 10 modules and 54 lessons, I cover all the things I learned while building applications at The Home Depot. I deep dive into building and maintaining large, mission-critical React applications - because at big companies like this, it&apos;s about so much more than just making the code work.&lt;/p&gt;
&lt;p&gt;From tooling and refactoring, to testing and design system libraries, there&apos;s a ton of material and hands-on practice here to prepare any React developer to build software that lives up to today&apos;s high standards. I hope you&apos;ll check it out.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout&quot;&gt;CSS Grid&lt;/a&gt; Mozilla docs&lt;/li&gt;
&lt;li&gt;CSS-Tricks: &lt;a href=&quot;https://css-tricks.com/snippets/css/complete-guide-grid/&quot;&gt;A Complete Guide to Grid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.newline.co/courses/newline-guide-to-modernizing-an-enterprise-react-app&quot;&gt;The newline Guide to Modernizing an Enterprise React App&lt;/a&gt; course&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox&quot;&gt;CSS Flexbox&lt;/a&gt; Mozilla docs&lt;/li&gt;
&lt;li&gt;CSS-Tricks: &lt;a href=&quot;https://css-tricks.com/snippets/css/a-guide-to-flexbox/&quot;&gt;A Complete Guide to Flexbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>css</category><category>react</category><category>javascript</category></item><item><title>Customize and Style Complex Data in React Table</title><link>https://www.paigeniedringhaus.com/blog/customize-and-style-complex-data-in-react-table/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/customize-and-style-complex-data-in-react-table/</guid><description>Sometimes table columns and cells need data from multiple object properties.</description><pubDate>Mon, 04 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/customize-complex-data-react-table/spreadsheet.jpg&quot; alt=&quot;Spreadsheet of data on a laptop screen&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This past summer, I started working for an Internet of Things (IoT) startup, &lt;strong&gt;&lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Blues Wireless&lt;/a&gt;&lt;/strong&gt;, that aims to make IoT development simpler - even when reliable Internet connections are not available. Blues does this via &lt;strong&gt;&lt;a href=&quot;https://blues.io/products/notecard/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecards&lt;/a&gt;&lt;/strong&gt; - prepaid cellular devices that can be embedded into any IoT device &quot;on the edge&quot; to transmit sensor data as JSON to a secure cloud: &lt;strong&gt;&lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notehub&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Frontend web development is what I specialize in, not hardware or firmware development, so as I get more familiar with IoT development, I started by building a simpler project: an &lt;strong&gt;&lt;a href=&quot;https://www.hackster.io/paige-niedringhaus/low-code-gps-asset-tracker-and-map-display-b10419&quot;&gt;asset tracker&lt;/a&gt;&lt;/strong&gt; using a Blues &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/note-nbgl-500/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecard&lt;/a&gt;&lt;/strong&gt;, Blues &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/carr-al/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecarrier AL&lt;/a&gt;&lt;/strong&gt; with a built-in GPS antenna, and a small &lt;strong&gt;&lt;a href=&quot;https://www.adafruit.com/product/328&quot;&gt;lithium-ion polymer (LiPo) battery&lt;/a&gt;&lt;/strong&gt; to power the device.&lt;/p&gt;
&lt;p&gt;With the help of the Blues &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/guides-and-tutorials/notecard-guides/asset-tracking/?&amp;amp;utm_source=medium.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;developer experience docs&lt;/a&gt;&lt;/strong&gt;, I had temperature, voltage, and GPS location data being delivered to the Notehub cloud from my tracker in less than half an hour. A good start, but the way that data from sensors really becomes useful is when it&apos;s displayed to users in some sort of UI. It could be maps, charts, or in my case, tables.&lt;/p&gt;
&lt;p&gt;So I wanted to take my data from the Notehub cloud and pump it into a custom-made dashboard to track and display the Notecard&apos;s location and data readings from the real world. As a frontend developer, React is my current JavaScript framework of choice, and to get some more Next.js experience, I decided to build a Next.js TypeScript-powered dashboard, and I learned a ton of interesting things in the process. Over the course of a series of blog posts (which I&apos;ll link to in this article), I&apos;ll share with you some of the cools things I discovered.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you missed the first two installments of my blogs about building an asset tracking map in Next.js using React Leaflet, you can read it &lt;strong&gt;&lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The second one about making data visualization charts is available &lt;strong&gt;&lt;a href=&quot;./build-and-custom-style-recharts-data-charts&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;This post will show you how to use the React Table library to make a data table and customize the data displayed in the cells, filled with real-world location data.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s what the final dashboard looks like - the table of location coordinates  and data at the bottom is the focus for this particular post.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=uUJiX9q8x9M&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Create a table component in the Next.js app&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This article will not go through the initial setup of a brand new Next.js app - that&apos;s outside the scope of this blog. If you&apos;re starting from scratch, I would recommend following the &lt;a href=&quot;https://nextjs.org/docs/basic-features/typescript&quot;&gt;Next.js starter app with TypeScript documentation&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;d prefer, you can also fork and download my whole, working code base from the GitHub repo &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Install table dependencies&lt;/h3&gt;
&lt;p&gt;Let&apos;s kick off this post by adding the necessary table library to this Next.js app.&lt;/p&gt;
&lt;p&gt;Although there&apos;s many React-focused table libraries and components to choose from, I went with the &lt;strong&gt;&lt;a href=&quot;https://react-table.tanstack.com/&quot;&gt;React Table library&lt;/a&gt;&lt;/strong&gt; because it is a &quot;headless&quot; table-library that gives you a collection of lightweight, composable, and extensible hooks for building powerful tools and data grid experiences.&lt;/p&gt;
&lt;p&gt;The &quot;headless&quot; part means that there&apos;s no markup or styles rendered via React Table, so you can customize and style it exactly as you want. It may sound a little odd at first, but it actually ends up working out really well as you&apos;ll see soon.&lt;/p&gt;
&lt;p&gt;So, install React Table in the Next.js app by typing this command into the terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install react-table 
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; React Table is compatible with React v16.8+, so please ensure your app&apos;s version of React is at least to here if not above.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;TypeScript Note:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re using TypeScript in your project (like I am), you&apos;ll also want to install the following dev dependency to avoid TypeScript errors:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install @types/react-table --save-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now, we&apos;re ready to start using React Table to make a table in the application to display location data.&lt;/p&gt;
&lt;h3&gt;Create the &lt;code&gt;&amp;lt;EventTable&amp;gt;&lt;/code&gt; component and style it&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/customize-complex-data-react-table/table-hero.png&quot; alt=&quot;Table showing Notecard location, timestamp, and nearest cell tower at the time.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The custom styled event table we&apos;ll be building.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;For my table, I want to display &lt;strong&gt;&quot;events&quot;&lt;/strong&gt;, which are what Blues Wireless&apos;s Notecards produce and send to its cloud Notehub. Each event is a separate JSON object, and although there are all sorts of different event types stored in a single project, the ones of concern today are the &lt;strong&gt;&lt;code&gt;_track.qo&lt;/code&gt;&lt;/strong&gt; events.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;_track.qo&lt;/code&gt; event example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A typical &lt;code&gt;_track.qo&lt;/code&gt; event looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;uid&quot;: &quot;d7cf7475-45ff-4d8c-b02a-64de9f15f538&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T16:10:52Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T16:11:29Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 3,
      &quot;seconds&quot;: 90,
      &quot;motion&quot;: 76,
      &quot;temperature&quot;: 20.1875,
      &quot;time&quot;: 1636123230,
      &quot;voltage&quot;: 4.2578125
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T16:10:53Z&quot;,
      &quot;name&quot;: &quot;Sandy Springs, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.913747500000014,
      &quot;longitude&quot;: -84.35008984375
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It contains data like &lt;code&gt;temperature&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;voltage&lt;/code&gt;, and &lt;code&gt;gps_location&lt;/code&gt; coordinates. Useful stuff you might want to display in a table for easy readability, right?&lt;/p&gt;
&lt;p&gt;Right. So here&apos;s how I built a reusable table component in a new file in the Next.js app named &lt;code&gt;EventTable.tsx&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I recommend copying the following code and pasting it into your own component file, and you can also click on the file title below to see the live code repo in GitHub.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/src/components/EventTable.tsx&quot;&gt;&lt;code&gt;EventTable&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable react/jsx-key */
import { usePagination, useTable, Column } from &quot;react-table&quot;;
import styles from &quot;../../styles/EventTable.module.scss&quot;;

const EventTable = ({
  columns,
  data,
}: {
  data: Array&amp;lt;any&amp;gt;;
  columns: Array&amp;lt;Column&amp;gt;;
}) =&amp;gt; {
  const {
    getTableProps, // table props from react-table
    getTableBodyProps, // table body props from react-table
    headerGroups, // headerGroups, if your table has groupings
    prepareRow, // rows for the table based on the data passed
    page, // Instead of using &apos;rows&apos;, we&apos;ll use page
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data,
    },
    usePagination
  );

  return (
    &amp;lt;&amp;gt;
      &amp;lt;h2&amp;gt;Tracker Events&amp;lt;/h2&amp;gt;
      &amp;lt;table className={styles.tableWrapper} {...getTableProps()}&amp;gt;
        &amp;lt;thead&amp;gt;
          {headerGroups.map((headerGroup) =&amp;gt; (
            &amp;lt;tr {...headerGroup.getHeaderGroupProps()}&amp;gt;
              {headerGroup.headers.map((column, _index) =&amp;gt; (
                &amp;lt;th {...column.getHeaderProps()}&amp;gt;{column.render(&quot;Header&quot;)}&amp;lt;/th&amp;gt;
              ))}
            &amp;lt;/tr&amp;gt;
          ))}
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody {...getTableBodyProps()}&amp;gt;
          {page.map((row) =&amp;gt; {
            prepareRow(row);
            return (
              &amp;lt;tr {...row.getRowProps()}&amp;gt;
                {row.cells.map((cell) =&amp;gt; {
                  return (
                    &amp;lt;td {...cell.getCellProps()}&amp;gt;{cell.render(&quot;Cell&quot;)}&amp;lt;/td&amp;gt;
                  );
                })}
              &amp;lt;/tr&amp;gt;
            );
          })}
        &amp;lt;/tbody&amp;gt;
      &amp;lt;/table&amp;gt;
      &amp;lt;div className=&quot;pagination&quot;&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; gotoPage(0)} disabled={!canPreviousPage}&amp;gt;
          {&quot;&amp;lt;&amp;lt;&quot;}
        &amp;lt;/button&amp;gt;{&quot; &quot;}
        &amp;lt;button onClick={() =&amp;gt; previousPage()} disabled={!canPreviousPage}&amp;gt;
          {&quot;&amp;lt;&quot;}
        &amp;lt;/button&amp;gt;{&quot; &quot;}
        &amp;lt;button onClick={() =&amp;gt; nextPage()} disabled={!canNextPage}&amp;gt;
          {&quot;&amp;gt;&quot;}
        &amp;lt;/button&amp;gt;{&quot; &quot;}
        &amp;lt;button onClick={() =&amp;gt; gotoPage(pageCount - 1)} disabled={!canNextPage}&amp;gt;
          {&quot;&amp;gt;&amp;gt;&quot;}
        &amp;lt;/button&amp;gt;{&quot; &quot;}
        &amp;lt;span&amp;gt;
          Page{&quot; &quot;}
          &amp;lt;strong&amp;gt;
            {pageIndex + 1} of {pageOptions.length}
          &amp;lt;/strong&amp;gt;{&quot; &quot;}
        &amp;lt;/span&amp;gt;
        &amp;lt;span&amp;gt;
          | Go to page:{&quot; &quot;}
          &amp;lt;input
            type=&quot;number&quot;
            defaultValue={pageIndex + 1}
            onChange={(e) =&amp;gt; {
              const page = e.target.value ? Number(e.target.value) - 1 : 0;
              gotoPage(page);
            }}
            style={{ width: &quot;100px&quot; }}
          /&amp;gt;
        &amp;lt;/span&amp;gt;{&quot; &quot;}
        &amp;lt;select
          value={pageSize}
          onChange={(e) =&amp;gt; {
            setPageSize(Number(e.target.value));
          }}
        &amp;gt;
          {[10, 20, 30, 40, 50].map((pageSize) =&amp;gt; (
            &amp;lt;option key={pageSize} value={pageSize}&amp;gt;
              Show {pageSize}
            &amp;lt;/option&amp;gt;
          ))}
        &amp;lt;/select&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default EventTable;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s go through all the things happening in this table component - the amount of props being destructured right off the bat can be a little overwhelming at first glance.&lt;/p&gt;
&lt;p&gt;Although the actual import list from the &lt;code&gt;react-table&lt;/code&gt; library is very small - just three separate methods, the depth of functionality contained within expands quickly after the component&apos;s declared.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://react-table.tanstack.com/docs/api/useTable&quot;&gt;&lt;code&gt;useTable&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://react-table.tanstack.com/docs/api/usePagination&quot;&gt;&lt;code&gt;usePagination&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; combined make up all of the properties being destructured at the beginning of the component, which makes sense - this is a table libary we&apos;re working with, after all.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From these two hooks we get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getTableProps&lt;/code&gt;&lt;/strong&gt; - the table props from react-table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getTableBodyProps&lt;/code&gt;&lt;/strong&gt; - the table body props from react-table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;headerGroups&lt;/code&gt;&lt;/strong&gt; - headerGroups, if your table has groupings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;prepareRow&lt;/code&gt;&lt;/strong&gt; - rows for the table based on the data passed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;page&lt;/code&gt;&lt;/strong&gt; - necessary for having a paginated table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;canPreviousPage&lt;/code&gt;&lt;/strong&gt; - boolean if there are previous pages the table can paginate to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;canNextPage&lt;/code&gt;&lt;/strong&gt; - boolean if there are future pages the table can paginate to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;pageOptions&lt;/code&gt;&lt;/strong&gt; - an array corresponding to available pages in the table (useful for select interfaces allowing users to type in a page number instead of using buttons).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;pageCount&lt;/code&gt;&lt;/strong&gt; - amount of pages available based on current page size value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;gotoPage&lt;/code&gt;&lt;/strong&gt; - function to set page index to value specified by user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;nextPage&lt;/code&gt;&lt;/strong&gt; - function to increase page index by one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;previousPage&lt;/code&gt;&lt;/strong&gt; - function to decrease page index by one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;setPageSize&lt;/code&gt;&lt;/strong&gt; - function to set page size to a new value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;state: { pageIndex, pageSize }&lt;/code&gt;&lt;/strong&gt; - currently set page index and page size for table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whew! But after all that initial destructuring the &lt;code&gt;&amp;lt;EventTable&amp;gt;&lt;/code&gt; component only takes in two initial array props: &lt;code&gt;columns&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt;. Note that both of these arrays of values must be &lt;strong&gt;memoized&lt;/strong&gt;, according to the React Table &lt;a href=&quot;https://react-table.tanstack.com/docs/api/useTable&quot;&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;data&lt;/code&gt;&lt;/strong&gt; is what the &lt;code&gt;useTable&lt;/code&gt; hook turns into rows and pages of event data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;columns&lt;/code&gt;&lt;/strong&gt; are the core columns configuration object for the entire table (put a pin in this array - we&apos;ll get to configuring it later in this article).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And after that it&apos;s all JSX in this component.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;headerGroups&lt;/code&gt; are mapped over to render any headers at the very top of the table - our table will only have one header, but you could have multiple headers helping to visually show grouping of columns.&lt;/p&gt;
&lt;p&gt;Then, each &lt;code&gt;page&lt;/code&gt; is mapped over, each &lt;code&gt;row&lt;/code&gt; of data in that page is extracted and each &lt;code&gt;cell&lt;/code&gt; in that row is rendered.&lt;/p&gt;
&lt;p&gt;Followed by buttons galore and a custom input, which are added to make pagination possible in many different ways; &lt;code&gt;canPreviousPage&lt;/code&gt;, &lt;code&gt;nextPage&lt;/code&gt;, and &lt;code&gt;goToPage&lt;/code&gt;, for example.&lt;/p&gt;
&lt;p&gt;And finally, &lt;code&gt;pageSize&lt;/code&gt;, or the number of rows displayed in each page, and is also made dynamic.&lt;/p&gt;
&lt;p&gt;It&apos;s a lot of JSX, but it is fairly straightforward once some of the initial mapping and iterating is out of the way.&lt;/p&gt;
&lt;p&gt;The nice part though, is that the &lt;code&gt;react-table&lt;/code&gt; library has all of this functionality &lt;em&gt;built-in&lt;/em&gt;, and all we have to pass it in terms of data to get all this is two arrays. That&apos;s it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Style the table&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now for some very simple styling to make this table presentable looking. As I mentioned before, React Table considers itself more of a headless table utility library, and as such, applies no default styling to any of the tables it generates out of the box.&lt;/p&gt;
&lt;p&gt;Luckily, this also means there&apos;s no default styling to &lt;em&gt;undo&lt;/em&gt;, so just a few lines of CSS can make this table look nice.&lt;/p&gt;
&lt;p&gt;Wherever you&apos;re keeping styles in the Next.js app (I kept all of mine in the &lt;code&gt;styles/&lt;/code&gt; folder), create a new CSS or SCSS file named &lt;code&gt;EventTable.module.css&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;m using Sass in my Next project in addition to the built-in &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/built-in-css-support#adding-component-level-css&quot;&gt;CSS module styling&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There&apos;s very little Sass nesting going on in this particular SCSS file so I think it will be easy enough to follow, but if you&apos;d like to set up Sass in your own Next project, you can follow Next&apos;s directions &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/built-in-css-support#sass-support&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/styles/EventTable.module.scss&quot;&gt;&lt;code&gt;EventTable.module.scss&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.tableWrapper {
  border-spacing: 0;
  border: 1px solid #ededed;
  width: 100%;

  tr:nth-child(2n) {
    background-color: #fafafa;
  }

  th {
    padding: 15px;
  }

  td {
    padding: 5px 10px;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this SCSS file we&apos;re making a &lt;code&gt;tableWrapper&lt;/code&gt; class to give the table a light border (&lt;code&gt;border: 1px solid #ededed;&lt;/code&gt;), alternating the background color of the rows between the default background color or plain white with another off-white color (&lt;code&gt;background-color: #fafafa;&lt;/code&gt;) for better readability, and adding some padding to the table header (&lt;code&gt;padding: 15px;&lt;/code&gt;) and table data (&lt;code&gt;padding: 5px 10px;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Not that much styling, but it makes for a polished-enough looking table that goes with the minimalist feel of the rest of the dashboard.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; A lot of this code for the &lt;code&gt;&amp;lt;EventTable&amp;gt;&lt;/code&gt; was inspired by the very good examples in the &lt;strong&gt;&lt;a href=&quot;https://react-table.tanstack.com/docs/examples/pagination&quot;&gt;React Table documentation&lt;/a&gt;&lt;/strong&gt;, and I would strongly encourage you to check it out - it&apos;s very thorough and covers many of the table use cases people have.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Render the table in the app&lt;/h3&gt;
&lt;p&gt;With our table component done, it&apos;s time to add it to the main dashboard component. Import it into the &lt;code&gt;index.tsx&lt;/code&gt; file in your main &lt;code&gt;pages/&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;I&apos;ve condensed down the code in this file for clarity, but for the full code in GitHub, you can click on the file title here.&lt;/p&gt;
&lt;p&gt;The actual data and columns for the table will be handled shortly - this is just to get the &lt;code&gt;&amp;lt;EventTable&amp;gt;&lt;/code&gt; into the dashboard page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import EventTable from &quot;../src/components/EventTable&quot;;
// other imports 

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
// logic to transform data into the columns and data arrays needed to pass to the table

  return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;EventTable columns={columns} data={eventTableData} /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// more code down here: getStaticProps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is one of the easiest parts of this whole tutorial: import the &lt;code&gt;&amp;lt;EventTable&amp;gt;&lt;/code&gt; component at the top of the file, and then pop it into the JSX down below.&lt;/p&gt;
&lt;p&gt;Now on to populating this table with events data.&lt;/p&gt;
&lt;h2&gt;Fetch data for the table&lt;/h2&gt;
&lt;p&gt;In my &lt;strong&gt;&lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;first asset tracking dashboard post&lt;/a&gt;&lt;/strong&gt; I went into great detail about how to create your own asset tracker to generate real data for the app using Blues Wireless hardware and a data fetching function.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to follow along there to build your own tracker and route data to Notehub, please be my guest.&lt;/p&gt;
&lt;p&gt;For this post, I&apos;ll jump ahead to the part where we&apos;re already pulling data into the app via a Next.js &lt;code&gt;getStaticProps&lt;/code&gt; API call. The JSON data from the Notehub cloud looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {
    &quot;uid&quot;: &quot;d7cf7475-45ff-4d8c-b02a-64de9f15f538&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T16:10:52Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T16:11:29Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 3,
      &quot;seconds&quot;: 90,
      &quot;motion&quot;: 76,
      &quot;temperature&quot;: 20.1875,
      &quot;time&quot;: 1636123230,
      &quot;voltage&quot;: 4.2578125
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T16:10:53Z&quot;,
      &quot;name&quot;: &quot;Sandy Springs, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.913747500000014,
      &quot;longitude&quot;: -84.35008984375
    }
  },
  {
    &quot;uid&quot;: &quot;3b1ef772-44da-455a-a846-446a85a70050&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T22:22:18Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T22:23:12Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 2,
      &quot;motion&quot;: 203,
      &quot;seconds&quot;: 174,
      &quot;temperature&quot;: 22,
      &quot;time&quot;: 1636150938,
      &quot;voltage&quot;: 4.2265625
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T22:22:19Z&quot;,
      &quot;name&quot;: &quot;Doraville, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.901052500000006,
      &quot;longitude&quot;: -84.27090234375
    }
  },
  {
    &quot;uid&quot;: &quot;e94b0c68-b1d0-49cb-8361-d622d2d0081e&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T22:40:04Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T22:46:30Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 1,
      &quot;motion&quot;: 50,
      &quot;seconds&quot;: 41,
      &quot;temperature&quot;: 21.875,
      &quot;time&quot;: 1636152004,
      &quot;voltage&quot;: 4.1875
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T22:40:05Z&quot;,
      &quot;name&quot;: &quot;Peachtree Corners, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.9828325,
      &quot;longitude&quot;: -84.21591015624999
    }
  },
  {
    &quot;uid&quot;: &quot;1344517c-adcb-4133-af6a-b1132ffc86ea&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-06T03:04:07Z&quot;,
    &quot;received&quot;: &quot;2021-11-06T03:10:51Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 1,
      &quot;motion&quot;: 126,
      &quot;seconds&quot;: 218,
      &quot;temperature&quot;: 12.5625,
      &quot;time&quot;: 1636167847,
      &quot;voltage&quot;: 4.1875
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-06T03:04:08Z&quot;,
      &quot;name&quot;: &quot;Norcross, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.937182500000006,
      &quot;longitude&quot;: -84.25278515625
    }
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each JSON object in this array is a separate &lt;code&gt;_track.qo&lt;/code&gt; motion event that displays the Notecard&apos;s current location and sensor readings. The part of the object that we care about in this particular post is the &lt;code&gt;gps_location.latitude&lt;/code&gt;, &lt;code&gt;gps_location.longitude&lt;/code&gt;, and &lt;code&gt;body.voltage&lt;/code&gt; values. This is the data our table needs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;d like to save setting up your own asset tracker, you can paste this small set of events into your app&apos;s &lt;code&gt;index.js&lt;/code&gt; file to simulate the data being fetched from Notehub, for testing purposes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Transform the JSON data to fit custom table columns and cells&lt;/h3&gt;
&lt;p&gt;With data coming into our application, we&apos;ll manipulate it and create some new columns to display in the table. And this is where things start to get interesting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customize the cell data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you notice from the shape of the JSON data coming in, the &lt;code&gt;gps_location.latitude&lt;/code&gt; and &lt;code&gt;gps_location.longitude&lt;/code&gt; values are two separate properties in the &lt;code&gt;_track.qo&lt;/code&gt; event, but it makes more sense to display them together in a single data cell as a comma separated list.&lt;/p&gt;
&lt;p&gt;Likewise, the &lt;code&gt;time&lt;/code&gt; is in epoch time - a very machine readable format, that humans have a tough time deciphering. So for my table cells, it&apos;d be nice to format it into a date that makes sense to people.&lt;/p&gt;
&lt;p&gt;Here&apos;s how we&apos;ll do it - as always, the full code is available for you to review in GitHub.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import { useMemo, useEffect, useState } from &quot;react&quot;;
import dayjs from &quot;dayjs&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {

// state variables for the various pieces of data passed to the table
  const [eventTableData, setEventTableData] = useState&amp;lt;dataProps[]&amp;gt;([]);

  useEffect(() =&amp;gt; {
    if (data &amp;amp;&amp;amp; data.length &amp;gt; 0) {
      const eventData = [...data].reverse();
      setEventTableData(eventData);
    }
  }, [data]);

  interface row {
    [row: { string }]: any;
  }

  const columns = useMemo(
    () =&amp;gt; [
      {
        Header: &quot;Latest Events&quot;,
        columns: [
          {
            Header: &quot;Date&quot;,
            accessor: &quot;captured&quot;,
            Cell: (props: { value: string }) =&amp;gt; {
              const tidyDate = dayjs(props.value).format(&quot;MMM D, YY h:mm A&quot;);
              return &amp;lt;span&amp;gt;{tidyDate}&amp;lt;/span&amp;gt;;
            },
          },
          {
            Header: &quot;Voltage&quot;,
            accessor: &quot;body.voltage&quot;,
            Cell: (props: { value: string }) =&amp;gt; {
              const tidyVoltage = Number(props.value).toFixed(2);
              return &amp;lt;span&amp;gt;{tidyVoltage}V&amp;lt;/span&amp;gt;;
            },
          },
          {
            Header: &quot;Heartbeat&quot;,
            accessor: &quot;body.status&quot;,
          },
          {
            Header: &quot;GPS Location&quot;,
            accessor: &quot;gps_location&quot;,
            Cell: (row) =&amp;gt; {
              return (
                &amp;lt;span&amp;gt;
                  {row.row.original.gps_location.latitude.toFixed(6)}
                  &amp;amp;#176;,&amp;amp;nbsp;
                  {row.row.original.gps_location.longitude.toFixed(6)}&amp;amp;#176;
                &amp;lt;/span&amp;gt;
              );
            },
          },
        ],
      },
    ],
    []
  );

  return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;EventTable columns={columns} data={eventTableData} /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// getStaticProps call to Notehub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make this happen, we&apos;ll add in a few React Hooks: &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt; and &lt;code&gt;useMemo&lt;/code&gt;, and to make formatting the &lt;code&gt;time&lt;/code&gt; easier, I added the library &lt;strong&gt;&lt;a href=&quot;https://day.js.org/&quot;&gt;&lt;code&gt;dayjs&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; to my project. Not entirely necessary, but it&apos;s convenient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get the table data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Inside of the component, create a new state variable with the &lt;code&gt;useState&lt;/code&gt; Hook to hold the event data: &lt;code&gt;const [eventTableData, setEventTableData] = useState&amp;lt;dataProps[]&amp;gt;([]);&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, set up a &lt;code&gt;useEffect&lt;/code&gt; function that will run when the JSON data is fetched into the component on page load via the &lt;code&gt;getStaticProps&lt;/code&gt; call. When the &lt;code&gt;data&lt;/code&gt; is present, we take the data, reverse the order so the most recent events are first instead of last - I think that makes more sense when seeing a list of events here: most recent first - and set those events in the component&apos;s state via &lt;code&gt;setEventTableData&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configure the columns&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The final step is defining the columns for the table.&lt;/p&gt;
&lt;p&gt;The first thing we must do is wrap the newly defined &lt;code&gt;columns&lt;/code&gt; variable in a &lt;code&gt;useMemo&lt;/code&gt; function (as defined by the React Table documentation), and I&apos;ll also give the whole table a header named &lt;code&gt;Latest Events&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then we can set up the &lt;code&gt;columns&lt;/code&gt; array: I want one for the &lt;code&gt;Date&lt;/code&gt; stamp, one to display the device&apos;s &lt;code&gt;Voltage&lt;/code&gt;, one for the device&apos;s &lt;code&gt;Status&lt;/code&gt; (i.e. whether the event is a motion event caused by actual motion or it&apos;s a &quot;heartbeat&quot; event - an event just to let you know the device is still alive), and one for the &lt;code&gt;GPS Location&lt;/code&gt;, which as I said before I want to be a combination of latitude and longitude.&lt;/p&gt;
&lt;p&gt;Each of these titles will become a &lt;code&gt;Header&lt;/code&gt; property in each of these objects, and they will be followed by an &lt;code&gt;accessor&lt;/code&gt; property. Typically, the &lt;code&gt;accessor&lt;/code&gt; value will be something simple like &lt;code&gt;body.status&lt;/code&gt;, which is the way to get the actual value out of the object. If the &lt;code&gt;accessor&lt;/code&gt;, however, needs to be transformed before being set, this is where the &lt;code&gt;Cell&lt;/code&gt; function comes into play.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://react-table.tanstack.com/docs/api/useTable#cell-properties&quot;&gt;Cell&lt;/a&gt;&lt;/strong&gt; is a method that can be be used to transform the props in that cell and completely customize the return value, right down to the JSX.&lt;/p&gt;
&lt;p&gt;So for example, to modify the timestamp date into a nicely formatted string, we grab the &lt;code&gt;captured&lt;/code&gt; value out of the event, and then use &lt;code&gt;Cell&lt;/code&gt; to run a &lt;code&gt;dayjs&lt;/code&gt; function and format the date into a new variable named &lt;code&gt;tidyDate&lt;/code&gt;. And then we return &lt;code&gt;tidyDate&lt;/code&gt; as a bit of JSX wrapped in a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;p&gt;Similarly, to concatenate the latitude and longitude values together into one cell, we have to go even deeper into the props being passed to &lt;code&gt;Cell&lt;/code&gt;, and pull out two of the properties nested inside of the &lt;code&gt;gps_location&lt;/code&gt; object to return in the cell.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Console.log()&lt;/code&gt; is your friend here.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Don&apos;t be afraid to reach for &lt;code&gt;console.log()&lt;/code&gt; when putting together these complex data cells. Only by using it to see the shape of the data and each row in the table was I able to figure out how to extract the values I needed for the &lt;code&gt;GPS Location&lt;/code&gt; column.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And there you have it: our &lt;code&gt;columns&lt;/code&gt; are defined and our &lt;code&gt;data&lt;/code&gt; is too, pass both to the &lt;code&gt;&amp;lt;EventTable&amp;gt;&lt;/code&gt; component, and we should be good to go.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;About 9 months ago, I began working for an IoT startup, and learning how to manage and display readings in dashboards from devices &quot;on the edge&quot;. So one of the first projects I built to this end was a dashboard including data charts, a map showing device location, and a table listing all the events being displayed here.&lt;/p&gt;
&lt;p&gt;To render a table with all the flexibility and none of the cruft, I turned to the React Table library, a headless and highly extensible set of hooks that simplifies building complex tables, handling things like pagination, page size, and so much more, with very little effort on our part. Even modifying the display of table cell data in a row, is relatively straightforward. It&apos;s a great library.&lt;/p&gt;
&lt;p&gt;This dashboard actually came in handy when my parents&apos; car was stolen from their driveway the night after Thanksgiving. If you want to hear the whole story and build your own tracker, check out this &lt;strong&gt;&lt;a href=&quot;https://blues.io/blog/gps-asset-tracker-with-blues-wireless-and-react/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;blog post and video&lt;/a&gt;&lt;/strong&gt; I made for Blues Wireless - it details the whole process from hardware to software to deploying to Netlify.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you enjoyed learning how to leverage the React Table library to make a data table to display event data from an IoT asset tracker. Tables can be tricky to get right, but they&apos;re such a nice, straightforward way to display all sorts of data to users.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hackster.io/paige-niedringhaus/low-code-gps-asset-tracker-and-map-display-b10419&quot;&gt;Hackster.io original asset tracker project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard&quot;&gt;Asset tracker GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-table.tanstack.com/&quot;&gt;React Table&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://dev.blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;developer experience site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Original article about &lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;rendering maps in a Next.js application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow up article about &lt;a href=&quot;./build-and-custom-style-recharts-data-charts&quot;&gt;custom styling charts and tooltips with React Recharts library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>react</category><category>javascript</category><category>typescript</category><category>nextjs</category></item><item><title>Build and Custom Style Recharts Data Charts</title><link>https://www.paigeniedringhaus.com/blog/build-and-custom-style-recharts-data-charts/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/build-and-custom-style-recharts-data-charts/</guid><description>Recharts has standard charts and tooltips, but customizing them takes extra effort.</description><pubDate>Thu, 10 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/build-and-custom-style-recharts/charts.png&quot; alt=&quot;Temperature and voltage charts with styled tooltips&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Over the summer of 2021 I started working for an Internet of Things (IoT) startup, &lt;strong&gt;&lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Blues Wireless&lt;/a&gt;&lt;/strong&gt; that aims to make IoT development easy - even when reliable Internet connections are not available. Blues does this via &lt;strong&gt;&lt;a href=&quot;https://blues.io/products/notecard/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecards&lt;/a&gt;&lt;/strong&gt; - prepaid cellular devices that can be embedded into any IoT device &quot;on the edge&quot; to transmit sensor data as JSON to a secure cloud: &lt;strong&gt;&lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notehub&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I am not a hardware or firmware engineer however, web development is my area of expertise (frontend in particular), so to dip my toes into IoT development, I started off building a simpler project: an &lt;strong&gt;&lt;a href=&quot;https://www.hackster.io/paige-niedringhaus/low-code-gps-asset-tracker-and-map-display-b10419&quot;&gt;asset tracker&lt;/a&gt;&lt;/strong&gt; using only a Blues &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/note-nbgl-500/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecard&lt;/a&gt;&lt;/strong&gt;, Blues &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/carr-al/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecarrier AL&lt;/a&gt;&lt;/strong&gt; with a built-in GPS antenna, and a small &lt;strong&gt;&lt;a href=&quot;https://www.adafruit.com/product/328&quot;&gt;lithium-ion polymer (LiPo) battery&lt;/a&gt;&lt;/strong&gt; to power it all.&lt;/p&gt;
&lt;p&gt;With the help of the Blues &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/guides-and-tutorials/notecard-guides/asset-tracking/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;developer experience docs&lt;/a&gt;&lt;/strong&gt;, I had temperature, voltage, and GPS location data being delivered to the Notehub cloud from my tracker in under 30 minutes. That&apos;s cool and all, but the way that data from sensors in the world really becomes useful is when it&apos;s displayed to users in some sort of UI, right? It could be maps, tables, or in my case, charts.&lt;/p&gt;
&lt;p&gt;So I wanted to take my data from the Notehub cloud and pump it into a custom-made dashboard to track and display the Notecard&apos;s location, voltage, and sensor readings in the real world. React is my current JavaScript framework of choice, and I decided to build a Next.js TypeScript-powered dashboard, and I learned a ton of interesting things in the process, which I intend to share with you over a series of blog posts in the next few months.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you missed my first blog post installment all about building an asset tracking map in Next.js using React Leaflet, you can read it &lt;strong&gt;&lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Today, I plan to show you how to build charts and a custom styled tooltip in a Next.js application with the Recharts Library, using real-world data from a third-party API source.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s what the final dashboard looks like - the temperature and voltage charts are the focus for this particular post.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=uUJiX9q8x9M&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Create chart components in the Next.js app&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; This article will not go through the initial setup of a brand new Next.js app - that&apos;s outside the scope of this blog. If you&apos;re starting from scratch, I would recommend following the &lt;a href=&quot;https://nextjs.org/docs/basic-features/typescript&quot;&gt;Next.js starter app with TypeScript documentation&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;d prefer, you can also fork and download my whole, working code base from the GitHub repo &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Install chart dependencies&lt;/h3&gt;
&lt;p&gt;To get started adding charts to our Next.js application, we have to install the &lt;strong&gt;&lt;a href=&quot;https://recharts.org/en-US/&quot;&gt;Recharts library&lt;/a&gt;&lt;/strong&gt;. Recharts is a chart library built with React and the popular data visualization library D3, and it makes it easy to use React-based chart components that feel familiar to make all sorts of different types of charts, while still allowing a high degree of flexibility for customization, as needed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href=&quot;https://recharts.org/en-US/api&quot;&gt;API&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://recharts.org/en-US/examples&quot;&gt;examples&lt;/a&gt;&lt;/strong&gt; documentation for Recharts are thorough, and I&apos;d highly encourage you to read them to get a feel for the variety of charts available and how to work with them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Install the Recharts library in the Next.js app with the following commands in a terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install recharts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the only new library needed to get Recharts up and running, even when using TypeScript, so it&apos;s time to move on and make some various chart components.&lt;/p&gt;
&lt;h3&gt;Set up a &lt;code&gt;&amp;lt;TempChart &amp;gt;&lt;/code&gt; component&lt;/h3&gt;
&lt;p&gt;The first type of chart component we&apos;ll create for the dashboard will be used to display the temperature data supplied by the Notecard. This will be an area chart that looks like the image here.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/build-and-custom-style-recharts/temp-chart.png&quot; alt=&quot;Temperature area chart image and tooltip.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is a Recharts area chart displaying temperature data over time, including a tooltip.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Since this component will have the sole goal of displaying temperature data, create a new file in the repo named &lt;code&gt;TempChart.tsx&lt;/code&gt;, and paste the following code into it. The actual code in GitHub is available by clicking the file title below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/src/components/TempChart.tsx&quot;&gt;&lt;code&gt;TempChart.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {
  AreaChart,
  Area,
  XAxis,
  YAxis,
  Label,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
} from &quot;recharts&quot;;
import CustomTooltip from &quot;./CustomTooltip&quot;;

type tempDataProps = {
  shortenedDate: string;
  date: string;
  temp: number;
}[];

const TempChart = ({ tempData }: { tempData: tempDataProps }) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;h2&amp;gt;Temperature Chart&amp;lt;/h2&amp;gt;
      &amp;lt;ResponsiveContainer width={&quot;100%&quot;} height={300} min-width={300}&amp;gt;
        &amp;lt;AreaChart
          data={tempData}
          margin={{
            top: 10,
            right: 30,
            left: 20,
            bottom: 30,
          }}
        &amp;gt;
          &amp;lt;CartesianGrid strokeDasharray=&quot;3 3&quot; /&amp;gt;
          &amp;lt;XAxis dataKey=&quot;shortenedDate&quot;&amp;gt;
            &amp;lt;Label value=&quot;Date&quot; position=&quot;bottom&quot; /&amp;gt;
          &amp;lt;/XAxis&amp;gt;
          &amp;lt;YAxis dataKey=&quot;temp&quot;&amp;gt;
            &amp;lt;Label
              value=&quot;Temperature &amp;amp;#8457;&quot;
              angle={-90}
              position=&quot;left&quot;
              dy=&quot;-10&quot;
            /&amp;gt;
          &amp;lt;/YAxis&amp;gt;
          &amp;lt;Tooltip content={&amp;lt;CustomTooltip payload={tempData} /&amp;gt;} /&amp;gt;
          &amp;lt;Area
            type=&quot;monotone&quot;
            dataKey=&quot;temp&quot;
            stroke=&quot;#8884d8&quot;
            fill=&quot;#8884d8&quot;
          /&amp;gt;
        &amp;lt;/AreaChart&amp;gt;
      &amp;lt;/ResponsiveContainer&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default TempChart;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&apos;s a lot of imports from Recharts happening in this component, so let&apos;s go through them one by one to understand what their purposes are.&lt;/p&gt;
&lt;p&gt;Each of the imports from the &lt;code&gt;recharts&lt;/code&gt; library at the very top of the file represent a different component used to make this chart display correctly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AreaChart&lt;/code&gt;&lt;/strong&gt; is the container for all the chart data and is how Recharts knows what type of chart it&apos;s rendering.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Area&lt;/code&gt;&lt;/strong&gt; is where the array of data to be displayed by the chart is passed. The &lt;code&gt;stroke&lt;/code&gt; and &lt;code&gt;fill&lt;/code&gt; properties in the &lt;code&gt;&amp;lt;Area&amp;gt;&lt;/code&gt; component allow us to define the chart&apos;s line color and fill color as hex codes.
&lt;ul&gt;
&lt;li&gt;(Note: if there was more than one array of temperature data this chart needed to display - say, for multiple Notecards reporting data, a second &lt;code&gt;&amp;lt;Area&amp;gt;&lt;/code&gt; component would be included in the JSX underneath the first instance)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XAxis and YAxis&lt;/strong&gt; are how the chart knows what the X and Y axes of the chart should use as their data displays.
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;dataKey&lt;/code&gt; property inside of the axis component is the property name of the array data being passed to the chart. For example, each item in the array of data being passed to the temperature chart&apos;s &lt;code&gt;&amp;lt;YAxis&amp;gt;&lt;/code&gt; has a property of &lt;code&gt;&quot;temp&quot;&lt;/code&gt;, so that is the &lt;code&gt;dataKey&lt;/code&gt; for the &lt;code&gt;&amp;lt;YAxis&amp;gt;&lt;/code&gt; component.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Label&lt;/code&gt;&lt;/strong&gt; must always be a child component of the &lt;code&gt;XAxis&lt;/code&gt; or &lt;code&gt;YAxis&lt;/code&gt; component and it displays a custom axis label.
&lt;ul&gt;
&lt;li&gt;I like it because the chart label, label angle, value, positioning, and more can be changed very easily here.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;CartesianGrid&lt;/code&gt;&lt;/strong&gt; draws the nice squares which align with the cartesian coordinate axes.
&lt;ul&gt;
&lt;li&gt;This is not a required component, but I think it improves chart readability. The &lt;code&gt;strokeDasharray&lt;/code&gt; property is customizable, so feel free to play with the numbers to find a square pattern that suits you.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Tooltip&lt;/code&gt;&lt;/strong&gt; although our tooltip will end up being a custom component, in order to display it the custom one, we must pass it into the generic &lt;code&gt;&amp;lt;Tooltip&amp;gt;&lt;/code&gt; component as the property &lt;code&gt;content&lt;/code&gt;. We&apos;ll get into this more when we create the tooltip component, so put a pin in this for now.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ResponsiveContainer&lt;/code&gt;&lt;/strong&gt; wraps the whole chart component and makes it responsive to the size of the parent container. Although the chart component itself can be given a &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt;, they&apos;re static. When passing the &lt;code&gt;&amp;lt;ResponsiveContainer&amp;gt;&lt;/code&gt; component width and height props, one should be a percentage string.
&lt;ul&gt;
&lt;li&gt;For my component, the &lt;code&gt;width&lt;/code&gt; is &lt;code&gt;width={100%}&lt;/code&gt;, for this reason.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only other import to this file is the &lt;code&gt;&amp;lt;CustomTooltip&amp;gt;&lt;/code&gt; component and we&apos;ll get to this component in depth soon.&lt;/p&gt;
&lt;p&gt;After all the imports, the &lt;code&gt;tempDataProps&lt;/code&gt; are defined for the TypeScript array of data being passed to this chart. The &lt;code&gt;props&lt;/code&gt; are pretty simple: each object in the array will contain:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;shortenedDate&lt;/code&gt; (this is a simplified date format of MM/DD/YYYY) to display in the &lt;code&gt;&amp;lt;XAxis&amp;gt;&lt;/code&gt; component,&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;date&lt;/code&gt; - the longer form date of MMM D, YYYY h:mm A to display in the tooltip,&lt;/li&gt;
&lt;li&gt;And a &lt;code&gt;temp&lt;/code&gt; - the actual temperature.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, all of these chart components are composed in the JSX to make a responsive area chart with dates on the X axis, temperature on the Y axis, a lavender stroke and fill color, and a custom tooltip.&lt;/p&gt;
&lt;h3&gt;Build a &lt;code&gt;&amp;lt;VoltageChart&amp;gt;&lt;/code&gt; component&lt;/h3&gt;
&lt;p&gt;The second chart component we&apos;re going to build is for the Notecard&apos;s voltage levels over time. The Notecard is designed to be ultra low power so even small batteries can power it for long stretches of time (multiple years, even), but it&apos;s still good to keep an eye on the voltage so if it does start to drop, the LiPo battery can be recharged or swapped out.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/build-and-custom-style-recharts/voltage-chart.png&quot; alt=&quot;Voltage line chart and tooltip.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is a Recharts line chart displaying voltage data over time, including a tooltip.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This component will be a standard line chart instead of an area chart, so create a new component file named &lt;code&gt;VoltageChart.tsx&lt;/code&gt; in your project.&lt;/p&gt;
&lt;p&gt;A lot of the code for the &lt;code&gt;&amp;lt;VoltageChart&amp;gt;&lt;/code&gt; component should feel familiar when you read over it - it&apos;s quite similar to the &lt;code&gt;&amp;lt;TempChart&amp;gt;&lt;/code&gt; component&apos;s code. As before, you can click the file title to go the GitHub code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Yes, this chart code isn&apos;t the DRYest (don&apos;t repeat yourself).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If this was a larger project with more charts, I would work to make some more generic, &quot;base chart&quot; components to be more flexible for various purposes, but since it&apos;s a relatively small app with just a two charts, I kept it simpler.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/src/components/VoltageChart.tsx&quot;&gt;&lt;code&gt;VoltageChart.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {
  LineChart,
  Line,
  XAxis,
  YAxis,
  Label,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
} from &quot;recharts&quot;;
import CustomTooltip from &quot;./CustomTooltip&quot;;

type voltageDataChart = {
  shortenedDate: string;
  date: string;
  voltage: number;
}[];

const VoltageChart = ({ voltageData }: { voltageData: voltageDataChart }) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;h2&amp;gt;Voltage Chart&amp;lt;/h2&amp;gt;
      &amp;lt;ResponsiveContainer width={&quot;100%&quot;} height={300} min-width={300}&amp;gt;
        &amp;lt;LineChart
          data={voltageData}
          margin={{
            top: 10,
            right: 30,
            left: 20,
            bottom: 30,
          }}
        &amp;gt;
          &amp;lt;CartesianGrid strokeDasharray=&quot;3 3&quot; /&amp;gt;
          &amp;lt;XAxis dataKey=&quot;shortenedDate&quot;&amp;gt;
            &amp;lt;Label value=&quot;Date&quot; position=&quot;bottom&quot; /&amp;gt;
          &amp;lt;/XAxis&amp;gt;
          &amp;lt;YAxis dataKey=&quot;voltage&quot; type=&quot;number&quot; domain={[3.3, 5.6]}&amp;gt;
            &amp;lt;Label value=&quot;Voltage V&quot; angle={-90} position=&quot;left&quot; dy=&quot;-10&quot; /&amp;gt;
          &amp;lt;/YAxis&amp;gt;
          &amp;lt;Tooltip content={&amp;lt;CustomTooltip payload={voltageData} /&amp;gt;} /&amp;gt;
          &amp;lt;Line type=&quot;monotone&quot; dataKey=&quot;voltage&quot; stroke=&quot;#82ca9d&quot; /&amp;gt;
        &amp;lt;/LineChart&amp;gt;
      &amp;lt;/ResponsiveContainer&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default VoltageChart;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As with the &lt;code&gt;&amp;lt;TempChart&amp;gt;&lt;/code&gt;, the &lt;code&gt;&amp;lt;VoltageChart&amp;gt;&lt;/code&gt; imports all the same Recharts components except it uses &lt;strong&gt;&lt;code&gt;LineChart&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;Line&lt;/code&gt;&lt;/strong&gt; to indicate that this chart will be displayed as a line chart instead of an area chart and tell the &lt;code&gt;&amp;lt;Line&amp;gt;&lt;/code&gt; component the &lt;code&gt;type&lt;/code&gt; will be an unbroken &lt;code&gt;monotone&lt;/code&gt; type with a soft green &lt;code&gt;stroke&lt;/code&gt; color.&lt;/p&gt;
&lt;p&gt;Beyond these key differences everything else is much the same: same &lt;code&gt;&amp;lt;ResponsiveContainer&amp;gt;&lt;/code&gt; chart wrapper, similarly shaped &lt;code&gt;voltageData&lt;/code&gt; array (the &lt;code&gt;temp&lt;/code&gt; property on each object is replaced by &lt;code&gt;voltage&lt;/code&gt; here), same X and Y axis data (although this Y axis has a &lt;code&gt;domain&lt;/code&gt; property that sets the upper and lower bounds of the chart), and even the same &lt;code&gt;&amp;lt;CustomTooltip&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;So now that we&apos;ve defined our charts, it&apos;s time to dive into that &lt;code&gt;&amp;lt;CustomTooltip&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;h3&gt;Make a &lt;code&gt;&amp;lt;CustomTooltip&amp;gt;&lt;/code&gt; component and style it&lt;/h3&gt;
&lt;p&gt;This is where things stopped being so straightforward. If we examine the Recharts &lt;strong&gt;&lt;a href=&quot;https://recharts.org/en-US/api/Tooltip#content&quot;&gt;tooltip API documentation&lt;/a&gt;&lt;/strong&gt; closely, you&apos;ll see mention of the method &lt;code&gt;content&lt;/code&gt; as a way to render a custom tooltip, lucky for us, this method links to &lt;strong&gt;&lt;a href=&quot;https://recharts.org/en-US/examples/CustomContentOfTooltip&quot;&gt;example code&lt;/a&gt;&lt;/strong&gt; so we can see what props a custom tooltip component can take, including CSS styling.&lt;/p&gt;
&lt;p&gt;Here is what our custom tooltip is going to end up looking like.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/build-and-custom-style-recharts/tooltip.png&quot; alt=&quot;Custom Recharts tooltip.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A custom-styled tooltip in Recharts.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In the app, make a new component file named &lt;code&gt;CustomTooltip.tsx&lt;/code&gt;, and go ahead and make a new style file named &lt;code&gt;CustomTooltip.modules.scss&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;m using Sass in my Next project in addition to the built-in &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/built-in-css-support#adding-component-level-css&quot;&gt;CSS module styling&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There&apos;s very little Sass nesting going on in this particular SCSS file so I think it will be easy enough to follow, but if you&apos;d like to set up Sass in your own Next project, you can follow Next&apos;s directions &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/built-in-css-support#sass-support&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/src/components/CustomTooltip.tsx&quot;&gt;&lt;code&gt;CustomTooltip.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import styles from &quot;../../styles/CustomTooltip.module.scss&quot;;

const CustomTooltip = ({ active, payload }: any) =&amp;gt; {
  if (active &amp;amp;&amp;amp; payload &amp;amp;&amp;amp; payload.length) {
    return (
      &amp;lt;div className={styles.customTooltip}&amp;gt;
        &amp;lt;div className={styles.tooltipDetails}&amp;gt;
          &amp;lt;p className={styles.label}&amp;gt;Date: {payload[0].payload.date}&amp;lt;/p&amp;gt;
          {payload[0].payload.temp ? (
            &amp;lt;p&amp;gt;Temp {payload[0].payload.temp}&amp;amp;#8457;&amp;lt;/p&amp;gt;
          ) : (
            &amp;lt;p&amp;gt;Voltage {payload[0].payload.voltage}V&amp;lt;/p&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }

  return null;
};

export default CustomTooltip;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;CustomTooltip&lt;/code&gt; component here takes in two props:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;active&lt;/code&gt;&lt;/strong&gt; - a boolean denoting if a tooltip should be displayed (this happens when a user mouses over the chart on desktop or clicks on a particular point on mobile),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;payload&lt;/code&gt;&lt;/strong&gt; - the data the tooltip will be displaying from the chart. For us, we want the chart&apos;s temp (or voltage) and the more specific &lt;code&gt;date&lt;/code&gt; timestamp in our tooltip.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The custom tooltip&apos;s JSX checks if &lt;code&gt;active&lt;/code&gt; is true for a particular data point and if the &lt;code&gt;payload&lt;/code&gt; exists as a single object in the array. If both conditions are met, the tooltip displays the longer format date and either the temperature or voltage depending on which chart the tooltip&apos;s being invoked with.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Once again, for a larger project the display would need to be redesigned to be more flexible to whatever data props were being passed in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Our data&apos;s being displayed in the tooltip, now to give it a little styling to look decent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/styles/CustomTooltip.module.scss&quot;&gt;&lt;code&gt;CustomTooltip.scss&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.customTooltip {
  background: white;
  color: #333;
  box-shadow: 0 3px 14px rgb(0 0 0 / 40%);
  padding: 1px;
  text-align: left;
  border-radius: 12px;

  .tooltipDetails {
    margin: 13px 19px;
  }

  .label {
    font-weight: 600;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;customTooltip&lt;/code&gt; class wraps all the tooltip data, giving it a white background, black text with a little padding, a slight box shadow, and some nicely rounded corners. Nested inside of this class are &lt;code&gt;tooltipDetails&lt;/code&gt; which defines some margins around the text, and &lt;code&gt;label&lt;/code&gt;, which gives extra emphasis to the font.&lt;/p&gt;
&lt;p&gt;Then import the SCSS file into the &lt;code&gt;CustomTooltip&lt;/code&gt; component file, define the module&apos;s name as &lt;code&gt;styles&lt;/code&gt; and plug in the corresponding CSS in the correct components in the JSX. Now when this component is imported into the two chart components, it should look good and display the more specific tooltip data we want.&lt;/p&gt;
&lt;p&gt;With that done, we&apos;re ready to start using these components in the dashboard page.&lt;/p&gt;
&lt;h3&gt;Render the charts in the application&lt;/h3&gt;
&lt;p&gt;Ok, so in the main file where all our dashboard components are imported, let&apos;s add our charts and prepare to pass data to them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import TempChart from &quot;../src/components/TempChart&quot;;
import VoltageChart from &quot;../src/components/VoltageChart&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
// logic to transform data into the arrays needed to pass to the charts

return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;TempChart tempData={tempData} /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;VoltageChart voltageData={voltageData} /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// more code down here: getStaticProps that fetches the data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&apos;s not much to these imports, they&apos;re standard default imports to get these components into the file. After the two chart components are imported, they&apos;re rendered inside of the JSX down at the bottom of the file. The &lt;code&gt;getStaticProps&lt;/code&gt; function at the bottom of the file that I&apos;ve written a comment for is where the Notehub data gets pulled into the app, and the comment right under our &lt;code&gt;export default function&lt;/code&gt; line is where we&apos;ll transform that raw data into the &lt;code&gt;tempData&lt;/code&gt; and &lt;code&gt;voltageData&lt;/code&gt; arrays that our charts need.&lt;/p&gt;
&lt;p&gt;Let&apos;s get to it.&lt;/p&gt;
&lt;h2&gt;Pull in data for the charts&lt;/h2&gt;
&lt;p&gt;In my &lt;strong&gt;&lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;previous asset tracking dashboard article&lt;/a&gt;&lt;/strong&gt; I went into great detail about how to create your own asset tracker to generate real data for the app using Blues Wireless hardware and a data fetching function.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to follow along there to build your own tracker and route data to Notehub, please be my guest.&lt;/p&gt;
&lt;p&gt;For this post, I&apos;ll jump ahead to the part where we&apos;re already pulling data into the app via a Next.js &lt;code&gt;getStaticProps&lt;/code&gt; API call. The JSON data from the Notehub cloud looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {
    &quot;uid&quot;: &quot;d7cf7475-45ff-4d8c-b02a-64de9f15f538&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T16:10:52Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T16:11:29Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 3,
      &quot;seconds&quot;: 90,
      &quot;motion&quot;: 76,
      &quot;temperature&quot;: 20.1875,
      &quot;time&quot;: 1636123230,
      &quot;voltage&quot;: 4.2578125
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T16:10:53Z&quot;,
      &quot;name&quot;: &quot;Sandy Springs, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.913747500000014,
      &quot;longitude&quot;: -84.35008984375
    }
  },
  {
    &quot;uid&quot;: &quot;3b1ef772-44da-455a-a846-446a85a70050&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T22:22:18Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T22:23:12Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 2,
      &quot;motion&quot;: 203,
      &quot;seconds&quot;: 174,
      &quot;temperature&quot;: 22,
      &quot;time&quot;: 1636150938,
      &quot;voltage&quot;: 4.2265625
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T22:22:19Z&quot;,
      &quot;name&quot;: &quot;Doraville, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.901052500000006,
      &quot;longitude&quot;: -84.27090234375
    }
  },
  {
    &quot;uid&quot;: &quot;e94b0c68-b1d0-49cb-8361-d622d2d0081e&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-05T22:40:04Z&quot;,
    &quot;received&quot;: &quot;2021-11-05T22:46:30Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 1,
      &quot;motion&quot;: 50,
      &quot;seconds&quot;: 41,
      &quot;temperature&quot;: 21.875,
      &quot;time&quot;: 1636152004,
      &quot;voltage&quot;: 4.1875
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-05T22:40:05Z&quot;,
      &quot;name&quot;: &quot;Peachtree Corners, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.9828325,
      &quot;longitude&quot;: -84.21591015624999
    }
  },
  {
    &quot;uid&quot;: &quot;1344517c-adcb-4133-af6a-b1132ffc86ea&quot;,
    &quot;device_uid&quot;: &quot;dev:864475ABCDEF&quot;,
    &quot;file&quot;: &quot;_track.qo&quot;,
    &quot;captured&quot;: &quot;2021-11-06T03:04:07Z&quot;,
    &quot;received&quot;: &quot;2021-11-06T03:10:51Z&quot;,
    &quot;body&quot;: {
      &quot;hdop&quot;: 1,
      &quot;motion&quot;: 126,
      &quot;seconds&quot;: 218,
      &quot;temperature&quot;: 12.5625,
      &quot;time&quot;: 1636167847,
      &quot;voltage&quot;: 4.1875
    },
    &quot;gps_location&quot;: {
      &quot;when&quot;: &quot;2021-11-06T03:04:08Z&quot;,
      &quot;name&quot;: &quot;Norcross, GA&quot;,
      &quot;country&quot;: &quot;US&quot;,
      &quot;timezone&quot;: &quot;America/New_York&quot;,
      &quot;latitude&quot;: 33.937182500000006,
      &quot;longitude&quot;: -84.25278515625
    }
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each JSON object in this array is a separate &lt;code&gt;_track.qo&lt;/code&gt; motion event that displays the Notecard&apos;s current location and sensor readings. The part of the object that we care about in this particular post is the &lt;code&gt;body.temperature&lt;/code&gt; and &lt;code&gt;body.voltage&lt;/code&gt; values. This is the data our charts need.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;d like to save setting up your own asset tracker, you can paste this small set of events into your app&apos;s &lt;code&gt;index.js&lt;/code&gt; file to simulate the data being fetched from Notehub, for testing purposes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Take that data and reshape it to work with our chart and tooltip components&lt;/h3&gt;
&lt;p&gt;With the correct shape of our data being fed into our app (either via &lt;code&gt;getStaticProps&lt;/code&gt; and Notehub) or the JSON test data I shared above, it&apos;s time to reshape this data.&lt;/p&gt;
&lt;p&gt;I&apos;ve condensed down the logic to make this file easier to read, but you can see the full file on GitHub.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import { useState } from &quot;react&quot;;
import dayjs from &quot;dayjs&quot;;
import { convertCelsiusToFahrenheit } from &quot;../src/util/helpers&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {

// state variables for the various pieces of data passed to the charts
  const [tempData, setTempData] = useState&amp;lt;
    { date: string; shortenedDate: string; temp: number }[]
  &amp;gt;([]);

  const [voltageData, setVoltageData] = useState&amp;lt;
    { date: string; shortenedDate: string; voltage: number }[]
  &amp;gt;([]);

  // logic to transform data into the items needed to pass to the charts
  useEffect(() =&amp;gt; {
    const temperatureDataArray: {
        date: string;
        shortenedDate: string;
        temp: number;
        }[] = [];
    const voltageDataArray: {
        date: string;
        shortenedDate: string;
        voltage: number;
        }[] = [];
   
    if (data &amp;amp;&amp;amp; data.length &amp;gt; 0) {
      data
        .sort((a, b) =&amp;gt; {
          return Number(a.captured) - Number(b.captured);
        })
        .map((event) =&amp;gt; {
          const temperatureObj = {
            date: dayjs(event.captured).format(&quot;MMM D, YYYY h:mm A&quot;),
            shortenedDate: dayjs(event.captured).format(&quot;MM/DD/YYYY&quot;),
            temp: Number(convertCelsiusToFahrenheit(event.body.temperature)),
          };
          temperatureDataArray.push(temperatureObj);
          const voltageObj = {
            date: dayjs(event.captured).format(&quot;MMM D, YYYY h:mm A&quot;),
            shortenedDate: dayjs(event.captured).format(&quot;MM/DD/YYYY&quot;),
            voltage: Number(event.body.voltage.toFixed(2)),
          };
          voltageDataArray.push(voltageObj);
        });
    }
    setTempData(temperatureDataArray);
    setVoltageData(voltageDataArray);
  }, [data]);

return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;TempChart tempData={tempData} /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;VoltageChart voltageData={voltageData} /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// getStaticProps call to Notehub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&apos;s what&apos;s happening in this file, we declare two new React state variables: &lt;code&gt;tempData&lt;/code&gt; and &lt;code&gt;voltageData&lt;/code&gt; - these arrays are what get passed to the chart components. Each of these variables is an object with three properties: &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;shortenedDate&lt;/code&gt;, and either &lt;code&gt;temp&lt;/code&gt; or &lt;code&gt;voltage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, inside of a &lt;code&gt;useEffect&lt;/code&gt; function that runs as soon as the &lt;code&gt;data&lt;/code&gt; variable is available via the &lt;code&gt;getStaticProps&lt;/code&gt; call, we sort the data, and then iterate over each object in the original &lt;code&gt;data&lt;/code&gt; array and create a new &lt;code&gt;temperatureObj&lt;/code&gt; and &lt;code&gt;voltageObj&lt;/code&gt; from the data that gets pushed into the &lt;code&gt;temperatureDataArray&lt;/code&gt; and &lt;code&gt;voltageDataArray&lt;/code&gt; variables declared at the very top of the &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, those arrays are set into the component&apos;s state with our &lt;code&gt;useState&lt;/code&gt; variables. At this point, you should have a couple of nice looking charts displaying a few points of data about your Notecard&apos;s voltage and temperature.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you look closely, you can see a couple of extra imports at the top of this code example for the &lt;code&gt;dayjs&lt;/code&gt; library and a helper function I named &lt;code&gt;convertCelsiusToFahrenheit&lt;/code&gt;. The &lt;code&gt;dayjs&lt;/code&gt; library helps make date time formatting significantly easier for our &lt;code&gt;date&lt;/code&gt; and &lt;code&gt;shortenedDate&lt;/code&gt; properties for our new data arrays and &lt;code&gt;convertCelsiusToFahrenheit&lt;/code&gt; takes the Notecard&apos;s temp (reported in Celsius) and makes it Fahrenheit. Neither of these things is complicated, but I wanted to point them out for the very observant among you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Once I started working for an IoT startup, getting more familiar with the possibilities of what sensors could report from the real world became more of a focus for me - but still from a web development perspective. To that end, I built a web dashboard pulling data from our hardware devices out in the field: location, temperature, battery voltage, etc.&lt;/p&gt;
&lt;p&gt;For the data like temperature and voltage, charts seemed most appropriate to display the changing values over time, and so I chose the Recharts library to help with these data visualizations. The library&apos;s easy to work with and produces some nifty looking charts without too much effort on my part, and when I wanted to style my own tooltip and display some custom data, that was straightforward too.&lt;/p&gt;
&lt;p&gt;This dashboard actually came in handy when my parents&apos; car was stolen from their driveway the night after Thanksgiving. If you want to hear the whole story and build your own tracker, check out this &lt;strong&gt;&lt;a href=&quot;https://blues.io/blog/gps-asset-tracker-with-blues-wireless-and-react/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;blog post and video&lt;/a&gt;&lt;/strong&gt; I made for Blues Wireless - it details the whole process from hardware to software to deploying to Netlify.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you enjoyed learning how to create a couple of charts and custom tooltips using the Recharts library - slick data visualizations have so many potential applications for transforming lots of data points into meaningful data people can draw conclusions from.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hackster.io/paige-niedringhaus/low-code-gps-asset-tracker-and-map-display-b10419&quot;&gt;Hackster.io original asset tracker project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard&quot;&gt;Asset tracker GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://recharts.org/en-US/&quot;&gt;Recharts&lt;/a&gt; chart library&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://dev.blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;developer experience site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Previous article about &lt;a href=&quot;./create-an-asset-tracker-with-next-js-and-react-leaflet&quot;&gt;rendering maps in a Next.js application&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>nextjs</category><category>react</category><category>javascript</category><category>typescript</category><category>data visualization</category></item><item><title>How to Unit Test Next.js API Routes with TypeScript</title><link>https://www.paigeniedringhaus.com/blog/how-to-unit-test-next-js-api-routes-with-typescript/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/how-to-unit-test-next-js-api-routes-with-typescript/</guid><description>If you need env vars, mocked data, and TypeScript types, this one&apos;s for you.</description><pubDate>Wed, 16 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/how-to-unit-test-nextjs-api-routes/woman-coding.jpg&quot; alt=&quot;Woman coding&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://nextjs.org/&quot;&gt;Next.js&lt;/a&gt;&lt;/strong&gt; is an awesome frontend framework. It&apos;s powered by React under the hood so it plays well with everything React has to offer out of the box: Hooks, Context, hot browser reloading, TypeScript integration, and then it takes it a step further than what Create React App has, and offers even more like &lt;a href=&quot;https://nextjs.org/docs/routing/introduction&quot;&gt;routing&lt;/a&gt;, &lt;a href=&quot;https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props&quot;&gt;server side rendering (SSR)&lt;/a&gt;, &lt;a href=&quot;https://nextjs.org/docs/basic-features/data-fetching/get-static-props&quot;&gt;static site generation (SSG)&lt;/a&gt;, all the SEO juice that comes along with both SSR and SSG, &lt;em&gt;and&lt;/em&gt; built-in &lt;a href=&quot;https://nextjs.org/docs/api-routes/introduction&quot;&gt;API routing&lt;/a&gt; - no extra Node server required to proxy API calls securely to a database, another microservice, or a third party API.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;https://blues.io?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;work&lt;/a&gt;, a team of developers and I have been building a &lt;strong&gt;&lt;a href=&quot;https://github.com/blues/sparrow-starter&quot;&gt;new application&lt;/a&gt;&lt;/strong&gt; that we&apos;ve open sourced to help our users get up and running faster with the Internet of Things (IoT) hardware we create.&lt;/p&gt;
&lt;p&gt;For our first &quot;accelerator application&quot;, the idea is that a user will get some of our &lt;a href=&quot;https://blues.io/products/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;IoT devices&lt;/a&gt;, those devices will begin collecting data like temperature, humidity, motion, etc., they&apos;ll send that environmental data to a &lt;a href=&quot;https://notehub.io?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;cloud&lt;/a&gt;, and then they&apos;ll fork our &quot;starter application&quot; code to get a dashboard up and running, pulling in their own sensor data from the cloud, and displaying it in the browser.&lt;/p&gt;
&lt;p&gt;To build this app, we decided to go with the Next.js framework because it offered so many of the benefits I listed above, one of the most important being the the ability to make secure API calls without having to set up a standalone Node server using Next.js&apos;s &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/api-routes/introduction&quot;&gt;API routes&lt;/a&gt;&lt;/strong&gt;. All of the data displayed by the application must be fetched from the cloud (or a database) where the device data is stored after it&apos;s first recorded.&lt;/p&gt;
&lt;p&gt;And this being a production-ready application, things like automated unit and end-to-end tests to ensure the various pieces of the application work as expected are a requirement - both to give the developers and our users confidence that as new features are added already existing functionality remains intact.&lt;/p&gt;
&lt;p&gt;While by and large, the Next.js &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/getting-started&quot;&gt;documentation&lt;/a&gt;&lt;/strong&gt; is great, one place that it does fall short is when it comes to unit testing these API routes. There is literally nothing in the documentation that touches on how to test API routes with &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt; and &lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro/&quot;&gt;React Testing Library&lt;/a&gt; - the de facto unit testing library combo when it comes to any React-based app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which is why today I&apos;ll be showing you how to unit test Next.js API routes, including gotchas like local environment variables, mocked data objects, and even TypeScript types for Next-specific objects like &lt;code&gt;NextApiRequest&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The actual Next.js API route to test&lt;/h2&gt;
&lt;p&gt;So before we get to the tests, let me give you a brief example of the sorts of API calls this application might make. For our app, the first thing that must be fetched from the cloud is info about the &lt;strong&gt;&quot;gateway devices&quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The files I&apos;ve linked to in the actual repo are historical links in GitHub. The project underwent a major refactor afterwards to more cleanly divide up different layers for future ease of use and flexibility, but if you dig back far enough in the commit history (or just click on the hyperlinked file name) you can see our working code that matches what I&apos;m describing below.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Fetch the gateway device info&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;gateways&lt;/strong&gt; are the brains of the operation - there are a number of sensors that all communicate with the gateways telling them what environmental readings they&apos;re getting at their various locations, and the gateways are responsible for sending that data from each sensor to the cloud - it&apos;s like a hub and spoke system you&apos;d see on a bicycle wheel.&lt;/p&gt;
&lt;p&gt;Before anything else can happen in the app, we have to get the gateway information, which can later be used to figure out which sensors and readings go with which gateways. I won&apos;t go into more details about how the app works because it&apos;s outside the scope of this post, but you can see the whole repo in GitHub &lt;a href=&quot;https://github.com/blues/sparrow-starter&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s focus on the API call going from the Next.js app to our cloud (which happens to be called &lt;a href=&quot;https://notehub.io?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;Notehub&lt;/a&gt;). In order to &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/device-api/#get-device-by-uid?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;query Notehub&lt;/a&gt; we&apos;ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/api-introduction/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;authorization token&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;A Notehub &lt;a href=&quot;https://dev.blues.io/notehub/notehub-walkthrough/#create-a-new-project?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;project&apos;s ID&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;And a gateway &lt;a href=&quot;https://dev.blues.io/reference/glossary/#deviceuid?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;device&apos;s ID&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is an example of the call made to Notehub via Next.js to fetch the gateway device data. I&apos;ll break down what&apos;s happening after the code block.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Click the file name if you&apos;d like to see the original code this file was modeled after.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/sparrow-starter/blob/0a0c26c6e0db042b85861846defe621af999d936/src/pages/api/gateways/%5BgatewayUID%5D.ts&quot;&gt;&lt;code&gt;pages/api/gateways/[gatewayID].ts&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import type { NextApiRequest, NextApiResponse } from &apos;next&apos;;
import axios, { AxiosResponse } from &apos;axios&apos;;

export default async function gatewaysHandler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  // Only allow GET requests
  if (req.method !== &apos;GET&apos;) {
    res.status(405).json({ err: &apos;Method not allowed&apos; });
    return;
  }

  // Gateway UID must be a string
  if (typeof req.query.gatewayID !== &apos;string&apos;) {
    res.status(400).json({ err: &apos;Invalid gateway ID&apos; });
    return;
  }

  // Query params
  const { gatewayID } = req.query;
  // Notehub values
  const { BASE_URL, AUTH_TOKEN, APP_ID } = process.env;
  // API path
  const endpoint = `${BASE_URL}/v1/projects/${APP_ID}/devices/${gatewayID}`;
  // API headers
  const headers = {
    &apos;Content-Type&apos;: &apos;application/json&apos;,
    &apos;X-SESSION-TOKEN&apos;: AUTH_TOKEN,
  };

  // API call
  try {
    const response: AxiosResponse = await axios.get(endpoint, { headers });
    // Return JSON
    res.status(200).json(response.data);
  } catch (err) {
    // Check if we got a useful response
    if (axios.isAxiosError(err)) {
      if (err.response &amp;amp;&amp;amp; err.response.status === 404) {
        // Return 404 error
        res.status(404).json({ err: &apos;Unable to find device&apos; });
      }
    } else {
      // Return 500 error
      res.status(500).json({ err: &apos;Failed to fetch Gateway data&apos; });
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our code, the &lt;strong&gt;&lt;a href=&quot;https://axios-http.com/docs/intro&quot;&gt;Axios HTTP library&lt;/a&gt;&lt;/strong&gt; is used to make our HTTP requests cleaner and simpler, there are &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/environment-variables&quot;&gt;environment variables&lt;/a&gt;&lt;/strong&gt; passed in from a &lt;code&gt;.env.local&lt;/code&gt; file for various pieces of the call to the Notehub project which need to be kept secret (things like &lt;code&gt;APP_ID&lt;/code&gt; and &lt;code&gt;AUTH_TOKEN&lt;/code&gt;), and since this project is written in TypeScript, the &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/typescript#api-routes&quot;&gt;&lt;code&gt;NextApiRequest&lt;/code&gt; and &lt;code&gt;NextApiResponse&lt;/code&gt; types&lt;/a&gt;&lt;/strong&gt; also need to be imported at the top of the file.&lt;/p&gt;
&lt;p&gt;After the imports, there&apos;s a few validation checks to make sure that the HTTP request is a &lt;code&gt;GET&lt;/code&gt;, and the &lt;code&gt;gatewayID&lt;/code&gt; from the query params is a string (which it always should be, but it never hurts to confirm), then the URL request to the Notehub project is constructed (&lt;code&gt;endpoint&lt;/code&gt;) along with the required &lt;code&gt;headers&lt;/code&gt; to allow for access, and the call is finally made with Axios. Once the JSON payload is returned from Notehub, it&apos;s read for further errors like the gateway ID cannot be found, and if everything&apos;s in order, all the gateway info is returned.&lt;/p&gt;
&lt;p&gt;There&apos;s just enough functionality and possible error scenarios to make it interesting, but no so much that it&apos;s overwhelming to test. Time to get on with writing unit tests.&lt;/p&gt;
&lt;h2&gt;Set up API testing in Next.js&lt;/h2&gt;
&lt;p&gt;Ok, now that we&apos;ve seen the actual API route we want to write unit tests for, it&apos;s time to get started. Since we&apos;re just testing API calls instead of components being rendered in the DOM, Jest is the only testing framework we&apos;ll need this time, but that being said, there&apos;s still a little extra configuration to take care of.&lt;/p&gt;
&lt;h3&gt;Install the &lt;code&gt;node-mocks-http&lt;/code&gt; Library&lt;/h3&gt;
&lt;p&gt;The first thing that we&apos;ll need to do in order to mock the HTTP requests and response objects for Notehub (instead of using actual production data, which is much harder to set up correctly every time) is to install the &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/node-mocks-http&quot;&gt;&lt;code&gt;node-mocks-http&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This library allows for mocking HTTP requests by any Node-based application that uses &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; objects (which Next.js does). It has this handy function called &lt;strong&gt;&lt;a href=&quot;https://github.com/howardabrams/node-mocks-http#createmocks&quot;&gt;&lt;code&gt;createMocks()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, which merges together two of its other functions &lt;code&gt;createRequest()&lt;/code&gt; and &lt;code&gt;createResponse()&lt;/code&gt; that allow us to mock both &lt;code&gt;req&lt;/code&gt; and &lt;code&gt;res&lt;/code&gt; objects in the same function. This lets us dictate what Notehub should accept and return when the &lt;code&gt;gatewayHandler()&lt;/code&gt; function is called in our tests.&lt;/p&gt;
&lt;p&gt;Add this library to the project&apos;s &lt;code&gt;devDependencies&lt;/code&gt; list in the &lt;code&gt;package.json&lt;/code&gt; file like so.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev node-mocks-http
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Add an &lt;code&gt;.env.test.local&lt;/code&gt; file for test-related environment variables&lt;/h3&gt;
&lt;p&gt;I learned the hard way that environment variables present in a Next.js project&apos;s &lt;code&gt;.env.local&lt;/code&gt; file (the &lt;a href=&quot;https://nextjs.org/docs/basic-features/environment-variables&quot;&gt;prescribed way Next wants to read environment variables&lt;/a&gt;) do not automatically populate to its unit tests.&lt;/p&gt;
&lt;p&gt;Instead, we need to make a new file at the root of the project named &lt;code&gt;.env.test.local&lt;/code&gt; to hold the &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/environment-variables#test-environment-variables&quot;&gt;test environment variables&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This file will basically be a duplicate of the &lt;code&gt;env.local&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;We&apos;ll include the &lt;code&gt;BASE_URL&lt;/code&gt; to reach our API, a valid &lt;code&gt;AUTH_TOKEN&lt;/code&gt;, a valid &lt;code&gt;APP_ID&lt;/code&gt; and a valid &lt;code&gt;DEVICE_ID&lt;/code&gt;. The &lt;code&gt;DEVICE_ID&lt;/code&gt; is the gateway device&apos;s ID, which actually comes from the app&apos;s URL query parameters but since this is just unit testing this route file&apos;s functionality, to keep all our variables in one centralized place, we&apos;ll pass the gateway&apos;s ID as an environment variable.&lt;/p&gt;
&lt;p&gt;Here&apos;s what your test environment variables file should contain.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Neither this file nor your actual &lt;code&gt;.env.local&lt;/code&gt; file should &lt;em&gt;ever&lt;/em&gt; be committed to your repo in GitHub. Make sure these are in your &lt;code&gt;.gitignore&lt;/code&gt; file so they don&apos;t accidentally make it there where anyone could read potentially secret variables.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.env.test.local&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BASE_URL=https://api.notefile.net
AUTH_TOKEN=[MY_AUTH_TOKEN]
APP_ID=[app:MY_NOTEHUB_PROJECT_ID]
DEVICE_ID=[dev:MY_GATEWAY_DEVICE_ID]
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use real env vars for your test file:&lt;/strong&gt; Although in our final test file you won&apos;t see us importing all of these variables to construct the Notehub URL, if they are not valid and included now, the tests will error out - the tests are actually constructing valid URLs under the hood, we&apos;re just specifying what to send the receive back when the calls are placed. Undefined variables or nonsense test data variables will cause the tests to fail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And with those two things done, we can get to testing.&lt;/p&gt;
&lt;h3&gt;Write the API tests&lt;/h3&gt;
&lt;p&gt;For keeping things in line with what Jest recommends, we can store all our test files inside of a folder at the root of the Next project named &lt;code&gt;__tests__/&lt;/code&gt;, and to make it easy to figure out which tests go with which components, I tend to like to mimic the original file path and name for the file being tested.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you prefer to keep your tests inline with your actual source files, that&apos;s a valid choice as well. I&apos;ve worked with both kinds of code repos so it&apos;s really a matter of personal preference.&lt;/p&gt;
&lt;p&gt;In that case, I tend to just create &lt;code&gt;__tests__/&lt;/code&gt; folders at the root of each folder alongside where the actual files live. So inside of the &lt;code&gt;pages/api/&lt;/code&gt; folder I&apos;d make a new folder named &lt;code&gt;__tests__/&lt;/code&gt; and add any related test files in there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since this is a route API file buried within our &lt;code&gt;pages/&lt;/code&gt; folder, I&apos;d recommend a similar file path inside the &lt;code&gt;__tests__/&lt;/code&gt; folder: &lt;code&gt;__tests__/pages/api/gateways/[gatewayID].test.ts&lt;/code&gt;. In this way, a quick glance at the file name should tell us exactly what this file is testing.&lt;/p&gt;
&lt;p&gt;Then, we come up with possible test cases to cover.&lt;/p&gt;
&lt;p&gt;Some scenarios to test include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Testing a valid response from Notehub with a valid &lt;code&gt;authToken&lt;/code&gt;, &lt;code&gt;APP_ID&lt;/code&gt; and &lt;code&gt;DEVICE_ID&lt;/code&gt; which results in a 200 status code.&lt;/li&gt;
&lt;li&gt;Testing that an invalid gateway ID for a device that doesn&apos;t exist and throws a 404 error.&lt;/li&gt;
&lt;li&gt;Testing that no gateway ID results in a 400 error.&lt;/li&gt;
&lt;li&gt;And testing that trying to make any type of HTTP call besides a &lt;code&gt;GET&lt;/code&gt; results in a 405 error.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is what my tests look like to test this API endpoint. We&apos;ll dig into the details after the big code block.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Click the file name if you&apos;d like to see the original code this file was modeled after.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/blues/sparrow-starter/blob/b1712d3b34040b12794ddc71671649c401450eea/__tests__/src/pages/api/gateways/%5BgatewayUID%5D.test.ts&quot;&gt;&lt;code&gt;__tests__/pages/api/gateways/[gatewayUID].test.ts&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * @jest-environment node
 */
import { createMocks, RequestMethod } from &apos;node-mocks-http&apos;;
import type { NextApiRequest, NextApiResponse } from &apos;next&apos;;
import gatewaysHandler from &apos;../../../../../src/pages/api/gateways/[gatewayUID]&apos;;

describe(&apos;/api/gateways/[gatewayUID] API Endpoint&apos;, () =&amp;gt; {
  const authToken = process.env.AUTH_TOKEN;
  const gatewayID = process.env.DEVICE_ID;

  function mockRequestResponse(method: RequestMethod = &apos;GET&apos;) {
    const {
      req,
      res,
    }: { req: NextApiRequest; res: NextApiResponse } = createMocks({ method });
    req.headers = {
      &apos;Content-Type&apos;: &apos;application/json&apos;,
      &apos;X-SESSION-TOKEN&apos;: authToken,
    };
    req.query = { gatewayID: `${gatewayID}` };
    return { req, res };
  }

  it(&apos;should return a successful response from Notehub&apos;, async () =&amp;gt; {
    const { req, res } = mockRequestResponse();
    await gatewaysHandler(req, res);

    expect(res.statusCode).toBe(200);
    expect(res.getHeaders()).toEqual({ &apos;content-type&apos;: &apos;application/json&apos; });
    expect(res.statusMessage).toEqual(&apos;OK&apos;);
  });

  it(&apos;should return a 404 if Gateway UID is invalid&apos;, async () =&amp;gt; {
    const { req, res } = mockRequestResponse();
    req.query = { gatewayID: &apos;hello_world&apos; }; // invalid gateway ID

    await gatewaysHandler(req, res);

    expect(res.statusCode).toBe(404);
    expect(res._getJSONData()).toEqual({ err: &apos;Unable to find device&apos; });
  });

  it(&apos;should return a 400 if Gateway ID is missing&apos;, async () =&amp;gt; {
    const { req, res } = mockRequestResponse();
    req.query = {}; // Equivalent to a null gateway ID

    await gatewaysHandler(req, res);

    expect(res.statusCode).toBe(400);
    expect(res._getJSONData()).toEqual({
      err: &apos;Invalid gateway UID parameter&apos;,
    });
  });

  it(&apos;should return a 405 if HTTP method is not GET&apos;, async () =&amp;gt; {
    const { req, res } = mockRequestResponse(&apos;POST&apos;); // Invalid HTTP call

    await gatewaysHandler(req, res);

    expect(res.statusCode).toBe(405);
    expect(res._getJSONData()).toEqual({
      err: &apos;Method not allowed&apos;,
    });
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Handle the imports&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before writing our tests we need to import the &lt;code&gt;createMocks&lt;/code&gt; and &lt;code&gt;RequestMethod&lt;/code&gt; variables from the &lt;code&gt;node-mocks-http&lt;/code&gt; library. As I noted earlier, &lt;code&gt;createMocks()&lt;/code&gt; allows us to mock both the &lt;code&gt;req&lt;/code&gt; and &lt;code&gt;res&lt;/code&gt; objects in one function, instead of having to mock them separately.&lt;/p&gt;
&lt;p&gt;Additionally, since this is a TypeScript file, we&apos;ll need to import the &lt;code&gt;NextApiRequest&lt;/code&gt; and &lt;code&gt;NextApiResponse&lt;/code&gt; types from &lt;code&gt;next&lt;/code&gt; - just like for the real API route file.&lt;/p&gt;
&lt;p&gt;And finally, we need to import the real &lt;code&gt;gatewayHandler&lt;/code&gt; function - it&apos;s what we&apos;re trying to unit test after all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create a reusable &lt;code&gt;mockRequestResponse()&lt;/code&gt; helper function&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After creating a &lt;code&gt;describe&lt;/code&gt; block to house all the unit tests, I created a reusable helper function to set up the mocked API call for each test.&lt;/p&gt;
&lt;p&gt;This reusable &lt;code&gt;mockRequestResponse()&lt;/code&gt; function, allows us to only have to construct our mocked HTTP call once, cuts down on the amount of duplicate code in the test files, and makes overall readability easier. Although we may change various parts of the &lt;code&gt;req&lt;/code&gt; or &lt;code&gt;res&lt;/code&gt; object based on what scenario is being tested, writing this function once and being able to call it inside of each test is a big code (and time) saver.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const authToken = process.env.AUTH_TOKEN;
const gatewayID = process.env.DEVICE_ID;

function mockRequestResponse(method: RequestMethod = &apos;GET&apos;) {
  const {
    req,
    res,
  }: { req: NextApiRequest; res: NextApiResponse } = createMocks({ method });
  req.headers = {
    &apos;Content-Type&apos;: &apos;application/json&apos;,
    &apos;X-SESSION-TOKEN&apos;: authToken,
  };
  req.query = { gatewayID: `${gatewayID}` };
  return { req, res };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above, I&apos;ve pulled out a snippet from the larger code block that focuses just on the &lt;code&gt;mockRequestResponse()&lt;/code&gt; function and the two environment variables it needs to during its construction &lt;code&gt;authToken&lt;/code&gt; and &lt;code&gt;gatewayID&lt;/code&gt;. After declaring the function name we specify its method using the &lt;code&gt;node-http-mocks&lt;/code&gt; &lt;code&gt;RequestMethod&lt;/code&gt; object: &lt;code&gt;method:RequestMethod=&quot;GET&quot;&lt;/code&gt;, and then we destructure and set the &lt;code&gt;req&lt;/code&gt; and &lt;code&gt;res&lt;/code&gt; object types that come from the &lt;code&gt;createMocks()&lt;/code&gt; function as &lt;code&gt;NextApiRequest&lt;/code&gt; and &lt;code&gt;NextApiResponse&lt;/code&gt; (just like in our real code).&lt;/p&gt;
&lt;p&gt;We create the same &lt;code&gt;req.headers&lt;/code&gt; object that Notehub requires with our test-version &lt;code&gt;authToken&lt;/code&gt;, and set the mocked query parameter &lt;code&gt;gatewayID&lt;/code&gt; equal to the &lt;code&gt;gatewayID&lt;/code&gt; being supplied by our &lt;code&gt;.env.test.local&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Write each test&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With our &lt;code&gt;mockRequestResponse()&lt;/code&gt; function built, we can simply call it inside of each test to get our mocked &lt;code&gt;req&lt;/code&gt; and &lt;code&gt;res&lt;/code&gt; objects, call the actual &lt;code&gt;gatewayHandler()&lt;/code&gt; function with those mocked objects, and make sure the responses that come back are what we expect.&lt;/p&gt;
&lt;p&gt;If a property on the &lt;code&gt;req&lt;/code&gt; object needs to be modified before the call to &lt;code&gt;gatewayHandler&lt;/code&gt; is made, it&apos;s as straight forward as calling the &lt;code&gt;mockRequestResponse()&lt;/code&gt; function and then modifying whatever property of the &lt;code&gt;req&lt;/code&gt; object needs to be updated.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { req, res } = mockRequestResponse();
req.query = { gatewayID: &apos;hello_world&apos; };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To check response objects, especially for error scenarios where different error strings are passed when a gateway ID is missing or invalid, we can use the &lt;code&gt;res._getJSONData()&lt;/code&gt; function to actually read out the contents of the response. That way we can check actual error message along with the HTTP status codes.&lt;/p&gt;
&lt;p&gt;Pretty handy, right?&lt;/p&gt;
&lt;h3&gt;Check the test code coverage&lt;/h3&gt;
&lt;p&gt;If you&apos;re using &lt;strong&gt;&lt;a href=&quot;https://jestjs.io/docs/configuration#collectcoverage-boolean&quot;&gt;Jest&apos;s code coverage&lt;/a&gt;&lt;/strong&gt; reporting features, now&apos;s a good time to run that function and check out the code coverage for this file in the terminal printout or the browser.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can open the code coverage report via the command line by typing: &lt;code&gt;open coverage/lcov-report/index.html&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And hopefully, when you navigate to the code coverage for the &lt;code&gt;pages/api/&lt;/code&gt; routes, you&apos;ll see some much better code coverage for this file now.&lt;/p&gt;
&lt;p&gt;Now go forth and add unit tests to all other API routes as needed.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I&apos;m a fan of the Next.js framework - it&apos;s React at its heart with lots of niceties like SEO and API routes baked in. While Next fits the bill for many projects nowadays and helps get us up and running fast with projects, its testing documentation leaves something to be desired - especially for some of its really great additions like API routes.&lt;/p&gt;
&lt;p&gt;Automated testing is a requirement in today&apos;s modern software world, and being able to write unit tests to continue to confirm an app&apos;s functionality works as expected isn&apos;t something to be ignored or glossed over. Luckily, the &lt;code&gt;node-mocks-http&lt;/code&gt; library helps make setting up mocked &lt;code&gt;req&lt;/code&gt; and &lt;code&gt;res&lt;/code&gt; objects simple, so that we can test our Next.js app from all angles - from presentational components in the DOM down to API routes on the backend.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope learning how to unit test API routes helps you out in your next Next.js project (no pun intended!).&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/&quot;&gt;Next.js framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest unit testing library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro/&quot;&gt;React Testing Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://axios-http.com/docs/intro&quot;&gt;Axios HTTP library&lt;/a&gt; docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://notehub.io?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=sparrow-accelerator&amp;amp;utm_content=unit-test-nextjs-routes&quot;&gt;Notehub&lt;/a&gt; cloud&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/node-mocks-http&quot;&gt;Node mocks HTTP&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;Full &lt;a href=&quot;https://github.com/blues/sparrow-starter&quot;&gt;GitHub project repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>nextjs</category><category>react</category><category>typescript</category><category>api</category><category>testing</category></item><item><title>Create an Asset Tracker with Next.js and React Leaflet</title><link>https://www.paigeniedringhaus.com/blog/create-an-asset-tracker-with-nextjs-and-react-leaflet/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/create-an-asset-tracker-with-nextjs-and-react-leaflet/</guid><description>Incremental static regeneration makes updating static pages easy.</description><pubDate>Tue, 18 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/asset-tracker-map-nextjs-react-leaflet/asset-tracker-map.png&quot; alt=&quot;React-Leaflet map rendering the asset tracker&apos;s location&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Recently I began working for an Internet of Things startup, &lt;strong&gt;&lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Blues Wireless&lt;/a&gt;&lt;/strong&gt; that aims to make IoT development easier - even when reliable Internet connections are not available. Blues does this via &lt;strong&gt;&lt;a href=&quot;https://blues.io/products/notecard/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecards&lt;/a&gt;&lt;/strong&gt; - prepaid cellular devices that can be embedded into any IoT device &quot;on the edge&quot; to transmit sensor data as JSON to a secure cloud: &lt;strong&gt;&lt;a href=&quot;https://notehub.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notehub&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Since web development is my main area of expertise (not IoT development), I started off building an easier IoT project: an &lt;strong&gt;&lt;a href=&quot;https://www.hackster.io/paige-niedringhaus/low-code-gps-asset-tracker-and-map-display-b10419&quot;&gt;asset tracker&lt;/a&gt;&lt;/strong&gt; using just a Blues &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/note-nbgl-500/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecard&lt;/a&gt;&lt;/strong&gt;, Blues &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/carr-al/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecarrier AL&lt;/a&gt;&lt;/strong&gt; with a built-in GPS antenna, and a small &lt;strong&gt;&lt;a href=&quot;https://www.adafruit.com/product/328&quot;&gt;lithium-ion polymer (LiPo) battery&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With the help of the Blues &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/guides-and-tutorials/notecard-guides/asset-tracking/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;developer experience documentation&lt;/a&gt;&lt;/strong&gt;, I had GPS location data being delivered to the Notehub cloud in short order. That&apos;s cool and all, but the way that data from sensors in the world really becomes useful is when it&apos;s displayed to users in some sort of UI, right? It could be charts, tables, or in my case, a map.&lt;/p&gt;
&lt;p&gt;So I wanted to take my data from the Notehub cloud and put it into a custom-made dashboard to track and display the Notecard&apos;s location in the real world. Since React is my current JavaScript framework of choice, I decided to build a Next.js- TypeScript-powered dashboard, and I learned a ton of stuff in the process, which I intend to share with you over a series of blog posts in the next few months.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this article, I&apos;m going to show you how to add a map to a Next.js application, pull in location data from a third-party API source, and regularly revalidate the data to update the map when new location data is present.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s what the final dashboard looks like - the map is the focus for this particular post:&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=uUJiX9q8x9M&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Set up a map component in Next.js app&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This article will not go through the initial setup of a brand new Next.js app - that&apos;s outside the scope of this post. If you&apos;re starting from scratch, I would recommend following the &lt;a href=&quot;https://nextjs.org/docs/basic-features/typescript&quot;&gt;Next.js starter app with TypeScript documentation&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;d prefer, you can also fork and download my whole, working code from the GitHub repo &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Install map project dependencies&lt;/h3&gt;
&lt;p&gt;The first thing to do in this post, is add a map to a Next project. This is going to require a few new npm packages added to our project: &lt;strong&gt;&lt;a href=&quot;https://leafletjs.com/&quot;&gt;leaflet&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href=&quot;https://react-leaflet.js.org/&quot;&gt;react-leaflet&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://github.com/ghybs/leaflet-defaulticon-compatibility&quot;&gt;leaflet-defaulticon-compatibility&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install leaflet react-leaflet leaflet-defaulticon-compatibility
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; You&apos;ll also need &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-dom&lt;/code&gt; as peer dependencies if they&apos;re not already in your project, too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;leaflet&lt;/strong&gt; is our base, JavaScript library for interactive maps - it provides the basis upon which our other packages depend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;react-leaflet&lt;/strong&gt; provides easier-to-use React components for Leaflet maps. It provides bindings between React and Leaflet, not replacing Leaflet, but leveraging it to abstract Leaflet layers as React components. If you&apos;re curious to learn more about React Leaflet, I recommend perusing the &lt;a href=&quot;https://react-leaflet.js.org/docs/start-introduction/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;leaflet-defaulticon-compatibility&lt;/strong&gt; retrieves all Leaflet Default Icon options from CSS, in particular all icon images URL&apos;s, to improve compatibility with bundlers and frameworks that modify URL&apos;s in CSS.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Build engines and frameworks that modify URLs in CSS, can often conflict with Leaflet built-in Default Icon images automatic management, and this package helps handle it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;TypeScript Note:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re using TypeScript in your project, you&apos;ll also want to want to install the follow dev dependency to avoid TypeScript errors:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install @types/leaflet --save-dev 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With new map libraries installed, it&apos;s time to move on to configuring the project to use these new resources.&lt;/p&gt;
&lt;h3&gt;Generate a Mapbox token for the map&apos;s display style and add it to the project&lt;/h3&gt;
&lt;p&gt;For the map display that the asset tracker will be on, I chose to use &lt;strong&gt;&lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox&lt;/a&gt;&lt;/strong&gt; styles. It&apos;s got a lot of nice &lt;strong&gt;&lt;a href=&quot;https://docs.mapbox.com/api/maps/styles/&quot;&gt;map display styles&lt;/a&gt;&lt;/strong&gt; to choose from, and developers can create their own &lt;strong&gt;&lt;a href=&quot;https://docs.mapbox.com/help/getting-started/access-tokens/&quot;&gt;Mapbox API tokens&lt;/a&gt;&lt;/strong&gt; to access these styles by signing up for a free &lt;strong&gt;&lt;a href=&quot;https://account.mapbox.com/auth/signup/&quot;&gt;Mapbox account&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After you&apos;ve signed up and created a new API token, copy the token value - it will be used in the Next.js app. In the Next.js app&apos;s &lt;code&gt;next.config.js&lt;/code&gt; file at the root of the project, add the API token like so:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;next.config.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/** @type {import(&apos;next&apos;).NextConfig} */
module.exports = {
  reactStrictMode: true,
  env: {
    MAPBOX_ACCESS_TOKEN:
      &quot;[MAPBOX_TOKEN]&quot;,
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From this file, Next can access the token when it needs to call the Mapbox API endpoint. Next, we&apos;ll create the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component in our project.&lt;/p&gt;
&lt;h3&gt;Create the &lt;code&gt;&amp;lt;Map&amp;gt;&lt;/code&gt; component&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/asset-tracker-map-nextjs-react-leaflet/asset-tracker-map-2.png&quot; alt=&quot;React-Leaflet map rendering the asset tracker&apos;s location&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is how the component looks rendered out with GPS data.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As this is a React project, individual, reusable components are how I like to roll, so inside of the project, create a new file named &lt;code&gt;Map.tsx&lt;/code&gt; and paste in the following code. The live code is available by clicking the file title below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/src/components/Map.tsx&quot;&gt;&lt;code&gt;Map.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {
  MapContainer,
  TileLayer,
  Marker,
  Popup,
  GeoJSON,
  CircleMarker,
} from &quot;react-leaflet&quot;;
import &quot;leaflet/dist/leaflet.css&quot;;
import &quot;leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css&quot;;
import &quot;leaflet-defaulticon-compatibility&quot;;

const Map = ({
  coords,
  lastPosition,
  markers,
  latestTimestamp,
}: {
  coords: number[][];
  lastPosition: [number, number];
  markers: [number, number][];
  latestTimestamp: string;
}) =&amp;gt; {
  const geoJsonObj: any = [
    {
      type: &quot;LineString&quot;,
      coordinates: coords,
    },
  ];

  const mapMarkers = markers.map((latLng, i) =&amp;gt; (
    &amp;lt;CircleMarker key={i} center={latLng} fillColor=&quot;navy&quot; /&amp;gt;
  ));

  return (
    &amp;lt;&amp;gt;
      &amp;lt;h2&amp;gt;Asset Tracker Map&amp;lt;/h2&amp;gt;
      &amp;lt;MapContainer
        center={lastPosition}
        zoom={12}
        style={{ height: &quot;100%&quot;, width: &quot;100%&quot; }}
      &amp;gt;
        &amp;lt;TileLayer
          url={`https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.MAPBOX_ACCESS_TOKEN}`}
        /&amp;gt;
        &amp;lt;Marker position={lastPosition} draggable={true}&amp;gt;
          &amp;lt;Popup&amp;gt;
            Last recorded position:
            &amp;lt;br /&amp;gt;
            {lastPosition[0].toFixed(3)}&amp;amp;#176;,&amp;amp;nbsp;
            {lastPosition[1].toFixed(3)}&amp;amp;#176;
            &amp;lt;br /&amp;gt;
            {latestTimestamp}
          &amp;lt;/Popup&amp;gt;
          &amp;lt;GeoJSON data={geoJsonObj}&amp;gt;&amp;lt;/GeoJSON&amp;gt;
          {mapMarkers}
        &amp;lt;/Marker&amp;gt;
      &amp;lt;/MapContainer&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default Map;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&apos;s talk about everything that&apos;s going on in this component.&lt;/p&gt;
&lt;p&gt;At the top of the file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;all the individual React Leaflet components needed for this component are imported,&lt;/li&gt;
&lt;li&gt;the original Leaflet CSS is imported,&lt;/li&gt;
&lt;li&gt;&lt;em&gt;and&lt;/em&gt; the Leaflet Default Icon Compatibility CSS and JS are imported afterwards - as specified by the &lt;a href=&quot;https://www.npmjs.com/package/leaflet-defaulticon-compatibility#usage&quot;&gt;usage instructions&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, are the props that this component accepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;coords&lt;/code&gt;&lt;/strong&gt; - a list of arrays that have GPS longitude and latitude in them - this draws the connecting lines between coordinates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lastPosition&lt;/code&gt;&lt;/strong&gt; - the most recent GPS latitude and longitude to display in the popup when the user clicks the icon on the map.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;markers&lt;/code&gt;&lt;/strong&gt; - another list of arrays that have GPS latitude and longitude (yes, the order of coordinates is reversed in these arrays) to display the blue circles of previous places on the map the tracker was.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;latestTimestamp&lt;/code&gt;&lt;/strong&gt; - the most recent timestamp of GPS coordinates received (also for displaying in the popup on the map).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s skip down to the JSX.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;MapContainer /&amp;gt;&lt;/code&gt;&lt;/strong&gt; is the component responsible for creating the Leaflet Map instance and providing it to its child components - without this component, the map won&apos;t work. In this component we can define the map&apos;s &lt;code&gt;center&lt;/code&gt; coordinates, its default zoom level on the map, and some basic styling for the component to display properly.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;&amp;lt;TileLayer /&amp;gt;&lt;/code&gt;&lt;/strong&gt; component is where our Mapbox style and newly generated API token come into play. Just choose whatever style suits your fancy, replace the &lt;code&gt;streets-v11&lt;/code&gt; portion of the string with it, and make sure the Mapbox token is present in the &lt;code&gt;next.config.js&lt;/code&gt; file, which I showed in the previous step. Without this component there&apos;s no map background for the coordinates to render on - instead it will just be a blank canvas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;Marker /&amp;gt;&lt;/code&gt;&lt;/strong&gt; takes in the &lt;code&gt;lastPosition&lt;/code&gt; prop to display the icon on the map of the tracker&apos;s last recorded position, and it wraps the &lt;code&gt;&amp;lt;Popup /&amp;gt;&lt;/code&gt; component, the &lt;code&gt;&amp;lt;GeoJSON /&amp;gt;&lt;/code&gt; component, and the list of &lt;code&gt;&amp;lt;CircleMarker /&amp;gt;&lt;/code&gt; components.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;&amp;lt;Popup /&amp;gt;&lt;/code&gt;&lt;/strong&gt; component is a nicely-styled tooltip that can display whatever info is desired. My &lt;code&gt;&amp;lt;Popup /&amp;gt;&lt;/code&gt; shows the tracker&apos;s last GPS coordinates and time it was reported when a user clicks on it, but it can display anything you want.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;&amp;lt;GeoJson /&amp;gt;&lt;/code&gt;&lt;/strong&gt; component is where the &lt;code&gt;coords&lt;/code&gt; list of GPS longitude and latitude arrays are passed in to draw the connecting lines between coordinates. The &lt;code&gt;type: &quot;LineString&quot;&lt;/code&gt; in the &lt;code&gt;geoJsonObj&lt;/code&gt; where the coordinates are fed in, is what handles it.&lt;/p&gt;
&lt;p&gt;And last but not least, the &lt;strong&gt;&lt;code&gt;&amp;lt;CircleMarker &amp;gt;/&lt;/code&gt;&lt;/strong&gt; components, which are displayed in this component&apos;s JSX as &lt;code&gt;{mapMarkers}&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; In order to get all the &lt;code&gt;markers&lt;/code&gt; in the list to render as individual circles on the map, I had to create this little function to iterate over the list and generate all the circles, then inject that directly into the JSX.&lt;/p&gt;
&lt;p&gt;Trying to iterate over all the values inside the JSX wouldn&apos;t work, which I believe is an example of how this &lt;code&gt;react-leaflet&lt;/code&gt; package behaves differently from traditional React code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that&apos;s all that&apos;s going on in this component, not so complicated when it&apos;s broken down into the individual pieces that make it up, right?&lt;/p&gt;
&lt;h3&gt;Render the map in a Next.js app&lt;/h3&gt;
&lt;p&gt;Our final step to get the map rendering inside of a Next app: importing the component with the option &lt;code&gt;ssr:false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since the &lt;code&gt;react-leaflet&lt;/code&gt; library only works in the browser, we have to use Next.js&apos;s &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr&quot;&gt;&lt;code&gt;dynamic import()&lt;/code&gt; support with no SSR&lt;/a&gt;&lt;/strong&gt; to tell the map component to only render after the Next.js server-side rendering has happened.&lt;/p&gt;
&lt;p&gt;So wherever this &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component is being injected into your app, use the syntax detailed below. In my app, it&apos;s in the &lt;code&gt;index.tsx&lt;/code&gt; page file, and I&apos;ve condensed the code in the file down for clarity. Click on the file title to see the full code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import dynamic from &quot;next/dynamic&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
  // needed to make the Leaflet map render correctly
  const MapWithNoSSR = dynamic(() =&amp;gt; import(&quot;../src/components/Map&quot;), {
    ssr: false,
  });

  // logic to transform data into the items needed to pass to the map

return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;MapWithNoSSR
            coords={lngLatCoords}
            lastPosition={lastPosition}
            markers={latLngMarkerPositions}
            latestTimestamp={latestTimestamp}
          /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// more code down here: getStaticProps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; has been dynamically imported with server-side rendering disabled, the component can be used just like any other in the application. Simple as that.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At this point, feel free to mock some hard coded data for the map to make sure it&apos;s working correctly. In the next section, I&apos;ll cover pulling in live data from the Notehub cloud were my asset tracker location data currently lives.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Pull in the data for the map&lt;/h2&gt;
&lt;p&gt;Ok, so the map is set up in the app, now it&apos;s time to give it some data to display. If you&apos;d like to build your own asset tracker like I did, you&apos;re welcome to - I&apos;ll briefly outline the hardware I used and point you towards the documentation to get it configured - the very same documentation I used to set mine up.&lt;/p&gt;
&lt;h3&gt;IoT Hardware list&lt;/h3&gt;
&lt;p&gt;Here&apos;s the equipment you&apos;ll need to make this project happen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blues Wireless &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/note-nbgl-500/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;NB-IoT &amp;amp; LTE-M Notecard Global&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;strong&gt;&lt;a href=&quot;https://shop.blues.io/products/carr-al/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notecarrier AL with LiPo battery connector&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.adafruit.com/product/328&quot;&gt;LiPo battery&lt;/a&gt;&lt;/strong&gt; from an IoT supplier like Adafruit (mine is the 3.7v 2500mAh version)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Initial Notecard and Notecarrier AL configuration&lt;/h3&gt;
&lt;p&gt;Follow the Blues &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/start/quickstart/notecarrier-al/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;quickstart guide&lt;/a&gt;&lt;/strong&gt; to set up the Notecard, Notecarrier, and first Notehub project, and the Blues &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/notecard/notecard-guides/asset-tracking/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;asset tracking guide&lt;/a&gt;&lt;/strong&gt; for the commands needed to configure a Notecard for GPS location tracking.&lt;/p&gt;
&lt;p&gt;In addition to these instructions, there&apos;s an important caveat to make this asset tracker work for our purposes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the final configuration step: &lt;a href=&quot;https://dev.blues.io/notecard/notecard-guides/asset-tracking/#tracker-configuration-requests?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;&lt;code&gt;card.location.track&lt;/code&gt;&lt;/a&gt; where the tracker starts running, include the property of: &lt;code&gt;&quot;sync&quot; : true&lt;/code&gt;. This property means &lt;em&gt;as soon as&lt;/em&gt; a new event is acquired by the Notecard (a new GPS location, in this case), the Notecard will sync the event to Notehub instead of waiting for its regularly scheduled &lt;code&gt;outbound&lt;/code&gt; time.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;re curious, here&apos;s all of the commands I used to set up my Notecard from start to finish using the &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/notecard-playground/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;built-in web REPL&lt;/a&gt;&lt;/strong&gt; on the Blues &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;developer experience site&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;$ {&quot;req&quot;:&quot;card.restore&quot;,&quot;delete&quot;:true}
#factory reset Notecard

$ {&quot;req&quot;:&quot;hub.set&quot;,&quot;product&quot;:&quot;com.blues.[NOTEHUB_PROJECT_ID_HERE]&quot;,&quot;mode&quot;:&quot;periodic&quot;,&quot;outbound&quot;:10,&quot;inbound&quot;:60}
#attach tracker to Notehub project, set it to periodic mode,
#sync outbound requests from the Notecard every 10 mins and inbound reqs from Notehub every 60 mins

$ {&quot;req&quot;:&quot;card.location.mode&quot;,&quot;mode&quot;:&quot;periodic&quot;,&quot;seconds&quot;:360}
#tell card how often to get GPS reading and only when motion is detected

$ {&quot;req&quot;:&quot;card.location.track&quot;,&quot;start&quot;:true,&quot;heartbeat&quot;:true,&quot;hours&quot;:12,&quot;sync&quot;:true}
#start tracking, issue heartbeat every 12 hours when no motion detected,
#sync data with Notehub as soon as a tracking event is acquired (this is an important one)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Use the Notehub API to fetch the tracker data into Next.js&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/api-introduction/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notehub API&lt;/a&gt; can be used to fetch &lt;strong&gt;events&lt;/strong&gt; (the data containing Notecard GPS coordinates) directly from Notehub. The Notehub API requires users to create an &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/reference/notehub-api/api-introduction/#authentication/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;authorization token&lt;/a&gt;&lt;/strong&gt; to be passed along with requests, but the process is well documented, as is the &lt;strong&gt;&lt;a href=&quot;https://dev.blues.io/reference/notehub-api/event-api/#get-events-by-project/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;API to fetch all events&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generate a Notehub auth token&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Below is the code to run in the command line to generate the Notehub authorization token:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl -X POST
-L &apos;https://api.notefile.net/auth/login&apos;
-d &apos;{&quot;username&quot;:&quot;[you@youremail.com]&quot;, &quot;password&quot;: &quot;[your_password]&quot;}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy this token and inside of your Next.js project, at the root of the project, create a &lt;code&gt;.env.local&lt;/code&gt; file - this is where sensitive info will be kept: secrets, project info, and anything else you&apos;d rather not commit to GitHub for all the world to see. Here&apos;s an example of what the file should look like, and the two secret variables it needs:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/.env&quot;&gt;&lt;code&gt;.env.local&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NOTEHUB_PROJECT_ID=APP_ID_GOES_HERE # get this from Notehub
NOTEHUB_TOKEN=NOTEHUB_GENERATED_TOKEN_GOES_HERE # paste in token generated in previous step
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;This &lt;code&gt;.env.local&lt;/code&gt; file is how &lt;a href=&quot;https://nextjs.org/docs/basic-features/environment-variables#loading-environment-variables&quot;&gt;Next.js automatically reads in environment variables&lt;/a&gt; used at build time or on the client side. All the variables you&apos;ll need are build time variables so none of them need to be prefixed with &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt;, which allows for variable access on the client side.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Create a &lt;code&gt;fetchNotecardData()&lt;/code&gt; function in Next.js&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With our Notehub token and project ID specified in the &lt;code&gt;.env.local&lt;/code&gt; file, now we can make our connection to Notehub via Next&apos;s &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/data-fetching/get-static-props&quot;&gt;&lt;code&gt;getStaticProps&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; function.&lt;/p&gt;
&lt;p&gt;Create a new file named something like &lt;code&gt;notecardData.ts&lt;/code&gt;, this is where the function to fetch data from Notehub and filter down to the events we want - the &lt;code&gt;_track.qo&lt;/code&gt; events - will live.&lt;/p&gt;
&lt;p&gt;Here is what the code to fetch events will look like - click on the file name to see the code in my actual repo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/src/lib/notecardData.ts&quot;&gt;&lt;code&gt;notecardData.ts&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export async function fetchNotecardData() {
  interface dataProps {
    [file: string]: any;
  }

  let eventArray: object[] = [];
  const baseUrl = `https://api.notefile.net/v1/projects/${process.env.NOTEHUB_PROJECT_ID}/events`;

  const headers = {
    &quot;Content-Type&quot;: &quot;application/json&quot;,
    &quot;X-SESSION-TOKEN&quot;: `${process.env.NOTEHUB_TOKEN}`,
  };

  const res = await fetch(fullUrl, {
    headers: headers,
  });
  const eventData = await res.json();
  eventArray = eventData.events;

  while (eventData.has_more) {
    const res = await fetch(`${baseUrl}?since=${eventData.through}`, {
      headers: headers,
    });
    const newEventData = await res.json();
    eventArray = [...eventArray, ...newEventData.events];
    if (newEventData.has_more) {
      eventData.through = newEventData.through;
    } else {
      eventData.has_more = false;
    }
  }

  const filteredEvents = eventArray.filter(
    (event: dataProps) =&amp;gt; event.file === &quot;_track.qo&quot;
  );

  return filteredEvents;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although this file looks verbose at first glance, it&apos;s not actually that complex.&lt;/p&gt;
&lt;p&gt;It starts off setting up a &lt;strong&gt;&lt;code&gt;baseUrl&lt;/code&gt;&lt;/strong&gt; that defines the URL connection to &lt;a href=&quot;https://dev.blues.io/reference/notehub-api/event-api/#get-events-by-project/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;Notehub events&lt;/a&gt; - this is where access the &lt;code&gt;NOTEHUB_PROJECT_ID&lt;/code&gt; environment variable comes into play.&lt;/p&gt;
&lt;p&gt;Then the &lt;strong&gt;&lt;code&gt;header&lt;/code&gt;&lt;/strong&gt; object containing the &lt;code&gt;&quot;X-SESSION-TOKEN&quot;&lt;/code&gt;, which is set equal to our generated &lt;code&gt;NOTEHUB_TOKEN&lt;/code&gt;, is up next.&lt;/p&gt;
&lt;p&gt;After that, the Notehub event endpoint is hit, and it will automatically pull back the first 50 events it has stored, and if there&apos;s more events than what was just returned, the JSON response list will also include the properties &lt;strong&gt;&lt;code&gt;through&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;has_more&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;has_more&lt;/code&gt; exists, this &lt;code&gt;while&lt;/code&gt; loop function will keep hitting Notehub using the &lt;code&gt;through&lt;/code&gt; value (the globally-unique identifier of the last event in the array of returned events), until there are no more events to add to the &lt;code&gt;eventArray&lt;/code&gt; list.&lt;/p&gt;
&lt;p&gt;Finally, all of the events that have been gathered up are filtered down to only the &lt;code&gt;_track.qo&lt;/code&gt; type, because those are the events that contain the tracker&apos;s GPS coordinates.&lt;/p&gt;
&lt;h3&gt;Call the &lt;code&gt;fetchNotecardData()&lt;/code&gt; function on the page&lt;/h3&gt;
&lt;p&gt;With our function to connect to Notehub and get event data constructed, it&apos;s time to make that call in the page where the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component is located. To do this, we&apos;ll be using Next&apos;s &lt;code&gt;getStaticProps&lt;/code&gt; function to fetch the data server-side.&lt;/p&gt;
&lt;p&gt;Inside of the &lt;code&gt;index.tsx&lt;/code&gt; file where we previously imported the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component, we&apos;ll add the following code down at the bottom of the file. I&apos;ve condensed the rest of the file for clarity, but the full file is linked below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import { GetStaticProps } from &quot;next&quot;;
import { fetchNotecardData } from &quot;../src/lib/notecardData&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
  // map component imported dynamically here

  // logic to transform data into the items needed to pass to the map

return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;MapWithNoSSR
            coords={lngLatCoords}
            lastPosition={lastPosition}
            markers={latLngMarkerPositions}
            latestTimestamp={latestTimestamp}
          /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export const getStaticProps: GetStaticProps = async () =&amp;gt; {
  const data = await fetchNotecardData();
  return { props: { data } };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To call the Notehub API in the &lt;code&gt;index.tsx&lt;/code&gt; file on the server-side, we import the &lt;code&gt;fetchNotecardData()&lt;/code&gt; function itself, import the &lt;code&gt;getStaticProps&lt;/code&gt; function from Next, and then at the end of the file, call &lt;code&gt;fetchNotecardData()&lt;/code&gt; from inside the &lt;code&gt;getStaticProps&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Finally we return that data from Notehub as &lt;code&gt;props&lt;/code&gt; that can be passed to the &lt;code&gt;Home&lt;/code&gt; component.&lt;/p&gt;
&lt;h3&gt;Massage the data into shape for the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component&lt;/h3&gt;
&lt;p&gt;Good. We&apos;ve got data from Notehub, and there&apos;s one last thing to do: take this JSON data returned from Notehub and re-shape it to fit the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component. Once again, I&apos;ve condensed down the logic to make this file easier to read, but you can see the full file on GitHub.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import { useEffect, useState } from &quot;react&quot;;
import dayjs from &quot;dayjs&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
  // map component imported dynamically here

  // state variables for the various pieces of data passed to the map
  const [lngLatCoords, setLngLatCoords] = useState&amp;lt;number[][]&amp;gt;([]);
  const [lastPosition, setLastPosition] = useState&amp;lt;[number, number]&amp;gt;([
      00.00, 00.00
  ]);
  const [latestTimestamp, setLatestTimestamp] = useState&amp;lt;string&amp;gt;(&quot;&quot;);
  const [latLngMarkerPositions, setLatLngMarkerPositions] = useState&amp;lt;
    [number, number][]
  &amp;gt;([]);

  // logic to transform data into the items needed to pass to the map
  useEffect(() =&amp;gt; {
    const lngLatArray: number[][] = [];
    const latLngArray: [number, number][] = [];
   
    if (data &amp;amp;&amp;amp; data.length &amp;gt; 0) {
      data
        .sort((a, b) =&amp;gt; {
          return Number(a.captured) - Number(b.captured);
        })
        .map((event) =&amp;gt; {
          let lngLatCoords: number[] = [];
          let latLngCoords: [number, number] = [0, 1];

          lngLatCoords = [
            event.gps_location?.longitude,
            event.gps_location?.latitude,
          ];
          latLngCoords = [
            event.gps_location?.latitude,
            event.gps_location?.longitude,
          ];
          
          lngLatArray.push(lngLatCoords);
          latLngArray.push(latLngCoords);
        });
      const lastEvent = data.at(-1);
      let lastCoords: [number, number] = [0, 1];
      lastCoords = [
        lastEvent.gps_location.latitude,
        lastEvent.gps_location.longitude,
      ];
      setLastPosition(lastCoords);
      const timestamp = dayjs(lastEvent?.captured).format(&quot;MMM D, YYYY h:mm A&quot;);
      setLatestTimestamp(timestamp);
    }
    setLngLatCoords(lngLatArray);
    setLatLngMarkerPositions(latLngArray);
  }, [data]);

return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;MapWithNoSSR
            coords={lngLatCoords}
            lastPosition={lastPosition}
            markers={latLngMarkerPositions}
            latestTimestamp={latestTimestamp}
          /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// getStaticProps call to Notehub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this function, once the data is fetched from Notehub and passed to the component, we set some new React &lt;code&gt;useState&lt;/code&gt; variables to hold the data to pass to the &lt;code&gt;&amp;lt;Map /&amp;gt;&lt;/code&gt; component.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;There&apos;s a &lt;strong&gt;&lt;code&gt;lngLatCoords&lt;/code&gt;&lt;/strong&gt; list - this is list of coordinates that will be used to draw the lines between the recorded GPS coordinates (and it must be passed as &lt;code&gt;[longitude, latitude]&lt;/code&gt; to the &lt;code&gt;&quot;LineString&quot;&lt;/code&gt; &lt;code&gt;&amp;lt;GeoJSON /&amp;gt;&lt;/code&gt; component).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;lastPosition&lt;/code&gt;&lt;/strong&gt; state variable is used to center the map, center the marker icon, and display in the &lt;code&gt;&amp;lt;Popup /&amp;gt;&lt;/code&gt; along with the &lt;strong&gt;&lt;code&gt;latestTimestamp&lt;/code&gt;&lt;/strong&gt; variable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;And the &lt;strong&gt;&lt;code&gt;latLngMarkerPositions&lt;/code&gt;&lt;/strong&gt; list is similar to the &lt;code&gt;lngLatCoords&lt;/code&gt; variable except the coordinates here are in the order of &lt;code&gt;[latitude, longitude]&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inside of the &lt;code&gt;useEffect()&lt;/code&gt; function the array of Notehub events is sorted and then iterated over to pull out all the relevant data in the shape required. And once all the events have been transformed, they&apos;re set in state and passed to the map.&lt;/p&gt;
&lt;h2&gt;Update the data regularly using ISR&lt;/h2&gt;
&lt;p&gt;There&apos;s one last thing we have not yet discussed and that is how to handle new &lt;code&gt;_track.qo&lt;/code&gt; events that get sent to Notehub &lt;strong&gt;after the asset tracking app originally loads the data and renders the map&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Early on as I was building my tracker, I had a simple &lt;code&gt;refreshData()&lt;/code&gt; function I was using to force Next.js to refetch Notehub data on the server-side on an interval every 5 minutes, but then I learned a much better way that is actually built in to Next: &lt;strong&gt;&lt;a href=&quot;https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration&quot;&gt;incremental static regeneration&lt;/a&gt;&lt;/strong&gt; (ISR).&lt;/p&gt;
&lt;p&gt;ISR enables us to use static-generation on a per-page basis, without needing to rebuild the entire site. What this means in practice is:
&lt;code&gt;getStaticProps&lt;/code&gt; is still called to fetch the data, but additionally a &lt;code&gt;revalidate&lt;/code&gt; option is passed in to the &lt;code&gt;return&lt;/code&gt; statement with an interval time in seconds. Every time that interval is reached, Next.js will call the function again and attempt to regenerate the page with any new data, and once the page has been regenerated Next will replace the old page with the new one. No loading messages, no screen jank, no extra libraries like WebSockets or long-polling or extra functions to force server-side refreshes manually - instead it&apos;s built in to Next.&lt;/p&gt;
&lt;p&gt;So to enable this revalidation of the page data on a regular interval, we&apos;ll turn back to the &lt;code&gt;index.tsx&lt;/code&gt; page once more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// imports
import { GetStaticProps } from &quot;next&quot;;
import { fetchNotecardData } from &quot;../src/lib/notecardData&quot;;
// other imports

type dataProps = {
// condensed for code brevity
};

export default function Home({ data }: { data: dataProps[] }) {
  // map component imported dynamically here

  // logic to transform data into the items needed to pass to the map

return (
    &amp;lt;div&amp;gt;
      {/* extra tracker app code */}
      &amp;lt;main&amp;gt;
        &amp;lt;h1&amp;gt;React Blues Wireless Asset Tracker&amp;lt;/h1&amp;gt;
        {/* other tracker components */}
        &amp;lt;div&amp;gt;
          &amp;lt;MapWithNoSSR
            coords={lngLatCoords}
            lastPosition={lastPosition}
            markers={latLngMarkerPositions}
            latestTimestamp={latestTimestamp}
          /&amp;gt;
        &amp;lt;/div&amp;gt;
        {/* other tracker components */}
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export const getStaticProps: GetStaticProps = async () =&amp;gt; {
  /* we&apos;re able to use Nextjs&apos;s ISR (incremental static regneration) 
  revalidate functionality to re-fetch updated map coords and re-render one a regular interval */
  const data = await fetchNotecardData();

  return { props: { data }, revalidate: 120 };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new code is at the very bottom of the &lt;code&gt;getStaticProps&lt;/code&gt; function in this file - the line &lt;code&gt;return { props: { data }, revalidate: 120 };&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This is all that&apos;s needed so that every two minutes Next.js will go back to Notehub and fetch any new data and re-render the page server-side. It&apos;s awesome.&lt;/p&gt;
&lt;p&gt;And with that, we&apos;ve got an asset tracker map built with Next.js, and regularly checking for new data.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;After I joined an IoT startup in July of 2021, I started dipping my toes into internet of things development with an asset tracker. And once I had GPS data being sent regularly to a cloud, I figured out how to extract that data from the cloud and display it in a custom-built dashboard map.&lt;/p&gt;
&lt;p&gt;With the help of the React-powered Next.js framework and the React Leaflet library, I was able to do so easily, and even leverage Next&apos;s built-in incremental static regeneration to re-fetch any new data server-side and re-render the map with that fresh data. It&apos;s pretty cool.&lt;/p&gt;
&lt;p&gt;This actually came in pretty handy when my parents&apos; car was stolen from their driveway the night after Thanksgiving. If you want to hear the whole story and build your own tracker, check out this &lt;strong&gt;&lt;a href=&quot;https://blues.io/blog/gps-asset-tracker-with-blues-wireless-and-react/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;blog post and video&lt;/a&gt;&lt;/strong&gt; I made for Blues Wireless - it details the whole process from hardware to software to deploying to Netlify.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you enjoyed learning how to set up a map in Next.js and render an asset tracker&apos;s location data to that map - just think how useful this could be for keeping track of a personal vehicle or a whole fleet of them. There&apos;s a lot of cool places you could take this project from here. Happy tracking!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hackster.io/paige-niedringhaus/low-code-gps-asset-tracker-and-map-display-b10419&quot;&gt;Hackster.io original asset tracker project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/react-gps-asset-tracker-dashboard&quot;&gt;Asset tracker GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leafletjs.com/&quot;&gt;Leaflet documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-leaflet.js.org/&quot;&gt;React Leaflet documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Blues Wireless &lt;a href=&quot;https://dev.blues.io/?&amp;amp;utm_source=paigeniedringhaus.com&amp;amp;utm_medium=web&amp;amp;utm_campaign=niedringhaus-effect&amp;amp;utm_content=ep-2&quot;&gt;developer experience site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Next.js &lt;a href=&quot;https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration&quot;&gt;incremental static regeneration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>nextjs</category><category>typescript</category><category>blues</category><category>maps</category><category>iot</category></item><item><title>Build a Gatsby Blog Post Filter</title><link>https://www.paigeniedringhaus.com/blog/build-a-gatsby-blog-post-filter/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/build-a-gatsby-blog-post-filter/</guid><description>Even with multiple data sources and things to filter by, it can be done.</description><pubDate>Thu, 16 Dec 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/gatsby-blog-post-filter/blog-filter.png&quot; alt=&quot;Blog filter input on author&apos;s personal site&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Earlier this year, I built &lt;strong&gt;&lt;a href=&quot;/&quot;&gt;my own website&lt;/a&gt;&lt;/strong&gt; using Gatsby to serve as a centralized place to showcase my work, &lt;strong&gt;&lt;a href=&quot;/media&quot;&gt;my talks&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href=&quot;/blog&quot;&gt;my blog articles&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;/courses&quot;&gt;courses&lt;/a&gt;&lt;/strong&gt;, and let people &lt;strong&gt;&lt;a href=&quot;/about&quot;&gt;get to know me&lt;/a&gt;&lt;/strong&gt; a little better.&lt;/p&gt;
&lt;p&gt;Since I&apos;ve been writing regularly for almost 4 years now, there&apos;s a lot of blog articles to sort through on the site, so one thing I wanted to do was make a filter on the blog page to let readers narrow down what they were interested in. There&apos;s a catch to this filter though, and it&apos;s twofold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I wanted to give readers multiple parts of a blog they could search by: blog titles, blog subtitles, and blog tags.&lt;/li&gt;
&lt;li&gt;Not all of my blog posts live on my site: many are hosted on other platforms like &lt;a href=&quot;https://paigen11.medium.com/&quot;&gt;Medium&lt;/a&gt;, &lt;a href=&quot;https://www.hackster.io/paige-niedringhaus&quot;&gt;Hackster.io&lt;/a&gt;, etc. so I couldn&apos;t rely solely on Gatsby&apos;s GraphQL queries during page generation to grab all the post data needed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It makes for a tricky situation, but certainly not an insurmountable one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this post, I&apos;ll show you how to build a blog filter in Gatsby that accesses data from multiple sources and filters them by multiple parameters.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s what the finished product looks like:&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/watch?v=rjYVvBNsJVM&quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;First things first, get all the post data in one place&lt;/h2&gt;
&lt;p&gt;Before we can start filtering down the blog posts we must gather together all the data from their different sources.&lt;/p&gt;
&lt;p&gt;If we were using just Gatsby to host blog content in the form of local Markdown files or a headless CMS integration, it would be possible to use Gatsby&apos;s &lt;a href=&quot;https://www.gatsbyjs.com/docs/how-to/sourcing-data/sourcing-from-the-filesystem/#using-gatsby-source-filesystem&quot;&gt;&lt;code&gt;gatsby-source-filesystem&lt;/code&gt;&lt;/a&gt; or the &lt;strong&gt;&lt;a href=&quot;https://www.gatsbyjs.com/docs/how-to/sourcing-data/headless-cms/&quot;&gt;Gatsby CMS integration guide of your choice&lt;/a&gt;&lt;/strong&gt; to pull in all the data in one fell swoop, but what about blogs that aren&apos;t accessible this way?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Before I built this site, I posted almost all of my tech blogs on Medium. I&apos;m in the process of moving them all here, but it&apos;s a lot of content and the going is slow.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well here&apos;s my low-tech, interim solution: a simple JavaScript list.&lt;/p&gt;
&lt;h3&gt;Make a file for the blogs not hosted on our Gatsby site&lt;/h3&gt;
&lt;p&gt;Until I eventually get all of my blogs hosted in one place (this website), I came up with an easy, workable solution - there&apos;s not even any GraphQL queries required. My solution was creating a new JavaScript file named &lt;code&gt;mediumBlogs.js&lt;/code&gt;. And all the file is, is a list of all my blogs on third-party sites.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example of a few of the posts and the properties I include for each blog post.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;mediumBlogs.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import moment from &apos;moment&apos;;
import googleJib from &apos;../content/images/google-jib.png&apos;;
import sequelize from &apos;../content/images/sequelize.png&apos;;

export default [
  {
    date: moment(&apos;2018-07-18&apos;).format(&apos;ll&apos;),
    img: googleJib,
    url:
      &apos;https://itnext.io/jib-getting-expert-docker-results-without-any-knowledge-of-docker-ef5cba294e05&apos;,
    subTitle: &apos;All of the containerization benefits, none of the complexity.&apos;,
    tags: [&apos;docker&apos;, &apos;devops&apos;, &apos;java &apos;, &apos;jib&apos;],
    timeToRead: 4,
    title: &apos;Jib: Getting Expert Docker Results Without Any Knowledge of Docker&apos;,
  },
  {
    date: moment(&apos;2018-08-04&apos;).format(&apos;ll&apos;),
    img: sequelize,
    url:
      &apos;https://medium.com/@paigen11/sequelize-the-orm-for-sql-databases-with-nodejs-daa7c6d5aca3&apos;,
    subTitle: &apos;The ORM For SQL Databases with Node.js&apos;,
    tags: [&apos;javascript&apos;, &apos;nodejs&apos;, &apos;sql&apos;, &apos;express&apos;],
    timeToRead: 8,
    title: &apos;Sequelize: Like Mongoose But For SQL&apos;,
  },
  // more blogs following the same format here
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately there was no Medium API to pull in this sort of data programmatically, so I made up my own properties of info I wanted to include - things like date, original URL, title and subtitle, tags, a thumbnail image - you get the idea, and manually put the file together.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I may have been able to figure out a more automated way to scrape this data from Medium, but it probably would have taken me just as long to come up with a working script as it did to type up this file with links to all my posts. I wasn&apos;t in a massive rush so I would just add 5 posts at a time as I was working on building the site in my spare time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The nice thing about doing it this way is that I was able to create my custom list of blog posts with exactly the data I wanted in the shape I needed - a shape that can be closely mimicked in my GraphQL queries to fetch locally hosted blog data, which I&apos;ll cover in the next sections.&lt;/p&gt;
&lt;p&gt;To use this file anywhere in the Gatsby blog, it just needs to be imported into the component that needs it.&lt;/p&gt;
&lt;p&gt;My list of blogs live in the &lt;code&gt;PostListing&lt;/code&gt; component, so to get the Medium blog list it&apos;s as simple as importing anything else into a JS file:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PostListing.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// other file imports above here
import mediumBlogs from &apos;../../../data/mediumBlogs&apos;;
// other file imports below here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the third-party post data handled, it&apos;s time to move on to the local data in Markdown files on the site.&lt;/p&gt;
&lt;h3&gt;Create a GraphQL &lt;code&gt;useStaticQuery&lt;/code&gt; Hook to grab all the local data&lt;/h3&gt;
&lt;p&gt;After making a list of all the additional blog posts not accessible by the Gatsby site, we also need to grab the data that Gatsby is responsible for. Since I choose to host my blogs in Markdown files that are stored in a &lt;strong&gt;&lt;a href=&quot;https://blog.bitsrc.io/how-to-utilize-submodules-within-git-repos-5dfdd1c62d09&quot;&gt;private repo on GitHub&lt;/a&gt;&lt;/strong&gt;, this data can be accessed with a combination of the &lt;a href=&quot;https://www.gatsbyjs.com/plugins/gatsby-source-filesystem/&quot;&gt;&lt;code&gt;gatsby-source-filesystem&lt;/code&gt;&lt;/a&gt; in the &lt;code&gt;gatsby-config.js&lt;/code&gt; file, and a custom Hook on the frontend to query the data.&lt;/p&gt;
&lt;p&gt;Using the &lt;code&gt;gatsby-source-filesystem&lt;/code&gt; to generate content from source data like Markdown files is fairly straightforward following the &lt;a href=&quot;https://www.gatsbyjs.com/docs/how-to/sourcing-data/sourcing-from-the-filesystem/&quot;&gt;documentation on the Gatsby site&lt;/a&gt;: just point the filesystem plugin towards your directory folder where all the files live and it takes care of the rest.&lt;/p&gt;
&lt;p&gt;On the client side, my version of Gatsby (v2.1 and above) supports GraphQL &lt;a href=&quot;https://www.gatsbyjs.com/docs/how-to/querying-data/use-static-query/&quot;&gt;&lt;code&gt;useStaticQuery&lt;/code&gt; Hooks&lt;/a&gt; that can run at build time. The special thing about these queries is that they don&apos;t need to be at the page level &lt;em&gt;and&lt;/em&gt; they can be written as reusable custom Hooks not attached to a particular page or component.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are a few &lt;a href=&quot;https://www.gatsbyjs.com/docs/how-to/querying-data/use-static-query/#known-limitations&quot;&gt;limitations&lt;/a&gt; to &lt;code&gt;useStaticQuery&lt;/code&gt; that makes it slightly less flexible than original, page-level queries, but it will work just fine for our purposes today.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to know more about this Hook, I wrote about it in-depth &lt;strong&gt;&lt;a href=&quot;https://blog.bitsrc.io/gatsby-fetching-data-at-the-component-level-with-usestaticquery-397e35e648e&quot;&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since the front matter in my local Markdown post files looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: &quot;Docker 102: Docker-Compose&quot;
subTitle: &apos;The recipe card for getting all your Dockerized apps to work together seamlessly.&apos;
thumbnail: ../images/docker-2.png 
featuredImage: ../images/docker-2.png
category: &quot;devops&quot;
date: &quot;2018-07-07&quot;
ogLink: &apos;https://itnext.io/docker-102-docker-compose-6bec46f18a0e&apos;
publication: ITNEXT
tags:
    - docker
    - devops
omit: false
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The custom &lt;code&gt;useStaticQuery&lt;/code&gt; Hook to fetch and parse this data can look something like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;usePostListingQuery.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useStaticQuery, graphql } from &apos;gatsby&apos;;

export const usePostListingQuery = () =&amp;gt; {
  const postListData = useStaticQuery(graphql`
    query PostQuery {
      allMarkdownRemark(
        filter: { frontmatter: { omit: { eq: false } } }
        sort: { fields: [fields___date], order: DESC }
      ) {
        edges {
          node {
            fields {
              slug
              date(formatString: &quot;MMM D, YYYY&quot;)
            }
            timeToRead
            frontmatter {
              omit
              title
              subTitle
              tags
              date
              thumbnail {
                childImageSharp {
                  fixed(width: 200) {
                    ...GatsbyImageSharpFixed
                  }
                }
              }
            }
          }
        }
      }
    }
  `);
  return postListData;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This query fetches all the same data from the Markdown files&apos; front matter as the data properties included in the custom list of third-party blog posts we made.&lt;/p&gt;
&lt;p&gt;With this reusable custom Hook at our disposal, it can be imported into the &lt;code&gt;PostListing&lt;/code&gt; component to fetch all the data about our local blog posts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PostListing.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// other imports above
import { usePostListingQuery } from &apos;../../Hooks/usePostListingQuery&apos;;
// other imports below

const PostListing = () =&amp;gt; {
  const localSitePosts = usePostListingQuery();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Combine the data into one list&lt;/h3&gt;
&lt;p&gt;Now that the &lt;code&gt;PostListing&lt;/code&gt; component&apos;s getting data from both our data sources, it&apos;s time to put them together in the right order. Still in the &lt;code&gt;PostListing&lt;/code&gt; component, we can declare a &lt;code&gt;useState&lt;/code&gt; Hook called &lt;code&gt;fullPostList&lt;/code&gt;, which is what will be rendered in the component&apos;s JSX. And inside of a &lt;code&gt;useEffect&lt;/code&gt; Hook, which will run on component load, we&apos;ll call a function named &lt;code&gt;getAndFormatAllPosts()&lt;/code&gt; which will combine the &lt;code&gt;localSitePosts&lt;/code&gt; queried via GraphQL from the Markdown files and the &lt;code&gt;mediumBlogs&lt;/code&gt; list from the &lt;code&gt;mediumBlogs.js&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PostListing.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const [fullPostList, setFullPostList] = useState([]);

  // get all Markdown post date with this custom Hook
  const localSitePosts = usePostListingQuery();

  const getAndFormatAllPosts = (posts) =&amp;gt; {
    const postList = posts.allMarkdownRemark.edges.map((postEdge) =&amp;gt; {
      return {
        path: postEdge.node.fields.slug,
        tags: postEdge.node.frontmatter.tags,
        thumbnail: postEdge.node.frontmatter.thumbnail.childImageSharp.fixed,
        title: postEdge.node.frontmatter.title,
        subTitle: postEdge.node.frontmatter.subTitle,
        date: postEdge.node.fields.date,
        timeToRead: postEdge.node.timeToRead,
      };
    });
    // access the Medium blog list imported into the component
    const fullPostList = postList.concat(mediumBlogs);
    // sort the combined posts by date
    const sortedPostsList = sortArrayByDate(fullPostList); 
    // set the full array of posts into component state
    setFullPostList(sortedPostsList);
  };

  useEffect(() =&amp;gt; {
    // combine and format all the blog posts on component load
    getAndFormatAllPosts(localSitePosts);
  }, []);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, &lt;code&gt;getAndFormatAllPosts()&lt;/code&gt; loops through all the Markdown posts fetched by the &lt;code&gt;usePostListingQuery()&lt;/code&gt; Hook and creates a list of objects with properties to match the &lt;code&gt;mediumBlogs&lt;/code&gt;&apos; object properties.&lt;/p&gt;
&lt;p&gt;Then, once all the &lt;code&gt;localSitePosts&lt;/code&gt; are formatted, the &lt;code&gt;mediumBlogs&lt;/code&gt; list is combined with them, and everything is sorted by date (that&apos;s the &lt;code&gt;sortArrayByDate()&lt;/code&gt; helper function), and this full list is set in our local state Hook &lt;code&gt;fullPostList&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Whew! Quite a lot happened here, but now we have a single list of objects with the same properties, time to filter them down.&lt;/p&gt;
&lt;h2&gt;Set up an input filter above the blog posts&lt;/h2&gt;
&lt;p&gt;Ok, there&apos;s our whole list of blogs, sorted and rendered in our &lt;code&gt;PostListing&lt;/code&gt; component&apos;s JSX. The next step is adding an input at the top of the component that a user can type into.&lt;/p&gt;
&lt;p&gt;If you&apos;re familiar with React and inputs, you know that the only way to register keystrokes in an input is with an &lt;code&gt;onChange()&lt;/code&gt; function that takes in events from the DOM, and then updates the component&apos;s state based on those events. For our purposes, we need the component to use whatever&apos;s in the input and narrow down the blog posts visible based on their &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;subTitle&lt;/code&gt; and &lt;code&gt;tag&lt;/code&gt; properties.&lt;/p&gt;
&lt;h3&gt;Add variables for the query values&lt;/h3&gt;
&lt;p&gt;To help us know when to show the full list of posts versus a narrowed down list based on if the input is empty or not, we need to add a couple of new variables to our component. One is a constant named &lt;code&gt;emptyQuery&lt;/code&gt; to set the input&apos;s value to an empty string when the component first loads, and the second is a new &lt;code&gt;useState&lt;/code&gt; Hook that starts out as an object with an empty &lt;code&gt;filteredPostList&lt;/code&gt; array and a &lt;code&gt;query&lt;/code&gt; property that defaults to the value of &lt;code&gt;emptyQuery&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PostListing.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const emptyQuery = &apos;&apos;;
  const [state, setState] = useState({
    filteredPostList: [],
    query: emptyQuery
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a &lt;code&gt;filterPosts()&lt;/code&gt; function&lt;/h3&gt;
&lt;p&gt;Our new variables enable us to write an &lt;code&gt;onChange()&lt;/code&gt; function for the input that will let us narrow down the results and return them to the component to display.&lt;/p&gt;
&lt;p&gt;We&apos;re going to name this function &lt;code&gt;filterPosts()&lt;/code&gt;, and every time a new keystroke (event) is added to the input this function will run. It will start by setting the current &lt;code&gt;event.target.value&lt;/code&gt; from the DOM equal to a variable locally scoped to the function named &lt;code&gt;query&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, we&apos;ll take the &lt;code&gt;fullPostList&lt;/code&gt; state and filter through all the posts looking to see which &lt;code&gt;post.title&lt;/code&gt;, &lt;code&gt;post.subTitles&lt;/code&gt; and &lt;code&gt;post.tags&lt;/code&gt; match the &lt;code&gt;query&lt;/code&gt;. Don&apos;t forget to use something like &lt;code&gt;toLowerCase()&lt;/code&gt; to ensure case sensitivity doesn&apos;t accidentally disqualify a post from making the list.&lt;/p&gt;
&lt;p&gt;Once the local &lt;code&gt;query&lt;/code&gt; variable and new &lt;code&gt;filteredPostList&lt;/code&gt; array have been created in the &lt;code&gt;filterPosts()&lt;/code&gt; function, the component&apos;s &lt;code&gt;state&lt;/code&gt; object is set with the new values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PostListing.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const filterPosts = (event) =&amp;gt; {
    const query = event.target.value;
    const filteredPostList = fullPostList.filter((post) =&amp;gt; {
      return (
        post.title.toLowerCase().includes(query.toLowerCase()) ||
        (post.subTitle &amp;amp;&amp;amp;
          post.subTitle.toLowerCase().includes(query.toLowerCase())) ||
        (post.tags &amp;amp;&amp;amp;
          post.tags.join(&apos;&apos;).toLowerCase().includes(query.toLowerCase()))
      );
    });

    // set the component&apos;s state with our newly generated query and list variables
    setState({
      query,
      filteredPostList
    });
  };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function&apos;s not so complicated, right? In reality we just have to check multiple properties in each &lt;code&gt;post&lt;/code&gt; object in the array to see if our &lt;code&gt;query&lt;/code&gt; exists in any of them. The &lt;code&gt;post.tags&lt;/code&gt; is a little tricky because it&apos;s an array of strings instead of a single string, but simply using &lt;code&gt;join(&apos;&apos;)&lt;/code&gt; on the tags before checking to see if the &lt;code&gt;query&lt;/code&gt; is included takes care of this too.&lt;/p&gt;
&lt;h3&gt;Render the newly filtered list&lt;/h3&gt;
&lt;p&gt;The final step is to take our new &lt;code&gt;filteredPostList&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt; pieces of state, determine if the &lt;code&gt;query&lt;/code&gt; is not an empty array (which would mean the search input is empty), and based on that render either the &lt;code&gt;fullPostList&lt;/code&gt; or &lt;code&gt;filteredPostList&lt;/code&gt; in the component.&lt;/p&gt;
&lt;p&gt;To do this part, we can create a new boolean called &lt;code&gt;hasSearchResults&lt;/code&gt; that will simply indicate if the &lt;code&gt;filteredPostList&lt;/code&gt; exists and the &lt;code&gt;query&lt;/code&gt; is not an empty string, and based on this boolean, we&apos;ll use another local variable called &lt;code&gt;posts&lt;/code&gt; that will tell the component which list to use.&lt;/p&gt;
&lt;p&gt;This is how we&apos;ll use just one local variable, &lt;code&gt;posts&lt;/code&gt;, to render our list of blog posts, regardless of which state variable is actually being rendered by the JSX (&lt;code&gt;fullPostList&lt;/code&gt; or &lt;code&gt;filteredPostList&lt;/code&gt;). Check out this code snippet to see what I mean.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PostListing.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const { filteredPostList, query } = state;
  const hasSearchResults = filteredPostList &amp;amp;&amp;amp; query !== emptyQuery;
  const posts = hasSearchResults ? filteredPostList : fullPostList;

 return (
    &amp;lt;&amp;gt;
      {!posts.length &amp;amp;&amp;amp; query === emptyQuery &amp;amp;&amp;amp; (
        &amp;lt;span className=&quot;post-wrapper&quot;&amp;gt;
        &amp;lt;span className=&quot;post-search-wrapper page-body&quot;&amp;gt;
            &amp;lt;input
              className=&quot;searchInput&quot;
              type=&quot;search&quot;
              aria-label=&quot;Search&quot;
              placeholder=&quot;Filter blog posts by title or tag&quot;
              onChange={(e) =&amp;gt; filterPosts(e)}
            &amp;gt;&amp;lt;/input&amp;gt;
          &amp;lt;/span&amp;gt;
          &amp;lt;div className=&quot;posts-wrapper wide-page-body&quot;&amp;gt;
            {posts.length ? (
              posts.map((post, index) =&amp;gt; (
                {/* more JSX code to render posts */}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty cool, huh?&lt;/p&gt;
&lt;h2&gt;Handle no results&lt;/h2&gt;
&lt;p&gt;There&apos;s one last scenario left to handle: if the search term in the input doesn&apos;t match any of the values in the blog posts. Luckily, that&apos;s fairly straightforward to deal with as well.&lt;/p&gt;
&lt;p&gt;For this situation, we can let the JSX do the heavy lifting - no extra state variables required. When the possibility occurs that whatever input string a user has searched for doesn&apos;t exist in any of the posts being filtered through, we need to show no posts and let the user know nothing matches their search params.&lt;/p&gt;
&lt;p&gt;The simplest way to do this in the JSX is by checking the &lt;code&gt;posts.length&lt;/code&gt;, which we already do in order to map over all the blog posts and display them on the page. We&apos;ll take this statement&apos;s ternary and change it from rendering &lt;code&gt;null&lt;/code&gt; if &lt;code&gt;posts.length&lt;/code&gt; does not exist and make it render a message for the user instead.&lt;/p&gt;
&lt;p&gt;Here&apos;s what the whole component&apos;s JSX looks like (slightly condensed for brevity): as long as the blog posts have loaded but the amount of ones filtered according to the user input is 0, the message displayed to the user says &quot;Sorry, no search results match your query.&quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PostListing.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return (
  &amp;lt;&amp;gt;
    {!posts.length &amp;amp;&amp;amp; query === emptyQuery &amp;amp;&amp;amp; (
      &amp;lt;span className=&quot;post-wrapper&quot;&amp;gt;
        &amp;lt;span className=&quot;post-search-wrapper page-body&quot;&amp;gt;
          &amp;lt;input
            className=&quot;searchInput&quot;
            type=&quot;search&quot;
            aria-label=&quot;Search&quot;
            placeholder=&quot;Filter blog posts by title or tag&quot;
            onChange={(e) =&amp;gt; filterPosts(e)}
          &amp;gt;&amp;lt;/input&amp;gt;
        &amp;lt;/span&amp;gt;
        &amp;lt;div className=&quot;posts-wrapper wide-page-body&quot;&amp;gt;
          {posts.length ? (
            posts.map((post, index) =&amp;gt; (
              &amp;lt;article className=&quot;post&quot; key={index}&amp;gt;
                &amp;lt;p className=&quot;post-date&quot;&amp;gt;
                  {post.date}&amp;amp;nbsp;
                  {&apos;\u2022&apos;} 
                  {post.timeToRead} min read
                &amp;lt;/p&amp;gt;
                &amp;lt;Link to={`/blog${post.path}`} key={post.title}&amp;gt;
                  &amp;lt;p className=&quot;post-title&quot;&amp;gt;{post.title}&amp;lt;/p&amp;gt;
                  &amp;lt;Img fixed={post.thumbnail} /&amp;gt;
                  &amp;lt;p&amp;gt;{post.subTitle}&amp;lt;/p&amp;gt;
                &amp;lt;/Link&amp;gt;
                &amp;lt;PostTags tags={post.tags} /&amp;gt;
              &amp;lt;/article&amp;gt;
            ))
          ) : (
            &amp;lt;div className=&quot;empty-results&quot;&amp;gt;
              &amp;lt;h2&amp;gt;Sorry, no search results match your query.&amp;lt;/h2&amp;gt;
            &amp;lt;/div&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
      &amp;lt;/span&amp;gt;
    &amp;lt;/&amp;gt;
  )}
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Isn&apos;t it nice how cleanly that can be handled with a ternary? I like it when React makes things easy for me.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Filtering and inputs are not the simplest thing to build when it comes to web development, and filters that check multiple properties in multiple objects for a match are even harder. But it can be done.&lt;/p&gt;
&lt;p&gt;Giving users the ability to narrow down results based on their interests (which hopefully align with article titles, subtitles, and tags) is a really nice feature to offer, and it was a fun challenge to build in Gatsby. And, surprisingly, not as complicated as I originally expected it to be.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, ES6, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you can put this custom built filter to use in your own React applications. I know I&apos;m always grateful for filter inputs like this and I think your users will be too.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/paigeniedringhaus.com&quot;&gt;GitHub repo for my personal site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>gatsby</category><category>react</category><category>graphql</category><category>javascript</category></item><item><title>Cypress Studio - the underrated feature speeding up e2e testing</title><link>https://www.paigeniedringhaus.com/blog/cypress-studio-the-underrated-feature-speeding-up-e2e-testing/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/cypress-studio-the-underrated-feature-speeding-up-e2e-testing/</guid><description>The feature dramatically cutting down the time it takes to write end-to-end tests.</description><pubDate>Thu, 21 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/dual-monitors.jpg&quot; alt=&quot;Dual monitors&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Photo by &amp;lt;a href=&quot;https://unsplash.com/@euwars&quot;&amp;gt;Farzad Nazifi&amp;lt;/a&amp;gt; on Unsplash&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Cypress.io just keeps raising the bar on end-to-end testing&lt;/h2&gt;
&lt;p&gt;When &lt;strong&gt;&lt;a href=&quot;https://www.cypress.io/&quot;&gt;Cypress.io&lt;/a&gt;&lt;/strong&gt; first hit the scene in 2015, it made a splash because it fixed so many of the issues that existed with other end-to-end testing (e2e) competitor frameworks.&lt;/p&gt;
&lt;p&gt;Between good documentation, intuitive syntax, improved debugging, and no reliance on &lt;a href=&quot;https://www.selenium.dev/&quot;&gt;Selenium&lt;/a&gt; under-the-hood - everything about Cypress was a major step forward for e2es, but it wasn&apos;t content just to stop there.&lt;/p&gt;
&lt;p&gt;The team behind Cypress regularly keeps releasing new features and functionality to make it more and more useful for devs, and make e2e testing (traditionally kind of a pain) easier and easier as well.&lt;/p&gt;
&lt;p&gt;One recent release that&apos;s currently tucked behind a feature flag is called &lt;strong&gt;&lt;a href=&quot;https://docs.cypress.io/guides/core-concepts/cypress-studio&quot;&gt;Cypress Studio&lt;/a&gt;&lt;/strong&gt;, and it&apos;s an absolute game changer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With Cypress Studio, you can &lt;em&gt;show&lt;/em&gt; Cypress exactly how to test by &lt;em&gt;recording interactions&lt;/em&gt; against the application under test. You click around in the DOM, and Cypress generates the test code to mimic what you&apos;re doing. Test written. Done.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to add Cypress to an existing JavaScript project, enable Cypress Studio, and let it help do the heavy lifting of writing end-to-end tests.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s such a cool feature to help dev teams save time on testing, deliver new features faster, and still ensure the mission critical functionality of the app continues to work as expected.&lt;/p&gt;
&lt;h2&gt;Add Cypress to a Project&lt;/h2&gt;
&lt;p&gt;Although Cypress is kind enough to provide a host of sample scripts to show many of its features in action, it really shines with a local app to test against, and I just so happen to have one that fits the bill.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If you&apos;d like to download a working version of the finished code and follow along, I have a link to the &lt;a href=&quot;https://github.com/paigen11/cypress-studio-sample-app&quot;&gt;GitHub repo here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Get an app to test&lt;/h3&gt;
&lt;p&gt;The app I&apos;m using is a React-based movie database that allows users to see upcoming movies and movies in theaters now, browse movies by genre, and search for movies by title. This will be a good app to demonstrate Cypress Studio&apos;s power.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/movie-app.png&quot; alt=&quot;Sample movie database React app&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Download Cypress to your app&lt;/h3&gt;
&lt;p&gt;Once we&apos;ve got an app to add Cypress to, the first thing we&apos;ll need to do is download Cypress to it.&lt;/p&gt;
&lt;p&gt;This is another reason Cypress stands head and shoulders above its competitors: one npm download gives you all the tools you need to start writing e2es. No dev dependencies, no extra libraries with mismatched package versions, none of that nonsense to deal with.&lt;/p&gt;
&lt;p&gt;At the root of your project, where your &lt;code&gt;package.json&lt;/code&gt; file lives, run the following command from the terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install cypress 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will add a bunch of new Cypress-based folders and files to your app, and with just a few small configuration changes we&apos;ll be ready to go.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/cypress-folder.png&quot; alt=&quot;Cypress folder structure inside of new project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;See all those new folders under &lt;code&gt;cypress/&lt;/code&gt;? That&apos;s what you should see after initial installation.&lt;/p&gt;
&lt;h3&gt;Add Cypress scripts to the &lt;code&gt;package.json&lt;/code&gt; to make it easier to run&lt;/h3&gt;
&lt;p&gt;For ease of use, I like to add npm scripts for the two main Cypress commands we&apos;ll be using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cypress open&lt;/code&gt;, which is used to open the &lt;strong&gt;&lt;a href=&quot;https://docs.cypress.io/guides/core-concepts/test-runner&quot;&gt;Cypress Test Runner&lt;/a&gt;&lt;/strong&gt; where we can watch tests run locally, debug them, and where we&apos;ll show Cypress how to test our app&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cypress run&lt;/code&gt;, which runs our e2es in &quot;headless mode&quot;, which is how they&apos;d run in a build pipeline&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In your &lt;code&gt;package.json&lt;/code&gt; file, add the following two lines in your &lt;code&gt;&quot;scripts&quot;&lt;/code&gt; section.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &quot;cy:run&quot;: &quot;cypress run&quot;,
    &quot;cy:open&quot;: &quot;cypress open&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when we need to run the tests, a simple &lt;code&gt;npm run cy:run&lt;/code&gt; or &lt;code&gt;npm run cy:open&lt;/code&gt;, straight from the command line, will do the trick.&lt;/p&gt;
&lt;h3&gt;Run Cypress&apos;s test scripts to make sure everything works&lt;/h3&gt;
&lt;p&gt;Ok, before we get to writing our own tests, let&apos;s run the pre-populated tests in Cypress to get familiar with the its Test Runner.&lt;/p&gt;
&lt;p&gt;From your command line, run the following shell command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm run cy:open
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should open the Cypress Test Runner, and from here, click the Run integration spec button in the top right hand corner to run through all the pre-made tests once.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/cypress-test-runner.png&quot; alt=&quot;Screenshot of the tests inside of the Cypress Test Runner&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE: Run &lt;code&gt;cypress open&lt;/code&gt; first&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When we run &lt;code&gt;cypress open&lt;/code&gt; for the first time, a new &lt;code&gt;cypress.json&lt;/code&gt; file is created at the root of our project. Even though it begins its life empty, this file is required for the headless version of Cypress (&lt;code&gt;cypress run&lt;/code&gt;) to work.&lt;/p&gt;
&lt;p&gt;So don&apos;t try to run Cypress in headless mode until after you&apos;ve done &lt;code&gt;cypress open&lt;/code&gt; in your project at least once. Otherwise, it will throw an error in the console.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After all the Cypress tests run and pass, we&apos;re ready to delete them and get to work on our own tests for our app.&lt;/p&gt;
&lt;h3&gt;Enable Cypress&apos;s experimental feature mode&lt;/h3&gt;
&lt;p&gt;Go ahead and clear all the files out of the Cypress folders of &lt;code&gt;fixtures/&lt;/code&gt; and &lt;code&gt;integration/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You&apos;ll probably also want to add the  folders of &lt;code&gt;cypress/screenshots/&lt;/code&gt; and &lt;code&gt;cypress/videos/&lt;/code&gt; to your &lt;code&gt;.gitignore&lt;/code&gt; file just so you don&apos;t commit those screenshots and videos that Cypress automatically takes during test runs to your GitHub repo (unless you want to, of course).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Add &lt;code&gt;baseUrl&lt;/code&gt; variable&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With that taken care of, let&apos;s set up a &lt;strong&gt;&lt;a href=&quot;https://docs.cypress.io/guides/references/configuration&quot;&gt;baseUrl&lt;/a&gt;&lt;/strong&gt; in our &lt;code&gt;cypress.json&lt;/code&gt; file and enable Cypress Studio there too.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Setting this &lt;code&gt;baseUrl&lt;/code&gt; variable just means we won&apos;t have to type &lt;code&gt;cy.visit(&apos;http://localhost:3000/&apos;);&lt;/code&gt; in every test. Instead, we&apos;ll be able to just write &lt;code&gt;cy.visit(&apos;/&apos;);&lt;/code&gt; and save ourselves some code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Turn on experimentalStudio&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To enable Cypress studio, just add &lt;strong&gt;&lt;a href=&quot;https://docs.cypress.io/guides/core-concepts/cypress-studio&quot;&gt;&quot;experimentalStudio&quot;: true&lt;/a&gt;&lt;/strong&gt; to our &lt;code&gt;cypress.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;So here&apos;s what the &lt;code&gt;cypress.json&lt;/code&gt; file will end up with.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
 &quot;baseUrl&quot;:&quot;http://localhost:3000&quot;, 
 &quot;experimentalStudio&quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can write our first test file and test.&lt;/p&gt;
&lt;h3&gt;Create a new test file&lt;/h3&gt;
&lt;p&gt;Inside of the &lt;code&gt;cypress/integration/&lt;/code&gt; folder in your project, create a new test file named &lt;code&gt;movie-search-spec.js&lt;/code&gt;. This folder is where Cypress will look for all your e2e test files when it runs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/cypress-new-test-file.png&quot; alt=&quot;New test file in Cypress integration folder&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Give it a placeholder test: we have to tell Cypress where we want it to record the test steps we&apos;re going to show it.&lt;/p&gt;
&lt;p&gt;So just create a typical &lt;code&gt;describe&lt;/code&gt; test block and inside of that, create an &lt;code&gt;it&lt;/code&gt; test.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cypress accepts all the traditional testing syntaxes familiar to those who&apos;ve used Jasmine, Chai, Mocha and Testing Library testing frameworks before. Whether you prefer &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;it&lt;/code&gt;, or &lt;code&gt;test&lt;/code&gt; - they&apos;re all good.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A good first test would be to test that a user can navigate to the movie search option, search for a particular movie name, and click into the results based on that search.&lt;/p&gt;
&lt;p&gt;Here&apos;s what my empty testing placeholder looks like in the &lt;code&gt;movie-search-spec.js&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;describe(&apos;Movie app&apos;, () =&amp;gt; {
  it(&apos;should show all results for movies that contain &quot;Star Wars&quot; in their titles&apos;, () =&amp;gt; {
    
  })
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think we&apos;re about ready to go.&lt;/p&gt;
&lt;h3&gt;Start the app &amp;amp; show Cypress how to test&lt;/h3&gt;
&lt;p&gt;One thing you must do before starting up Cypress to run tests against your local app is to start the app locally.&lt;/p&gt;
&lt;p&gt;For Cypress, it&apos;s an &lt;a href=&quot;https://docs.cypress.io/guides/getting-started/testing-your-app#Step-1-Start-your-server&quot;&gt;anti-pattern&lt;/a&gt; to start the app from a test, so just fire it up in a separate terminal, then open up the Cypress Test Runner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Start the movie app&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In one terminal run our movie app:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm run start 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Start the Cypress Test Runner&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And in a second terminal, open the Cypress Test Runner:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm run cy:open 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;In Cypress, Add Commands to Test&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When the Cypress Test Runner is open, enter our test file and click the tiny blue magic wand that says &lt;strong&gt;Add Commands to Test&lt;/strong&gt; when you hover over it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/cypress-add-tests.png&quot; alt=&quot;Click the blue magic wand to enable Cypress Studio mode&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And from here, go for it - test the app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/cypress-test-app.png&quot; alt=&quot;Test the app in the Cypress Test Runner browser and it will record your actions&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Go to town&lt;/h3&gt;
&lt;p&gt;For me, I clicked the Movie Search link in the nav bar, typed &quot;Star Wars&quot; into the search box, clicked into one of the results, etc.&lt;/p&gt;
&lt;p&gt;When you&apos;re satisfied with what your test is doing, click the &lt;strong&gt;Save Commands&lt;/strong&gt; button at the bottom of the test, and Cypress will run back through all the commands it&apos;s just recorded from your actions.&lt;/p&gt;
&lt;p&gt;Tell me that&apos;s not cool.&lt;/p&gt;
&lt;h3&gt;Check out the test in your e2e file now&lt;/h3&gt;
&lt;p&gt;If you go back to your IDE now, you&apos;ll see all the actions Cypress recorded, along with a few comments to tell you it was Cypress generating the code and not a developer.&lt;/p&gt;
&lt;p&gt;This is what my test now looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;describe(&apos;Movie app&apos;, () =&amp;gt; {
  it(&apos;should show all results for movies that contain &quot;Star Wars&quot; in their titles&apos;, () =&amp;gt; {
    /* ==== Generated with Cypress Studio ==== */
    cy.visit(&apos;/&apos;);
    cy.get(&apos;.navbar-top-links &amp;gt; :nth-child(3) &amp;gt; a&apos;).click();
    cy.get(&apos;.search-input&apos;).clear();
    cy.get(&apos;.search-input&apos;).type(&apos;Star Wars&apos;);
    cy.get(&apos;[type=&quot;submit&quot;]&apos;).click();
    cy.get(&apos;:nth-child(2) &amp;gt; .breakpoint__medium-up &amp;gt; .movie-component &amp;gt; .movie-poster&apos;).click();
    cy.get(&apos;.movie-details-reviews &amp;gt; :nth-child(3)&apos;).click();
    cy.get(&apos;.fa&apos;).click();
    /* ==== End Cypress Studio ==== */
  })
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just wow, right?&lt;/p&gt;
&lt;h3&gt;Fill in the gaps Cypress didn&apos;t code for&lt;/h3&gt;
&lt;p&gt;Although our test is good, Cypress can&apos;t be expected to test for all the things a developer might know are important.&lt;/p&gt;
&lt;p&gt;Things like the number of movies returned from searching &quot;star wars&quot; or checking the title of the movie being clicked into and the contents inside of the movie page itself.&lt;/p&gt;
&lt;p&gt;I&apos;ll fill in some of those details myself now.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;describe(&apos;Movie app&apos;, () =&amp;gt; {
  it(&apos;should show all results for movies that contain &quot;Star Wars&quot; in their titles&apos;, () =&amp;gt; {
    /* ==== Generated with Cypress Studio ==== */
    cy.visit(&apos;/&apos;);
    cy.get(&apos;.navbar-top-links &amp;gt; :nth-child(3) &amp;gt; a&apos;).click();
    cy.get(&apos;.search-label&apos;).should(&apos;contain&apos;, &apos;Search Movie Titles Here:&apos;); // user added
    cy.get(&apos;.search-input&apos;).clear();
    cy.get(&apos;.search-input&apos;).type(&apos;Star Wars&apos;);
    cy.get(&apos;[type=&quot;submit&quot;]&apos;).click();
    cy.get(&apos;.card-component&apos;).should(&apos;have.length&apos;, 20); // user added
    cy.get(&apos;:nth-child(2) &amp;gt; .breakpoint__medium-up &amp;gt; .movie-component &amp;gt; .movie-poster&apos;).click();
    cy.get(&apos;.movie-details-info__overview&apos;).should(&apos;contain&apos;, &apos;Movie Overview&apos;); // user added
    cy.get(&apos;div&apos;).should(&apos;contain&apos;, &quot;1977-05-25&quot;) // user added
    cy.get(&apos;div&apos;).should(&apos;contain&apos;, &quot;8.2&quot;) // user added
    cy.get(&apos;.movie-details-reviews &amp;gt; :nth-child(3)&apos;).click();
    cy.get(&apos;.fa&apos;).click();
    /* ==== End Cypress Studio ==== */
  })
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you look at my code above, I added comments after the extra assertions I added - mainly small things like checking for search text, the count of movies returned, the movie info like rating and release date in this specific movie.&lt;/p&gt;
&lt;p&gt;I didn&apos;t add a ton of extra code, just a few extra lines of details. Now run the test again and check the results.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm run cy:run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../images/cypress-studio-e2e-testing/cypress-tests-passed.png&quot; alt=&quot;Terminal display of Cypress tests passing in headless mode&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And we&apos;re done! Congrats - our first Cypress Studio-assisted e2e test is written.&lt;/p&gt;
&lt;h3&gt;Rinse, Repeat&lt;/h3&gt;
&lt;p&gt;Just repeat these steps for as many end-to-end tests as you need to write and prepare to be amazed at how much time it saves you.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In modern software, testing is a critical piece of any solid enterprise application. It helps ensure our app continues to function as expected while adding new functionality, and end-to-end testing is the closest we can get to mimicking exactly how a user would use the app with automation.&lt;/p&gt;
&lt;p&gt;Cypress broke the mold of what e2e testing frameworks are capable of when it debuted back in 2015, and it&apos;s only continued to improve with time.&lt;/p&gt;
&lt;p&gt;My favorite new feature of late is the ability to &lt;em&gt;show&lt;/em&gt; Cypress how a test should act instead of writing it yourself with Cypress Studio - the time saving possibilities are immense. And more time saved means finishing features faster and getting new functionality into the hands of users quicker. Win win win.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you enjoyed this, you may be interested in checking out my course &lt;strong&gt;&lt;a href=&quot;https://www.newline.co/courses/newline-guide-to-modernizing-an-enterprise-react-app&quot;&gt;&quot;The newline Guide to Modernizing an Enterprise React App&quot;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 10 modules and 54 lessons, I cover all the things I learned while at The Home Depot, that go into building and maintaining large, mission-critical React applications - because it&apos;s so much more than just making the code work.&lt;/p&gt;
&lt;p&gt;From tooling and refactoring, to testing and design system libraries, there&apos;s a ton of material and hands-on practice here to prepare any React developer to build software that lives up to today&apos;s high standards. I hope you&apos;ll check it out.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cypress.io/&quot;&gt;Cypress.io site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.cypress.io/guides/core-concepts/cypress-studio&quot;&gt;Cypress Studio experimental feature documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/cypress-studio-sample-app&quot;&gt;Full code for sample app GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>cypress</category><category>e2e</category><category>testing</category></item><item><title>Introducing Volta - it manages your Node.js versions so you don&apos;t have to</title><link>https://www.paigeniedringhaus.com/blog/introducing-volta-it-manages-your-nodejs-versions-so-you-dont-have-to/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/introducing-volta-it-manages-your-nodejs-versions-so-you-dont-have-to/</guid><description>With Volta, the old saying of &quot;It works on my machine...&quot; will become a thing of the past.</description><pubDate>Mon, 18 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/lightning.jpg&quot; alt=&quot;Lightning bolt&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Photo by &amp;lt;a href=&quot;https://unsplash.com/@felix_mittermeier&quot;&amp;gt;Felix Mittermeier&amp;lt;/a&amp;gt; on Unsplash&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Web development&apos;s not easy&lt;/h2&gt;
&lt;p&gt;When you&apos;re working with a team of developers, especially on a team responsible for managing multiple applications, you very well might have JavaScript apps that run on different versions of Node.js.&lt;/p&gt;
&lt;p&gt;Some might use Node 10, others Node 12, some may use Yarn as their package manager, others might use npm - and keeping track of all that is really hard. Ensuring every developer on the team is developing with the correct versions all the time is even harder. But it&apos;s essential.&lt;/p&gt;
&lt;p&gt;While the consequences might be relatively minor during local development: it works on one dev&apos;s machine and throws an error on another&apos;s, this sort of lack of standardization and clarity can have devastating effects when it comes to production.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I speak from personal experience when I say this sort of thing happened to me and my development team.&lt;/p&gt;
&lt;p&gt;We built our app on local machines running Node 10, but the build pipeline defaulted to the lowest Node version it had on hand, Node 6, and the app wouldn&apos;t start up in production. We had to roll back the deployment, figure out what went wrong - it turned into a very long night. It went on to live in infamy as &quot;Dark Thursday&quot; for all who experienced it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And it could have all been avoided if we&apos;d been using a handy little tool called Volta. &lt;strong&gt;I want to introduce Volta to you today so you can avoid the stress we went through - it&apos;s simple to get started with and can prevent catastrophes like this.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;What is Volta?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://volta.sh/&quot;&gt;Volta&lt;/a&gt;&lt;/strong&gt; touts itself as &quot;a hassle-free way to manage your JavaScript command-line tools.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What this means in practice is that Volta makes managing Node, npm, yarn, or other JavaScript executables shipped as part of packages, really easy.&lt;/p&gt;
&lt;h2&gt;Why Volta?&lt;/h2&gt;
&lt;p&gt;I&apos;ve told you what Volta is, but you&apos;re probably still wondering why I chose it in particular - it&apos;s certainly not the only game in town. NVM&apos;s another well known option for managing multiple versions of Node.&lt;/p&gt;
&lt;h3&gt;NVM&lt;/h3&gt;
&lt;p&gt;I used to use &lt;strong&gt;&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;Node Version Manager (NVM)&lt;/a&gt;&lt;/strong&gt; myself. Heck, I even wrote a whole &lt;strong&gt;&lt;a href=&quot;https://itnext.io/nvm-the-easiest-way-to-switch-node-js-environments-on-your-machine-in-a-flash-17babb7d5f1b&quot;&gt;blog post&lt;/a&gt;&lt;/strong&gt; about how useful it was.&lt;/p&gt;
&lt;p&gt;NVM is good, it does exactly what it sounds like: it allows you to easily download and switch versions of Node.js on your local machine.&lt;/p&gt;
&lt;p&gt;While it does make this task simpler, NVM is not the easiest to setup initially, and, more importantly, the developer using it still has to &lt;em&gt;remember themselves&lt;/em&gt; to switch to the correct version of Node for the project they&apos;re working on.&lt;/p&gt;
&lt;h3&gt;Volta&lt;/h3&gt;
&lt;p&gt;Volta, on the other hand, is easy to install &lt;em&gt;and&lt;/em&gt; it takes the thinking part out of the equation: once Volta&apos;s set up in a project and installed on a local machine, it will &lt;em&gt;automatically&lt;/em&gt; switch to the proper versions of Node.&lt;/p&gt;
&lt;p&gt;Yes, you heard that right. Similar to package managers, Volta keeps track of which project (if any) you’re working on based on your current directory. The tools in your Volta toolchain automatically detect when you’re in a project that’s using a particular version of the tools and takes care of routing to the right version of the tools for you.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;From that point on, every time you run Node inside your project directory, Volta automatically switches to that same version of Node you chose.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not only that, but it will also let you define yarn and npm versions in a project, and if the version of Node defined in a project isn&apos;t downloaded locally, Volta will go out and download the appropriate version.&lt;/p&gt;
&lt;p&gt;But when you switch to another project, Volta will defer to any presets in that project or revert back to the default environment variables. Cool, right?&lt;/p&gt;
&lt;p&gt;Ready to see it in action?&lt;/p&gt;
&lt;h2&gt;Setup Volta in a project&lt;/h2&gt;
&lt;p&gt;For ease of getting started, let&apos;s create a brand new React application with Create React App, then we&apos;ll add Volta our local machine and our new project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If you&apos;d like to download a working version of this code, I have a &lt;a href=&quot;https://github.com/paigen11/volta-sample-app&quot;&gt;GitHub repo here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Spin up a new React app&lt;/h3&gt;
&lt;p&gt;First things first, create a new app.&lt;/p&gt;
&lt;p&gt;Run the following command from a terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npx create-react-app volta-sample-app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you&apos;ve got your new React app created, open up the code in an IDE, and start it up via the command line.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm run start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/volta-start.png&quot; alt=&quot;Starting sample React app locally&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If everything goes according to plan, you&apos;ll see the nice, rotating React logo when you open up a browser at &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/running-react.png&quot; alt=&quot;React app running locally&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve got an app, let&apos;s add Volta to it.&lt;/p&gt;
&lt;h3&gt;Download Volta locally&lt;/h3&gt;
&lt;p&gt;Installing Volta to your development machine is a piece of cake - no matter your chosen operating system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unix&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re using a Unix based system (MacOS, Linux or the Windows Subsystem for Linux  - WSL) to install Volta, it&apos;s super easy.&lt;/p&gt;
&lt;p&gt;In a terminal, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl https://get.volta.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;ve got Windows, it&apos;s almost this easy. &lt;a href=&quot;https://github.com/volta-cli/volta/releases/download/v1.0.5/volta-1.0.5-windows-x86_64.msi&quot;&gt;Download and run the Windows installer&lt;/a&gt; and follow the instructions.&lt;/p&gt;
&lt;p&gt;Once Volta&apos;s finished downloading, double check it installed successfully by running this command in your terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ volta -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hopefully, you&apos;ll see a version for Volta like my screenshot below. If you don&apos;t try quitting your terminal completely, re-opening a new terminal session and running that command again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/volta-version.png&quot; alt=&quot;Current version of Volta&quot; /&gt;The current version of Volta on my machine is now v1.0.5.&lt;/p&gt;
&lt;h3&gt;Define your environment variables&lt;/h3&gt;
&lt;p&gt;Before we add our Volta-specific Node and npm versions to our project, let&apos;s see what the default environment variables are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get a baseline reading&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a terminal at the root of your project, run the following line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ node -v &amp;amp;&amp;amp; npm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For me, my default versions of Node and npm are v14.18.1 and v6.14.15, respectively.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/current-node-npm.png&quot; alt=&quot;Default versions of Node and npm on local machine&quot; /&gt;&lt;/p&gt;
&lt;p&gt;With our baseline established, we can switch up our versions just for this project with Volta&apos;s help.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pin a node version&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We&apos;ll start with Node. Since v16 is the current version of Node, let&apos;s add that to our project.&lt;/p&gt;
&lt;p&gt;Inside of our project at the root level where our &lt;code&gt;package.json&lt;/code&gt; file lives, run the following command.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ volta pin node@16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;volta pin [JS_TOOL]@[VERSION]&lt;/code&gt; will put this particular JavaScript tool at our specified version into our app&apos;s &lt;code&gt;package.json&lt;/code&gt;. After committing this to our repo with git, any future devs using Volta to manage dependencies will be able to read this out of the repo and use the exact same version.&lt;/p&gt;
&lt;p&gt;With Volta we can be as specific or generic as want defining versions, and Volta will fill in any gaps. I specified the major Node version I wanted (16) and then Volta filled in the minor and patch versions for me. Pretty nice!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/volta-pinned-node.png&quot; alt=&quot;Newly pinned Node version via Volta&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When you&apos;ve successfully added your Node version, you&apos;ll see the following success message in your terminal: &lt;code&gt;pinned node@16.11.1 in package.json&lt;/code&gt; (or whatever version you pinned).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip: Make your pinned Node version match your build server&apos;s Node version&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Had Volta been an option at the time, my team might never have had to go through &quot;Dark Thursday&quot;.&lt;/p&gt;
&lt;p&gt;Instead, we could have pinned the same Node version used in our build pipeline and production servers to our project for local development to prevent such compatibility issues.&lt;/p&gt;
&lt;p&gt;At the very least, we could have realized ahead of time we might have a problem with production before deploying.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pin an npm version&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That was pretty straightforward, now let&apos;s tackle our npm version. Still in the root of our project in the terminal, run this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ volta pin npm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this particular instance, I didn&apos;t even specify any sort of version for npm, so Volta defaults to choosing the latest LTS release to add to our project. Convenient.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/volta-pinned-npm.png&quot; alt=&quot;Newly pinned npm version via Volta&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The current LTS version for npm is 8, so now our project&apos;s been given npm v8.1.0 as its default version.&lt;/p&gt;
&lt;h3&gt;Check your package.json&lt;/h3&gt;
&lt;p&gt;To confirm the new JavaScript environment versions are part of our project, check the app&apos;s &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Scroll down to the bottom and you should see a new property named &lt;code&gt;&quot;volta&quot;&lt;/code&gt;. Inside of the &lt;code&gt;&quot;volta&quot;&lt;/code&gt; property should be a &lt;code&gt;&quot;node&quot;: &quot;16.11.1&quot;&lt;/code&gt; and an &lt;code&gt;&quot;npm&quot;: &quot;8.1.0&quot;&lt;/code&gt; version.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/volta-packagejson.png&quot; alt=&quot;Newly updated package.json with Volta Node and npm versions&quot; /&gt;&lt;/p&gt;
&lt;p&gt;From now on, any dev who has Volta installed on their machine and pulls down this repo will have their settings for these tools automatically switch to use these particular node and npm versions.&lt;/p&gt;
&lt;p&gt;To make doubly sure, you can also re-run the first command we did before pinning our versions with Volta to see what our current development environment is now set to.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ node -v &amp;amp;&amp;amp; npm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this, your terminal should tell you it&apos;s using those same versions: Node.js v16 and npm v8.&lt;/p&gt;
&lt;h2&gt;Watch the magic happen&lt;/h2&gt;
&lt;p&gt;Now, you can sit back and let Volta handle things for you. Just like that. 😎&lt;/p&gt;
&lt;p&gt;If you want to see what happens when there&apos;s nothing specified for Volta (like when you&apos;re just navigating between repos or using your terminal for shell scripts), try navigating up a level from your project&apos;s root and checking your Node and npm versions again.&lt;/p&gt;
&lt;p&gt;In the screenshot below, I opened two terminals side by side: the one of the left is inside of my project with Volta versions, the one on the right is a level higher in my folder structure.&lt;/p&gt;
&lt;p&gt;I ran the following command in both:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ node -v &amp;amp;&amp;amp; npm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in my project, Node v16 and npm v8 are running, but outside of the project, Node v14 and npm v6 are present. I did nothing but switch directories and Volta took care of the rest.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/volta-to-manage-nodejs/volta-no-volta.png&quot; alt=&quot;Volta using preset`s when specified and not when not specified&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Try and tell me this isn&apos;t cool and useful. I dare you. 😉&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building solid, stable apps is tough enough without having to also keep track of which versions of Node, yarn and npm each app runs best with. By using a tool like Volta, we can take the guesswork out of our JavaScript environment variables, and actually make it &lt;em&gt;harder&lt;/em&gt; for a member of the dev team to use the wrong versions than the right ones.&lt;/p&gt;
&lt;p&gt;And remember to double check your local Node version matches your production server&apos;s Node version, too.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you enjoyed this, you may be interested in checking out my course &lt;strong&gt;&lt;a href=&quot;https://www.newline.co/courses/newline-guide-to-modernizing-an-enterprise-react-app&quot;&gt;&quot;The newline Guide to Modernizing an Enterprise React App&quot;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 10 modules and 54 lessons, I cover all the things I learned while at The Home Depot, that go into building and maintaining large, mission-critical React applications - because it&apos;s so much more than just making the code work.&lt;/p&gt;
&lt;p&gt;From tooling and refactoring, to testing and design system libraries, there&apos;s a ton of material and hands-on practice here to prepare any React developer to build software that lives up to today&apos;s high standards. I hope you&apos;ll check it out.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://volta.sh/&quot;&gt;Volta documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;NVM GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/volta-sample-app&quot;&gt;Full code for sample app GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>react</category><category>nvm</category><category>volta</category></item><item><title>Animating React with React Transition Group</title><link>https://www.paigeniedringhaus.com/blog/animating-react-with-react-transition-group/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/animating-react-with-react-transition-group/</guid><description>Another handy React animation library to have in your tool belt.</description><pubDate>Tue, 14 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import YouTube from &apos;../../src/components/YouTube.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-transition-group/hero.jpeg&quot; alt=&quot;Colorful abstract wallpaper&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A few months ago, I gave a talk with a coworker at the tech conference &lt;a href=&quot;https://connect.tech/&quot;&gt;Connect.Tech&lt;/a&gt; about the ever-growing need for responsive web design when building websites and applications. During the presentation, we discussed a few different ways to approach it, specifically when it comes to the JavaScript framework &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I won&apos;t go into all the details in our talk of how to approach responsive design (if you&apos;d like, you can see the full &lt;a href=&quot;https://t.co/WFHmJsDZ4d?amp=1&quot;&gt;slide deck of the talk&lt;/a&gt; here), I did want to share a handy React animation library I stumbled across while building the mobile-responsive demo application, called &lt;a href=&quot;https://reactcommunity.org/react-transition-group/&quot;&gt;React Transition Group&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll cover what React Transition Group is, the different component options it provides, and how I used it to animate a mobile navbar in a demo application.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;React Transition Group&lt;/h2&gt;
&lt;h3&gt;What makes it different?&lt;/h3&gt;
&lt;p&gt;Unlike other React animation libraries like &lt;a href=&quot;http://react-spring.io&quot;&gt;React Spring&lt;/a&gt; or &lt;a href=&quot;https://www.react-reveal.com/&quot;&gt;React Reveal&lt;/a&gt;, React Transition Group &quot;exposes simple components useful for defining entering and exiting transitions...it does not animate styles by itself. Instead it exposes transition stages, manages classes and group elements and manipulates the DOM in useful ways, making the implementation of actual visual transitions much easier.&quot;&lt;/p&gt;
&lt;p&gt;React Transition Group is a lower-level type of animation library. It doesn&apos;t care nearly as much about what type of animation you&apos;d like to do, it just makes it easier to do any sort of animation on any React component with as little hassle as it can.&lt;/p&gt;
&lt;p&gt;And it doesn&apos;t hurt to know that React Transition Group began in the original React framework (it&apos;s mentioned in the &lt;a href=&quot;https://reactjs.org/docs/animation.html&quot;&gt;docs&lt;/a&gt;) before being spun out into a new package to be maintained by the community. That&apos;s a pretty good endorsement for trying RTG, in my book.&lt;/p&gt;
&lt;p&gt;Now that you know a little more about RTG&apos;s approach to animation, let me cover a few of the different component options it gives users, and how they work.&lt;/p&gt;
&lt;h3&gt;Types of RTG Components&lt;/h3&gt;
&lt;p&gt;React Transition Group offers four different types of components for users to choose from based on their animation needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://reactcommunity.org/react-transition-group/transition&quot;&gt;Transition&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first component to cover is &lt;code&gt;Transition&lt;/code&gt;. This component lets you describe a transition from one component state to another over a span of time with a simple API. Most commonly it&apos;s used to animate the mounting and unmounting of a component, but it can also be used to describe in-place transition states as well. Personally, I tend to favor &lt;code&gt;CSSTransition&lt;/code&gt; over the straight &lt;code&gt;Transition&lt;/code&gt; component, but that&apos;s just me.&lt;/p&gt;
&lt;p&gt;The transition component tracks the &quot;enter&quot; and &quot;exit&quot; states for the component. The four main states a Transition can be in are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&apos;entering&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&apos;entered&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&apos;exiting&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&apos;exited&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The transition state is toggled on via the &lt;code&gt;in&lt;/code&gt; prop, when it&apos;s &lt;code&gt;true&lt;/code&gt; the component will begin the &lt;code&gt;entering&lt;/code&gt; stage for the duration of the transition until it&apos;s fully visible, at which point it will switch to the &lt;code&gt;entered&lt;/code&gt; stage. Upon exit, the same things will happen with &lt;code&gt;exiting&lt;/code&gt; and &lt;code&gt;exited&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A simple example of fading in a component on enter and fading it out on exit might look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Transition } from &apos;react-transition-group&apos;;

const duration = 300;

const defaultStyle = {
  transition: `opacity ${duration}ms ease-in-out`,
  opacity: 0,
};

const transitionStyles = {
  entering: { opacity: 1 },
  entered: { opacity: 1 },
  exiting: { opacity: 0 },
  exited: { opacity: 0 },
};

const Fade = ({ inProp }) =&amp;gt; (
  &amp;lt;Transition in={inProp} timeout={duration}&amp;gt;
    {(state) =&amp;gt; (
      &amp;lt;div
        style={{
          ...defaultStyle,
          ...transitionStyles[state],
        }}
      &amp;gt;
        I&apos;m a fade Transition!
      &amp;lt;/div&amp;gt;
    )}
  &amp;lt;/Transition&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, once the &lt;code&gt;inProp&lt;/code&gt; prop is &lt;code&gt;true&lt;/code&gt;, the &lt;code&gt;Transition&lt;/code&gt; component will activate and begin fading in to view courtesy of the &lt;code&gt;transitionStyles&lt;/code&gt; variable (where opacity is defined) that correspond to the various &quot;enter&quot; or &quot;exit&quot; stages I outlined earlier.&lt;/p&gt;
&lt;p&gt;It&apos;s worth noting this is a platform-agnostic base component -- if you&apos;re looking for CSS transitions (like I was for my use case), you&apos;ll probably want the &lt;code&gt;CSSTransition&lt;/code&gt; component instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://reactcommunity.org/react-transition-group/css-transition&quot;&gt;CSSTransition&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re using CSS transitions or animations, the &lt;code&gt;CSSTransition&lt;/code&gt; component is what you&apos;ll want to use; it&apos;s built upon the &lt;code&gt;Transition&lt;/code&gt; component, so it inherits all of its props.&lt;/p&gt;
&lt;p&gt;To work, &lt;code&gt;CSSTransition&lt;/code&gt; applies a pair of class names during the &lt;code&gt;appear&lt;/code&gt;, &lt;code&gt;enter&lt;/code&gt;, and &lt;code&gt;exit&lt;/code&gt; states of the transition. The first class is applied and then a second &lt;code&gt;*-active&lt;/code&gt; class in order to activate the CSS transition. After the transition, matching &lt;code&gt;*-done&lt;/code&gt; class names are applied to persist the transition state.&lt;/p&gt;
&lt;p&gt;For instance, if your &lt;code&gt;CSSTransition&lt;/code&gt; component&apos;s &lt;code&gt;classNames&lt;/code&gt; property is &lt;code&gt;sample&lt;/code&gt;, you&apos;d first see &lt;code&gt;sample-enter&lt;/code&gt;, then &lt;code&gt;sample-enter-active&lt;/code&gt;, and finally &lt;code&gt;sample-enter-done&lt;/code&gt; for the ending state when the animation is done. And when it&apos;s time to reverse the animation (such as with a modal or slider that needs to disappear or exit the screen), you&apos;d see it cycle through &lt;code&gt;sample-exit&lt;/code&gt; and &lt;code&gt;sample-exit-active&lt;/code&gt; and &lt;code&gt;sample-exit-done&lt;/code&gt; on your component&apos;s &lt;code&gt;classNames&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Here&apos;s a simplified code sample of what the JSX and accompanying CSS classes might look like for making a &lt;code&gt;div&lt;/code&gt; of text fade in or out. (I&apos;ve omitted the imports at the top of the file because they&apos;re the same named import for each type of component from RTG: &lt;code&gt;import { CSSTransition } from &apos;react-transition-group&apos;;&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;First the JavaScript code showing the &lt;code&gt;CSSTransition&lt;/code&gt; component wrapping a &lt;code&gt;div&lt;/code&gt; element to show or hide based on the state of &lt;code&gt;isVisible&lt;/code&gt;, which is toggled by the &lt;code&gt;button&lt;/code&gt; element underneath.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const FadeExample = () =&amp;gt; {
  const [isVisible, setIsVisible] = useState(false);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;CSSTransition
        in={isVisible}
        timeout={300}
        classNames=&quot;fade&quot;
        unmountOnExit
      &amp;gt;
        &amp;lt;div className=&quot;fade-text&quot;&amp;gt;I&apos;ll fade in and out&amp;lt;/div&amp;gt;
      &amp;lt;/CSSTransition&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setIsVisible(!isVisible)}&amp;gt;
        Toggle Visibility
      &amp;lt;/button&amp;gt;
    &amp;lt;/&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&apos;s the CSS classes that the &lt;code&gt;CSSTransition&lt;/code&gt; component would experience once &lt;code&gt;isVisible&lt;/code&gt; became &lt;code&gt;true&lt;/code&gt; and triggered the &lt;code&gt;in&lt;/code&gt; prop to fade the text in or out (just like with the original &lt;code&gt;Transition&lt;/code&gt; component).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.fade-enter {
  opacity: 0;
}

.fade-enter-active {
  opacity: 1;
  transition: opacity 300ms ease-in;
}

.fade-enter-done {
  opacity: 1;
}

.fade-exit {
  opacity: 1;
}

.fade-exit-active {
  opacity: 0;
  transition: opacity 300ms ease-in;
}

.fade-exit-done {
  opacity: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;*-active&lt;/code&gt; classes represent which styles you want to animate to, so it&apos;s important to add the &lt;code&gt;transition&lt;/code&gt; declaration only to them, otherwise transitions might not behave as intended. This might not be obvious when the transitions are symmetrical, i.e. when &lt;code&gt;*-enter-active&lt;/code&gt; is the same as &lt;code&gt;*-exit&lt;/code&gt;, but it becomes apparent quickly in more complex transitions.&lt;/p&gt;
&lt;p&gt;Let&apos;s move on now to React Transition Group&apos;s next option: &lt;code&gt;SwitchTransition&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://reactcommunity.org/react-transition-group/switch-transition&quot;&gt;SwitchTransition&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This component is useful if you want to control the render between state transitions, it&apos;s inspired by Vue transition modes. Based on the selected mode (&lt;code&gt;in-out&lt;/code&gt; or &lt;code&gt;out-in&lt;/code&gt;), and the child&apos;s key which is the &lt;code&gt;Transition&lt;/code&gt; or &lt;code&gt;CSSTransition&lt;/code&gt; component, the &lt;code&gt;SwitchTransition&lt;/code&gt; makes a consistent transition between them.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;out-in&lt;/code&gt; mode is selected, &lt;code&gt;SwitchTransition&lt;/code&gt; waits until the old child leaves and then inserts a new child. If the &lt;code&gt;in-out&lt;/code&gt; mode is selected, the &lt;code&gt;SwitchTransition&lt;/code&gt; inserts a new child first, waits for the new child to enter and then removes the old child.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example so you can see how the code might be structured to make two different buttons &quot;switch&quot; places in the DOM based on the current state. Once again, imports at the top of the file omitted for brevity.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const SwitchExample = () =&amp;gt; {
  const [state, setState] = useState(false);

  return (
    &amp;lt;SwitchTransition mode=&quot;out-in&quot;&amp;gt;
      &amp;lt;CSSTransition
        key={state ? &quot;Goodbye, world!&quot; : &quot;Hello, world!&quot;}
        addEndListener={(node, done) =&amp;gt;
          node.addEventListener(&quot;transitionend&quot;, done, false)
        }
        classNames=&quot;fade&quot;
      &amp;gt;
        &amp;lt;button onClick={() =&amp;gt; setState((state) =&amp;gt; !state)}&amp;gt;
          {state ? &quot;Goodbye, world!&quot; : &quot;Hello, world!&quot;}
        &amp;lt;/button&amp;gt;
      &amp;lt;/CSSTransition&amp;gt;
    &amp;lt;/SwitchTransition&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;SwitchTransition&lt;/code&gt; wraps the &lt;code&gt;CSSTransition&lt;/code&gt; component, which actually handles the logic and animating of entering a new &lt;code&gt;Button&lt;/code&gt; and exiting the existing one. The &lt;code&gt;key&lt;/code&gt; in &lt;code&gt;CSSTransition&lt;/code&gt; keeps track of state in the component, and every time the state changes (based on a button click), the &lt;code&gt;CSSTransition&lt;/code&gt; component takes action and &lt;code&gt;SwitchTransition&lt;/code&gt; handles keeping the old button visible until after the new button has appeared, which &lt;code&gt;CSSTransition&lt;/code&gt; is fading out based on its event listener.&lt;/p&gt;
&lt;p&gt;That &lt;code&gt;addEndListener&lt;/code&gt; function is crucial to animating the switch between elements, without it, the state (and components) will instantaneously flip like there&apos;s no animations at all.&lt;/p&gt;
&lt;p&gt;Here&apos;s the CSS for the &lt;code&gt;fade&lt;/code&gt; class name associated with &lt;code&gt;CSSTransition&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.fade-enter {
  opacity: 0;
}

.fade-exit {
  opacity: 1;
}

.fade-enter-active {
  opacity: 1;
  transition: opacity 200ms;
}

.fade-exit-active {
  opacity: 0;
  transition: opacity 200ms;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The CSS here is really concerned with the &lt;code&gt;CSSTransition&lt;/code&gt; component wrapped inside of &lt;code&gt;SwitchTransition&lt;/code&gt;, but I figure the more sample code you see for how to animate things in and out of the DOM, the better.&lt;/p&gt;
&lt;p&gt;It takes some trial and error to get it right, but the documentation for &lt;code&gt;SwitchTransition&lt;/code&gt; is good and I&apos;m sure you&apos;ll figure it out without much of a problem if this is the kind of animation you desire in your application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://reactcommunity.org/react-transition-group/transition-group&quot;&gt;TransitionGroup&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Last but not least is the &lt;code&gt;&amp;lt;TransitionGroup&amp;gt;&lt;/code&gt; component. This component manages a set of transition components (&lt;code&gt;&amp;lt;Transition&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;CSSTransition&amp;gt;&lt;/code&gt;) in a list. Like with the individual transition components, &lt;code&gt;&amp;lt;TransitionGroup&amp;gt;&lt;/code&gt; is a state machine for managing the mounting and unmounting of components over time.&lt;/p&gt;
&lt;p&gt;Please note that &lt;code&gt;&amp;lt;TransitionGroup&amp;gt;&lt;/code&gt; does not define any animation behavior. Exactly &lt;em&gt;how&lt;/em&gt; a list item animates is up to the individual transition component, which means you can mix and match animations across different list items, which could be handy.&lt;/p&gt;
&lt;p&gt;Unlike &lt;code&gt;SwitchTransition&lt;/code&gt; which lets you control the entering and exiting of elements in the DOM, &lt;code&gt;TransitionGroup&lt;/code&gt; will make the animations happen simultaneously (i.e., to remove the old child and insert a new child at the same time).&lt;/p&gt;
&lt;p&gt;Take a look at this example of a simple chore list that can have chores removed from it once they&apos;re completed. First, the JSX code with no imports in the example.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const ChoreList = () =&amp;gt; {
  const [chores, setChores] = useState([
    { id: 1, text: &quot;Do laundry&quot; },
    { id: 2, text: &quot;Wash dishes&quot; },
    { id: 3, text: &quot;Vacuum&quot; },
    { id: 4, text: &quot;Walk the dog&quot; },
  ]);

  const removeChore = (id) =&amp;gt; {
    setChores((chores) =&amp;gt; chores.filter((chore) =&amp;gt; chore.id !== id));
  };

  return (
    &amp;lt;TransitionGroup className=&quot;chore-list&quot;&amp;gt;
      {chores.map(({ id, text }) =&amp;gt; (
        &amp;lt;CSSTransition key={id} timeout={500} classNames=&quot;chore&quot;&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;span&amp;gt;{text}&amp;lt;/span&amp;gt;
            &amp;lt;button onClick={() =&amp;gt; removeChore(id)}&amp;gt;Done&amp;lt;/button&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/CSSTransition&amp;gt;
      ))}
    &amp;lt;/TransitionGroup&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, here&apos;s the CSS that will make the chores fade out of the DOM as they&apos;re removed.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.chore-enter {
  opacity: 0;
}

.chore-enter-active {
  opacity: 1;
  transition: opacity 500ms ease-in;
}

.chore-exit {
  opacity: 1;
}

.chore-exit-active {
  opacity: 0;
  transition: opacity 500ms ease-in;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that, I&apos;ve covered all the main component options React Transition Group offers. All in all, using one or more of these components together gives you fine grained control over what type of and how your React components animate in the DOM.&lt;/p&gt;
&lt;p&gt;Now, let&apos;s get down to the business of how exactly I used React Transition Group to animate my mobile navbar in my demo site.&lt;/p&gt;
&lt;h2&gt;How I used RTG in My React App&lt;/h2&gt;
&lt;p&gt;The use case I had for React Transition Group is a fairly standard one, I&apos;m sure.&lt;/p&gt;
&lt;p&gt;For my app, a movie demo site I built using the &lt;a href=&quot;https://developers.themoviedb.org/3/getting-started/introduction&quot;&gt;Movie Database API&lt;/a&gt; for a data source, when it was in mobile view, I wanted the navbar (normally across the top of the page in larger layouts) to condense down to the well-recognized hamburger menu, and require users to click it to open the list of links.&lt;/p&gt;
&lt;p&gt;What I needed was to animate a mobile-sized navbar to slide into and out of the DOM for the user, at the touch of a button. Seemed like a simple enough request.&lt;/p&gt;
&lt;p&gt;Here&apos;s a video below of what I envisioned happening.&lt;/p&gt;
&lt;p&gt;&amp;lt;YouTube url=&quot;https://www.youtube.com/embed/3m2dxmkxRlI&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;Easy enough, right? Slide a navbar in when the user clicks the hamburger icon. slide it back out when they click the icon again.&lt;/p&gt;
&lt;p&gt;The code I&apos;ll be showing you are actual snippets taken from the demo site you&apos;re seeing in the video above. If you&apos;d like to see the whole codebase for this project, it&apos;s available &lt;a href=&quot;https://github.com/paigen11/movie-demo-3&quot;&gt;on GitHub&lt;/a&gt;, and if you&apos;d like to see a live version of the site, it&apos;s available &lt;a href=&quot;https://movie-demo-3.paigen11.now.sh/&quot;&gt;on this website&lt;/a&gt; (just make your desktop browser mobile-sized to see the animated navbar).&lt;/p&gt;
&lt;h3&gt;Step 1: Add CSSTransition Group to the Sidebar.js Component&lt;/h3&gt;
&lt;p&gt;The first thing I had to do after installing React Transition Group into my project&apos;s dependencies with &lt;code&gt;npm -i react-transition-group&lt;/code&gt;, was add it to the component I wanted to animate.&lt;/p&gt;
&lt;p&gt;This component is named &lt;code&gt;Sidebar&lt;/code&gt; and its full JavaScript code looks like this.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sidebar.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { useState } from &quot;react&quot;;
import { CSSTransition } from &quot;react-transition-group&quot;;
import { Link } from &quot;react-router-dom&quot;;
import &quot;./Sidebar.scss&quot;;

const Sidebar = () =&amp;gt; {
  const [expandedLinks, setExpandedLinks] = useState(false);

  const toggleLinks = () =&amp;gt; {
    setExpandedLinks(!expandedLinks);
  };

  return (
    &amp;lt;div className=&quot;sidebar-container&quot;&amp;gt;
      &amp;lt;div className=&quot;sidebar-hamburger&quot; onClick={toggleLinks}&amp;gt;
        &amp;lt;div className=&quot;hamburger-line&quot; /&amp;gt;
        &amp;lt;div className=&quot;hamburger-line&quot; /&amp;gt;
        &amp;lt;div className=&quot;hamburger-line&quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;CSSTransition
        in={expandedLinks}
        timeout={350}
        classNames=&quot;visible&quot;
        unmountOnExit
      &amp;gt;
        &amp;lt;div className=&quot;sidebar-links&quot; onClick={toggleLinks}&amp;gt;
          &amp;lt;Link to=&quot;/&quot; className=&quot;sidebar-link&quot;&amp;gt;
            Popular
          &amp;lt;/Link&amp;gt;
          &amp;lt;Link to=&quot;/top-rated&quot; className=&quot;sidebar-link&quot;&amp;gt;
            Top Rated
          &amp;lt;/Link&amp;gt;
          &amp;lt;Link to=&quot;/now-playing&quot; className=&quot;sidebar-link&quot;&amp;gt;
            Now Playing
          &amp;lt;/Link&amp;gt;
          &amp;lt;Link to=&quot;/upcoming&quot; className=&quot;sidebar-link&quot;&amp;gt;
            Upcoming
          &amp;lt;/Link&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/CSSTransition&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Sidebar;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;ll quickly break down what goes into this component. The way that &lt;code&gt;Sidebar&lt;/code&gt; triggers the &lt;code&gt;in&lt;/code&gt; prop in the &lt;code&gt;CSSTransition&lt;/code&gt; component (which will reveal all the navigation links to other pages in the site housed within the sidebar) is with the &lt;code&gt;toggleLinks&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Once &lt;code&gt;toggleLinks&lt;/code&gt; changes the &lt;code&gt;expandedLinks&lt;/code&gt; state to &lt;code&gt;true&lt;/code&gt;, the &lt;code&gt;CSSTransition&lt;/code&gt; component runs and adds the class name modifiers ( &lt;code&gt;enter&lt;/code&gt;, &lt;code&gt;enter-active&lt;/code&gt;, &lt;code&gt;exit&lt;/code&gt;, etc.) to the &lt;code&gt;visible&lt;/code&gt; class present on the &lt;code&gt;CSSTransition&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;And all I had to do to hide the sidebar links until I&apos;m ready for them, was wrap the main &lt;code&gt;div&lt;/code&gt; surrounding all the links with the &lt;code&gt;CSSTransition&lt;/code&gt; component. Pretty straightforward, so far, right?&lt;/p&gt;
&lt;h3&gt;Step 2: Generate the CSS to Support RTG&apos;s Animation Class Names&lt;/h3&gt;
&lt;p&gt;Now for the CSS. It&apos;s long, I&apos;ll admit -- I did a lot of styling to make this navbar look just how I wanted, but try to bear with me. It&apos;s really not complicated, just verbose from styling (and this is a condensed version where I cut out some extraneous CSS not relevant to this article).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sidebar.scss&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.sidebar-container {
  display: flex;
  flex-direction: column;
  position: relative;

  .sidebar-hamburger {
    display: flex;
    flex-direction: column;
    cursor: pointer;
    padding: 10px;

    .hamburger-line {
      width: 25px;
      height: 3px;
      background-color: white;
      margin: 2px 0;
    }
  }

  .sidebar-links {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 45px;
    left: 0;
    background-color: #333;
    width: 200px;
    z-index: 100;

    .sidebar-link {
      padding: 10px 20px;
      color: white;
      text-decoration: none;
    }
  }

  .visible-enter {
    transform: translateX(-100%);
  }

  .visible-enter-active {
    transform: translateX(0);
    transition: transform 0.3s linear;
  }

  .visible-enter-done {
    transform: translateX(0);
  }

  .visible-exit {
    transform: translateX(0);
  }

  .visible-exit-active {
    transform: translateX(-100%);
    transition: transform 0.3s linear;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you wade through all this styling and focus on the &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;translate&lt;/code&gt; properties in each class I&apos;ve defined above, you&apos;ll see what is causing the animation I want. I slide the navbar in to view on &lt;code&gt;.visible-enter-active&lt;/code&gt; with &lt;code&gt;transition: transform 0.3s linear;&lt;/code&gt; and slide it back out of view with &lt;code&gt;.visible-exit-active&lt;/code&gt; and &lt;code&gt;transition: transform 0.3s linear;&lt;/code&gt;. Piece of cake!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Responsive web design is only gaining more importance as technology touches more and more of our daily lives, and smooth animations to make that technology feel more natural are essential.&lt;/p&gt;
&lt;p&gt;React Transition Group makes animations of all kinds easy by providing 4 basic components and an easy-to-use API unconcerned with the specific types of animation it&apos;s enabling. This low-level implementation gives developers fine-grain control over exactly how their app&apos;s components flow in the DOM for the best user experience they can provide. RTG is really easy to get up and running, and a pleasure to develop with.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks -- I&apos;ll be writing more about JavaScript, React, ES6, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. If you&apos;re looking to add some slick animations to your React app, I hope you&apos;ll consider React Transition Group among the myriad of libraries out there. It makes animations simple and straightforward, even down to the tiny, micro-animation details. Give it a shot -- you won&apos;t regret it.&lt;/p&gt;
&lt;h2&gt;References and Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/movie-demo-3&quot;&gt;GitHub repo&lt;/a&gt;, React app with using React Transition Group&lt;/li&gt;
&lt;li&gt;Live demo site of &lt;a href=&quot;https://movie-demo-3.paigen11.now.sh/&quot;&gt;responsive app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Responsive design featuring React.js &lt;a href=&quot;https://drive.google.com/drive/folders/1oRtHrgzpPorn9ogGpAxA5lPrH3ycCYK9&quot;&gt;presentation deck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;React Transition Group, &lt;a href=&quot;https://reactcommunity.org/react-transition-group/&quot;&gt;site documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>react</category><category>javascript</category><category>css</category></item><item><title>9 React Testing Library Tips and Tricks</title><link>https://www.paigeniedringhaus.com/blog/9-react-testing-library-tips-and-tricks/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/9-react-testing-library-tips-and-tricks/</guid><description>Writing tests is hard. These tips make it a little easier</description><pubDate>Wed, 01 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-testing-library-tips/hero.jpeg&quot; alt=&quot;Technology workspace&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;A few weeks ago, I had the good fortune to attend a two-day training course at work on improving my &lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro&quot;&gt;React Testing Library&lt;/a&gt; knowledge and skills.&lt;/p&gt;
&lt;p&gt;At my job, my team relies heavily on many forms of automated testing (unit, integration, end-to-end, etc.) to help ensure that all the pieces of our app are working correctly. So when I took the course, I already had a basic understanding of how to use React Testing Library (RTL) because we had begun using it a few months prior as we started writing more React hooks-based components in our application. Our previous unit testing combination of Jest and Enzyme had stopped meeting our needs as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This training, however, opened my eyes to some really helpful info around using RTL I was totally unaware of. I wanted to share nine of the biggest takeaways for me in hopes that they&apos;ll help you in your own use of this testing library.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;What Is React Testing Library? And Why Is It Different?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is not a &quot;Getting Started with RTL&quot; piece. This article assumes you already have a pretty good understanding of how to use the testing framework. My aim is to show you some additional tricks to make writing (and debugging) tests easier.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With that said, I will give a brief overview of the whys and hows of &lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro&quot;&gt;&lt;strong&gt;React Testing Library&lt;/strong&gt;&lt;/a&gt; before I dive into the meat of this article.&lt;/p&gt;
&lt;h3&gt;The why&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/kentcdodds/&quot;&gt;Kent C. Dodds&lt;/a&gt; created the React Testing Library to address one problem: other testing libraries encouraged developers to write tests that were too tightly coupled to the implementation details of the components they were testing. Dodds believed that the tests should only verify the end results (the behavior) of the components.&lt;/p&gt;
&lt;p&gt;It makes sense when you think about it, right?&lt;/p&gt;
&lt;p&gt;Why don&apos;t we write integration tests closer to the way we write end-to-end tests? Tests that focus on the user&apos;s perspective (how the component looks and behaves in the DOM). Because that&apos;s what ultimately matters in the end: Do the components do what they&apos;re supposed to do when a user interacts with them?&lt;/p&gt;
&lt;p&gt;We don&apos;t necessarily care if it stores something in the Redux store or makes a particular API call to fetch data. Users don&apos;t know or care about that -- they care about if the screen shows the info they clicked on or the item they ordered is being shipped to them. And as developers, RTL&apos;s stance is that we should care about that too.&lt;/p&gt;
&lt;p&gt;To that end, Dodds recommends approaching testing in the following way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Avoid dependencies on the implementation details of your components.&lt;/li&gt;
&lt;li&gt;Make testing easy to maintain (i.e. refactoring the component implementation does not break the tests).&lt;/li&gt;
&lt;li&gt;Avoid shallow mounting, as we want to test that the components integrate to solve a user problem (such as editing data in a form).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this leads me to...&lt;/p&gt;
&lt;h3&gt;The how&lt;/h3&gt;
&lt;p&gt;The React Testing Library is a very lightweight solution for testing React components. It provides light utility functions on top of &lt;code&gt;react-dom&lt;/code&gt; and &lt;code&gt;react-dom/test-utils&lt;/code&gt; in a way that encourages better testing practices.&lt;/p&gt;
&lt;p&gt;Here are some interesting aspects of React Testing Library:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It focuses on verifying actual DOM nodes rather than verifying instances of rendered React components.&lt;/li&gt;
&lt;li&gt;It provides utilities for querying the DOM in the same way the user would.&lt;/li&gt;
&lt;li&gt;It finds elements by their label text (just like a user would).&lt;/li&gt;
&lt;li&gt;It finds links and buttons from their text (like a user would).&lt;/li&gt;
&lt;li&gt;It provides a way to find elements by a &lt;code&gt;data-testid&lt;/code&gt; as an &quot;escape hatch&quot; for elements where the text content and label do not make sense or are not practical or available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that that&apos;s out of the way, let&apos;s get to the good stuff: the hot tips.&lt;/p&gt;
&lt;h2&gt;Tip #1: Screen Instead of Component&lt;/h2&gt;
&lt;p&gt;Have you ever thought to yourself, &quot;Boy, writing &lt;code&gt;component.getByText...&lt;/code&gt; or &lt;code&gt;component.getByLabel...&lt;/code&gt; all the time sure is annoying. I wish there was another way&quot;? Turns out there is: It&apos;s called &lt;a href=&quot;https://testing-library.com/docs/dom-testing-library/api-queries#screen&quot;&gt;&lt;code&gt;screen&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of the queries exported by DOM Testing Library (which RTL is built on top of) accept a &lt;code&gt;container&lt;/code&gt; as the first argument. Because querying the entire &lt;code&gt;document.body&lt;/code&gt; is very common, DOM Testing Library also exports a &lt;code&gt;screen&lt;/code&gt; object that has every query that is pre-bound to &lt;code&gt;document.body&lt;/code&gt; (using the &lt;a href=&quot;https://testing-library.com/docs/dom-testing-library/api-helpers#within-and-getqueriesforelement-apis&quot;&gt;&lt;code&gt;within&lt;/code&gt;&lt;/a&gt; functionality).&lt;/p&gt;
&lt;p&gt;Here&apos;s how you use it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &quot;react&quot;;
import { screen } from &quot;@testing-library/dom&quot;;
import { render } from &quot;@testing-library/react&quot;;
import { act } from &quot;react-dom/test-utils&quot;;
import App from &quot;./App&quot;;

describe(&quot;Product Browser App&quot;, () =&amp;gt; {
  it(&quot;renders a welcome message&quot;, () =&amp;gt; {
    act(() =&amp;gt; {
      render(&amp;lt;App /&amp;gt;);
    });
    screen.findByText(&quot;Hello world&quot;);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trust me: After a while, &lt;code&gt;screen&lt;/code&gt; will become increasingly handy as you&apos;re writing tests to check what&apos;s visible or enabled (or not) in the DOM as you manipulate it.&lt;/p&gt;
&lt;h2&gt;Tip #2: FindByText Instead of waitForElement...getByText&lt;/h2&gt;
&lt;p&gt;If you&apos;ve used RTL before, you probably know it has several handy async functions that start with &lt;code&gt;waitFor&lt;/code&gt;, &lt;code&gt;waitForElement&lt;/code&gt;, or &lt;code&gt;waitForElementToBeRemoved&lt;/code&gt;. These can be useful to wait for an element to appear or disappear in response to an action.&lt;/p&gt;
&lt;p&gt;Typically, the &lt;code&gt;waitFor&lt;/code&gt; code would look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const orderButton = await waitForElement(() =&amp;gt; container.getByTestId(&quot;order-submit-button&quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The line above is pretty clean and concise, but there&apos;s an even cleaner way to write this: with the help of &lt;code&gt;findBy...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check this out:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const orderButton = await container.findByTestId(&quot;order-submit-button&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using any of the &lt;code&gt;findBy&lt;/code&gt; queries that RTL makes available (&lt;code&gt;findByText&lt;/code&gt;, &lt;code&gt;findByTestId&lt;/code&gt;, &lt;code&gt;findByPlaceholder&lt;/code&gt;, etc.), it automatically wraps the element to be searched for in a promise that will wait for it to be rendered, saving you from having to write the wrapper code yourself.&lt;/p&gt;
&lt;p&gt;On its own, this might not seem like much, but imagine writing many multiples of this sort of test all over your application. The leaner test code starts to add up quickly.&lt;/p&gt;
&lt;h2&gt;Tip #3: UserEvent for Async Actions&lt;/h2&gt;
&lt;p&gt;H/T to Kent C. Dodds for letting me know that functions like &lt;code&gt;render()&lt;/code&gt; and &lt;code&gt;fireEvent()&lt;/code&gt; don&apos;t actually need to be manually wrapped in &lt;code&gt;act()&lt;/code&gt; -- every async utility is automatically wrapped courtesy of RTL. Sweet -- that&apos;s even more knowledge for you!&lt;/p&gt;
&lt;p&gt;I do want this to stay a 9 tip blog post, however, so I still wanted to share a library making asynchronous actions like &lt;code&gt;click()&lt;/code&gt; or &lt;code&gt;select()&lt;/code&gt; just a wee bit simpler, just so you&apos;re aware it exists.&lt;/p&gt;
&lt;p&gt;Here&apos;s what the typical async event code looks like in RTL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;await fireEvent.click(orderButton);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not the worst thing to have to write... but consider the amount of &lt;code&gt;async / await&lt;/code&gt; events you have for one fairly complex test case. And write multiple tests to test one component.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/testing-library/user-event&quot;&gt;user-event&lt;/a&gt; library &quot;tries to simulate the real events that would happen in the browser as the user interacts with it. For example &lt;code&gt;userEvent.click(checkbox)&lt;/code&gt; would change the state of the checkbox.&quot;&lt;/p&gt;
&lt;p&gt;Just import it at the top of your test file like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import userEvent from &quot;@testing-library/user-event&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, here&apos;s that same code from above with the &lt;code&gt;userEvent&lt;/code&gt; library applied:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;userEvent.click(orderButton);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look at how that code got even leaner! This, to me, was a game-changer when I learned about it and I absolutely love using it now in my own tests.&lt;/p&gt;
&lt;p&gt;Note: The user-event library doesn&apos;t fully support all async actions in RTL yet. Some actions like &lt;code&gt;change&lt;/code&gt; and &lt;code&gt;keyDown&lt;/code&gt; are not available in user-event, but the library is looking for people to add to it, so if you&apos;d like to contribute, I&apos;m sure they&apos;d appreciate the help.&lt;/p&gt;
&lt;h2&gt;Tip #4: PrettyDOM Instead of debug&lt;/h2&gt;
&lt;p&gt;Debugging non-working code is painful. Debugging non-working tests can be even more painful -- especially when you run RTL&apos;s &lt;code&gt;component.debug()&lt;/code&gt; on the component, but the component&apos;s DOM tree is so large it cuts off before the whole thing is rendered in the console.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(component.debug());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&apos;s what the console shows when the typical &lt;code&gt;debug()&lt;/code&gt; runs in an RTL test:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-testing-library-tips/debug-console-output.png&quot; alt=&quot;Console output showing debug() cutting off with ellipsis&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Notice the &quot;...&quot; at the end of this screenshot? That&apos;s where the render of the DOM tree in the console ends.&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;There&apos;s a solution to this annoyance, however. It&apos;s called &lt;a href=&quot;https://testing-library.com/docs/dom-testing-library/api-helpers#prettydom&quot;&gt;&lt;code&gt;prettyDOM()&lt;/code&gt;&lt;/a&gt;, and RTL&apos;s &lt;code&gt;debug()&lt;/code&gt; method is actually built on top of it. The &lt;code&gt;prettyDOM&lt;/code&gt; function originates in the DOM Testing Library and allows for extra configuration beyond just specifying the component or element to print out. It has an optional &lt;code&gt;maxLength&lt;/code&gt; parameter to limit the size of the resulting string -- or, in my case, to print out very, very large DOM trees.&lt;/p&gt;
&lt;p&gt;Here&apos;s how I use &lt;code&gt;prettyDOM&lt;/code&gt; to print those pesky extra-big DOM trees:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(prettyDOM(component.container, 99999));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is another snippet of the DOM tree being rendered to the console with &lt;code&gt;prettyDOM&lt;/code&gt;. Notice that it keeps going after the RTL &lt;code&gt;debug()&lt;/code&gt; method ends:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-testing-library-tips/prettydom-console-output.png&quot; alt=&quot;Console output showing prettyDOM rendering the full DOM tree&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This rendering of the DOM tree goes on for a lot longer, but you can see it keeps going past the &quot;.ant-radio-button-checked&quot; span where it cut off before.&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Lately, &lt;code&gt;prettyDOM&lt;/code&gt;&apos;s been a real life-saver for me when I&apos;ve been trying to debug some particularly tricky components in my team&apos;s application. Without this option, it would have taken me so much longer to figure out what the problems with the test were.&lt;/p&gt;
&lt;h2&gt;Tip #5: Document.querySelector to Check a Component&apos;s Classes&lt;/h2&gt;
&lt;p&gt;I hope you don&apos;t run into this issue -- I really do -- but if you&apos;re using a component library in your React application like &lt;a href=&quot;https://ant.design/&quot;&gt;Ant Design&lt;/a&gt;, you&apos;re going to learn very quickly that testing some of the more complex components (e.g. tables, radio buttons, etc.) can get really painful with RTL.&lt;/p&gt;
&lt;p&gt;This is because a lot of the typical ways you&apos;d use to ID and check elements with RTL don&apos;t exist (or are too generic) on Ant components. And in some cases, you need to check whether Ant elements are enabled or disabled, but unlike how a custom component might have a &lt;code&gt;data-testid&lt;/code&gt; to target, Ant does not. It has an additional class added to its &lt;code&gt;className&lt;/code&gt; property instead.&lt;/p&gt;
&lt;p&gt;But RTL doesn&apos;t offer an option for checking component classes. In that case, we have to resort to the &lt;code&gt;document&lt;/code&gt; level of the DOM and employ &lt;code&gt;document.querySelector&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To check if an Ant component is hidden, here&apos;s how I did it below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;expect(document.querySelector(&quot;.hidden&quot;)).toBeInTheDocument();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s not particularly elegant code, but it works in a pinch. Just like Kent C. Dodds says to consider &lt;code&gt;data-testid&lt;/code&gt; as an &quot;escape hatch,&quot; consider &lt;code&gt;document.querySelector()&lt;/code&gt; in the same vein. Use it sparingly and only if you have no other options to target an element in RTL.&lt;/p&gt;
&lt;h2&gt;Tip #6: ParentElement to Access Elements Above the Target&lt;/h2&gt;
&lt;p&gt;This is a lesser-known trick I only learned this past week -- again because Ant components are a pain to test with React Testing Library.&lt;/p&gt;
&lt;p&gt;I needed to enter text into an input, then click a plus (+) button at the end of the input box for the value to be saved into the DOM. The plus button, however, happened to be a level above the input element in the component, so in order to target it, I learned about the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement&quot;&gt;&lt;code&gt;parentElement&lt;/code&gt;&lt;/a&gt; selector, which is actually native to the browser, not RTL specifically. And I couldn&apos;t just search the whole component for the plus button because there were multiple plus buttons on the page for multiple inputs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const input = component.queryByPlaceholderText(componentText);
const enter = input.parentElement.querySelector(&quot;.anticon-plus&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see in the example above, first I created the variable &lt;code&gt;input&lt;/code&gt; targeting the input, then I created the second variable &lt;code&gt;enter&lt;/code&gt; targeting the plus button in the input&apos;s parent element.&lt;/p&gt;
&lt;p&gt;This let me click the correct input plus button even though there was no &lt;code&gt;data-testid&lt;/code&gt; or other individually defining characteristic about this Ant input. It&apos;s come in pretty handy as of late. I hope it can help you too.&lt;/p&gt;
&lt;h2&gt;Tip #7: PreviousSibling and nextSibling to Access Elements in Line With the Target&lt;/h2&gt;
&lt;p&gt;In a very similar situation, I also learned about the options of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Node/previousSibling&quot;&gt;&lt;code&gt;previousSibling&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Node/nextSibling&quot;&gt;&lt;code&gt;nextSibling&lt;/code&gt;&lt;/a&gt; (also browser native properties) to select elements around a particular element being targeted in the DOM by React Testing Library.&lt;/p&gt;
&lt;p&gt;In this scenario, I needed to click a checkbox in an Ant table component to select one of the options present in the table. The checkbox element was a sibling of the option&apos;s name, which was the only unique element present in each row of the table.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const keyToSelect = await component.findByText(&quot;key to select&quot;);
userEvent.click(keyToSelect.previousSibling.firstChild.firstChild);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, I created a variable (&lt;code&gt;keyToSelect&lt;/code&gt;) targeting a single row in the Ant table using the unique name of the row (&lt;code&gt;&quot;key to select&quot;&lt;/code&gt;). Then I was able to use the &lt;code&gt;previousSibling&lt;/code&gt; of the targeted element to access the checkbox and select the row inside the table.&lt;/p&gt;
&lt;p&gt;Not exactly the easiest syntax, I&apos;ll admit, but it solved my problem. And you can do exactly the same type of element targeting using &lt;code&gt;nextSibling&lt;/code&gt; as well.&lt;/p&gt;
&lt;h2&gt;Tip #8: Use { exact: false } for Fuzzy Text Matches in the DOM&lt;/h2&gt;
&lt;p&gt;Sometimes, it&apos;s tough to use one of the &lt;code&gt;getByText&lt;/code&gt;- or &lt;code&gt;findByText&lt;/code&gt;-type searches in RTL because it defaults to exact matching. This means &lt;code&gt;getByText(&quot;Hi there&quot;)&lt;/code&gt; will only work if the string is exactly the same in the DOM: full-string, case-sensitive. If there&apos;s a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, a newline (&lt;code&gt;\n&lt;/code&gt;), or something else between &lt;code&gt;&quot;Hi&quot;&lt;/code&gt; and &lt;code&gt;&quot;there&quot;&lt;/code&gt;, this &lt;code&gt;getByText()&lt;/code&gt; query would fail to find the text.&lt;/p&gt;
&lt;p&gt;To do a fuzzy match, which will not be case-sensitive and will include substrings, you can add &lt;code&gt;{ exact: false }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check out this example below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div&amp;gt;Hi there!&amp;lt;/div&amp;gt;

getByText(container, &quot;i the&quot;, { exact: false });
getByText(container, &quot;hi there&quot;, { exact: false });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although it&apos;s more recommended to use a regex if you need to match a substring, for a simpler text selection in the DOM, I think this is a fine substitute. And I don&apos;t know about you, but I always have to test regex out in the browser to remember how to write it. I use it so infrequently.&lt;/p&gt;
&lt;h2&gt;Tip #9: Open Any File in the Browser From the Command Line&lt;/h2&gt;
&lt;p&gt;Final tip, and this one isn&apos;t actually specific to React Testing Library, but I learned it in this class as well and I think it&apos;s pretty cool.&lt;/p&gt;
&lt;p&gt;If you&apos;re using VS Code as your JavaScript IDE of choice and you want to open a file in the browser from the VS Code built-in terminal command line, it&apos;s a snap.&lt;/p&gt;
&lt;p&gt;In the command line, all you have to do is type &lt;code&gt;open &amp;lt;file path&amp;gt;&lt;/code&gt;, and voila: A new window pops open in your browser.&lt;/p&gt;
&lt;p&gt;The reason I mention it here is because it provided a quick and easy way for me to check my code coverage, as I added new tests to our application. I find it a lot easier to click around in the browser version of code coverage to see which lines are tested than using the little printout in the terminal.&lt;/p&gt;
&lt;p&gt;For example, to open code coverage for our project, I&apos;d write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;open coverage/lcov-report/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there it is, ready to be examined in detail. VS Code handy shortcuts for the win. I thought it was a fun fact and I hope you might find it useful too.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;React Testing Library is a powerful framework that&apos;s really changed the way we approach integration testing React applications. It took a minute for me to wrap my head around the changes that RTL entails, but I think it makes more sense for how the application should really work in the real world.&lt;/p&gt;
&lt;p&gt;And although I knew some things about React Testing Library, I learned a lot of lesser-known tips and tricks that have helped simplify and streamline my own testing.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks -- I&apos;ll be writing more about JavaScript, React, ES6, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you learned a few new things that will make your own use of the React Testing Library that much easier. Integration testing nowadays is a necessary piece of any good web application. The least I can do is try to make it a little easier for you.&lt;/p&gt;
&lt;h2&gt;References and Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;React Testing Library &lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro&quot;&gt;documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;React Testing Library &lt;a href=&quot;https://github.com/testing-library/react-testing-library&quot;&gt;GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RTL User Event &lt;a href=&quot;https://github.com/testing-library/user-event&quot;&gt;GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>react</category><category>testing</category><category>javascript</category></item><item><title>How to Use React&apos;s Context API and useContext() Hooks Effectively</title><link>https://www.paigeniedringhaus.com/blog/how-to-use-reacts-context-api-and-usecontext-hooks-effectively/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/how-to-use-reacts-context-api-and-usecontext-hooks-effectively/</guid><description>Avoid prop drilling both your values and your functions with the help of Context</description><pubDate>Tue, 03 Mar 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-context-api-usecontext/hero.jpeg&quot; alt=&quot;Colorful pattern&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;At work recently, I was faced with a problem that&apos;s quite common, thanks to React&apos;s one-way data flow. At a high level of my application, I opened a checkout drawer that contained a user&apos;s selection of items to order. In another, much lower component, I triggered the actual ordering of those items. Once the order was successfully placed, I needed the drawer to automatically slide closed again.&lt;/p&gt;
&lt;p&gt;Following so far?&lt;/p&gt;
&lt;p&gt;Because of the nature of my app&apos;s checkout process, there were a lot of intermediate components between the top-level, parent component (controlling the drawer&apos;s open or closed state), and the final checkout child component inside the drawer (containing the button and function to place the order).&lt;/p&gt;
&lt;p&gt;I wanted to avoid having to pass down props containing the drawer&apos;s open state and a function to toggle the drawer&apos;s state back to closed upon order success. None of the other intermediate components needed those props for anything, so it would be extra code that didn&apos;t need to be there. Then I lit upon a solution — something I&apos;d heard a bit about but had never had a need to use: React&apos;s Context.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll be detailing how I used React&apos;s Context API and its &lt;code&gt;useContext&lt;/code&gt; hook to avoid prop drilling both application state and functions.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;What&apos;s the React Context API?&lt;/h2&gt;
&lt;p&gt;Before I get too far into the weeds of how I employed the &lt;a href=&quot;https://reactjs.org/docs/context.html&quot;&gt;&lt;strong&gt;Context API&lt;/strong&gt;&lt;/a&gt; to help solve my problems, let me go over what it is and how it works, so we&apos;re all on the same page.&lt;/p&gt;
&lt;p&gt;React&apos;s official documentation does the best job of defining Context:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Context provides a way to pass data through the component tree without having to pass props down manually at every level. — &lt;a href=&quot;https://reactjs.org/docs/context.html#when-to-use-context&quot;&gt;React Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just as in the scenario I described above, Context exists in React as a way to pass data around an application without having to explicitly pass a prop through every level of the tree. It&apos;s React&apos;s built-in way of sharing data that can be considered &quot;global&quot; for a tree of React components.&lt;/p&gt;
&lt;p&gt;Examples of this could include user authentication, preferred language or theme setting, or, as with my situation, a child component telling a parent component to switch its state from an open drawer to a closed drawer.&lt;/p&gt;
&lt;p&gt;Yes, you could use Redux for this sort of global state management as well, but the boilerplate code required to set up Redux, its actions and its dispatchers, is a lot of extra work for what should be a relatively simple set of tasks. Plus, with the release of &lt;a href=&quot;https://reactjs.org/docs/hooks-intro.html&quot;&gt;&lt;strong&gt;React Hooks&lt;/strong&gt;&lt;/a&gt;, using context has been made easier than before.&lt;/p&gt;
&lt;p&gt;OK, let&apos;s talk about how to use React&apos;s Context API and the &lt;code&gt;useContext&lt;/code&gt; Hook. I&apos;ll show you how to implement it using my own application.&lt;/p&gt;
&lt;h2&gt;Using React Context&lt;/h2&gt;
&lt;p&gt;The first thing you need to do to use the Context API is to create a new Context file. This is the file that will hold any data variables, default values, and functions you might want to make accessible to the components when using this context.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://reactjs.org/docs/context.html#reactcreatecontext&quot;&gt;React.createContext()&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Inside your context file, which I tend to name &lt;code&gt;XyzContext.js&lt;/code&gt;, you&apos;ll &lt;strong&gt;create&lt;/strong&gt; this particular instance of &lt;code&gt;Context&lt;/code&gt;, and assign it some default values.&lt;/p&gt;
&lt;p&gt;Here&apos;s the context file I made for my application to handle the visibility of the checkout drawer and the toggle of its visibility state.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CheckoutDrawerContext.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { createContext } from &apos;react&apos;;

const CheckoutDrawerContext = createContext({
  showDrawer: false,
  toggleCheckoutDrawer: () =&amp;gt; {},
});

export default CheckoutDrawerContext;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see from my code snippets, to create a new instance of Context is relatively easy. In my case, after calling &lt;code&gt;creatContext()&lt;/code&gt;, I just passed in an object with a boolean about the checkout drawer&apos;s current visibility (&lt;code&gt;showDrawer&lt;/code&gt; with a default starting value of &lt;code&gt;false&lt;/code&gt;) and an empty arrow function called &lt;code&gt;toggleCheckoutDrawer()&lt;/code&gt;, which will eventually be associated with a function that actually affects the drawer&apos;s state of being shown or hidden.&lt;/p&gt;
&lt;p&gt;When React renders a component that subscribes to this &lt;code&gt;CheckoutDrawerContext&lt;/code&gt; object it will read the current context values from the closest matching &lt;code&gt;Provider&lt;/code&gt; above it in the tree.&lt;/p&gt;
&lt;p&gt;The default value argument (&lt;code&gt;showDrawer&lt;/code&gt;, in this case) is &lt;em&gt;only&lt;/em&gt; used when a component does not have a matching Provider above it in the tree.&lt;/p&gt;
&lt;p&gt;Now that this particular instance of Context is created, we can move on to using it in my application.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://reactjs.org/docs/context.html#contextprovider&quot;&gt;Context.Provider&lt;/a&gt; and its values&lt;/h3&gt;
&lt;p&gt;Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes.&lt;/p&gt;
&lt;p&gt;The provider accepts &lt;code&gt;value&lt;/code&gt; props to be passed to consuming components that are descendants of this Provider. What&apos;s also good to know is that one Provider can be connected to many consumers. If multiple children need to know or change the values of the provider, they can.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Cart.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;CheckoutDrawerContext.Provider value={{ showDrawer, toggleCheckoutDrawer }}&amp;gt;
  &amp;lt;section className=&quot;cart-checkout&quot;&amp;gt;
    &amp;lt;CartDrawer selectedCartItems={selectedCartItems} /&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/CheckoutDrawerContext.Provider&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For my application, inside of my top level &lt;code&gt;Cart&lt;/code&gt; component, I wrapped my &lt;code&gt;CartDrawer&lt;/code&gt; component in my &lt;code&gt;CheckoutDrawerContext.Provider&lt;/code&gt;. I did this because child components nested within &lt;code&gt;CartDrawer&lt;/code&gt; would need access to the values the &lt;code&gt;CheckoutDrawerContext.Provider&lt;/code&gt; contains — in this case, the &lt;code&gt;showDrawer&lt;/code&gt; state and the &lt;code&gt;toggleCheckoutDrawer()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;As for the values being passed to the &lt;code&gt;CheckoutDrawerContext.Provider&lt;/code&gt;, I made them inside the &lt;code&gt;Cart.js&lt;/code&gt; file too.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Cart.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const [showDrawer, setShowDrawer] = useState(false);

const toggleCheckoutDrawer = () =&amp;gt; {
  setShowDrawer(!showDrawer);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the &lt;code&gt;useState()&lt;/code&gt; React Hook inside of the &lt;code&gt;Cart&lt;/code&gt; component file, I created a piece of state called &lt;code&gt;showDrawer&lt;/code&gt; with its setter to update the boolean &lt;code&gt;setShowDrawer&lt;/code&gt;. I created a function called &lt;code&gt;toggleCheckoutDrawer()&lt;/code&gt;, which would switch the value of &lt;code&gt;showDrawer&lt;/code&gt; to whatever its opposite value was.&lt;/p&gt;
&lt;p&gt;I named these states and functions after the default values in my &lt;code&gt;CheckoutDrawerContext&lt;/code&gt; file, but this is not necessary — I did it only for my own convenience.&lt;/p&gt;
&lt;p&gt;Right, so now the &lt;code&gt;Context.Provider&lt;/code&gt; is up and running and it has its values of &lt;code&gt;showDrawer&lt;/code&gt; and &lt;code&gt;toggleCheckoutDrawer()&lt;/code&gt;. I&apos;m ready to move on to the consuming values part.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://reactjs.org/docs/context.html#contextconsumer&quot;&gt;React.Consumer&lt;/a&gt; and &lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#usecontext&quot;&gt;React.useContext()&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Initially, when Context was first released with React, it was only available to stateful, class-based components.&lt;/p&gt;
&lt;p&gt;The syntax for Context consumers is similar to that for Providers to add it to a project — wrap the consumer around the code that needs access to the values, as shown in the sample code below.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ClassBasedChildComponent.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;SampleContext.Consumer&amp;gt;
  {value =&amp;gt; /* do something with the context values passed here */}
&amp;lt;/SampleContext.Consumer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But since my application is using React hooks and the checkout flow is written using functional components, I leveraged the &lt;code&gt;useContext()&lt;/code&gt; hook for my components that needed access to the &lt;code&gt;CheckoutDrawerContext&lt;/code&gt; instead. In my opinion, it&apos;s cleaner code and easier to understand.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CheckoutSummaryDetails.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { useContext } from &apos;react&apos;;
import { orderItems } from &apos;../../../../services/orderService&apos;;
import CheckoutDrawerContext from &apos;../../../../context/CheckoutDrawerContext&apos;;

export const CheckoutSummaryDetails = props =&amp;gt; {
  const { summaryDetails, userInfo, items } = props;
  const checkoutDrawer = useContext(CheckoutDrawerContext);

  const placeOrder = async () =&amp;gt; {
    const executionResponse = await orderItems(userInfo, items);
    if (executionResponse === &apos;successfully placed order&apos;) {
      checkoutDrawer.toggleCheckoutDrawer();
    }
  };

  return (
    &amp;lt;div className=&quot;cart-drawer__summary&quot;&amp;gt;
      &amp;lt;strong className=&quot;cart-drawer__header&quot;&amp;gt;Summary&amp;lt;/strong&amp;gt;
      &amp;lt;div className=&quot;cart-drawer__summary-content&quot;&amp;gt;
        &amp;lt;div className=&quot;checkout-summary&quot;&amp;gt;
          &amp;lt;span&amp;gt;Final Checkout Summary&amp;lt;/span&amp;gt; &amp;lt;span&amp;gt;{summaryDetails}&amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;button type=&quot;button&quot; className=&quot;order-button&quot; onClick={placeOrder}&amp;gt;
        Order Now
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component above, &lt;code&gt;CheckoutSummaryDetails.js&lt;/code&gt;, is a very stripped-down version of the actual checkout in my application, but it serves its purpose for this example.&lt;/p&gt;
&lt;p&gt;First, note that the &lt;code&gt;CheckoutDrawerContext&lt;/code&gt; is imported into this &lt;code&gt;CheckoutSummaryDetails.js&lt;/code&gt; file. To actually gain access to the values of this Context, I create a new constant (&lt;code&gt;checkoutDrawer&lt;/code&gt;), and wrap the named Context in the &lt;code&gt;useContext()&lt;/code&gt; Hook. This gives me access to values within the &lt;code&gt;CheckoutDrawerContext&lt;/code&gt;. The rest is fairly straightforward.&lt;/p&gt;
&lt;p&gt;When the user clicks the button titled &quot;Order Now,&quot; the &lt;code&gt;placeOrder()&lt;/code&gt; function is fired in the component and it triggers the &lt;code&gt;orderItems()&lt;/code&gt; call to an API or a database or wherever else it might need to send the user info and the items being ordered. Upon a success message of the order being placed, the component that closes the &lt;code&gt;CartDrawer&lt;/code&gt; is triggered via &lt;code&gt;checkoutDrawer.toggleCheckoutDrawer()&lt;/code&gt;. This will switch the state of &lt;code&gt;showDrawer&lt;/code&gt; to some four or five levels higher up this component tree, from &lt;code&gt;true&lt;/code&gt; back to &lt;code&gt;false&lt;/code&gt;, and the &lt;code&gt;CartDrawer&lt;/code&gt; component will be hidden from view again.&lt;/p&gt;
&lt;p&gt;That&apos;s it! React&apos;s Context has prevented unnecessary prop passing &lt;em&gt;and&lt;/em&gt; allowed a child component to update the state of a parent component. Sweet!&lt;/p&gt;
&lt;p&gt;That wasn&apos;t so hard now, was it? Believe me, once you&apos;ve used Context successfully once, implementing it in lots of other places will be a cinch.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;React&apos;s Context API and &lt;code&gt;useContext&lt;/code&gt; Hook are fairly easy to understand in theory. They&apos;re a little less clear when it comes to implementing them the first time around.&lt;/p&gt;
&lt;p&gt;But they&apos;re such a help. Passing unneeded data through several levels of a component tree when only the second and sixth level of child components actually need those props is not helpful. It just means more props to keep track of, even when all the intermediate components don&apos;t need that data.&lt;/p&gt;
&lt;p&gt;Yes, Redux could do the same thing, but that&apos;s a lot of extra setup for even the simplest pieces of data. And unlike Redux, Context is native to React — it&apos;s already built-in, it&apos;s ready to go, and once you start using it, it&apos;s pretty intuitive. I was hesitant to try it at first, but once I figured it out, I became a big fan. I think you will be too.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I&apos;ll be writing more about JavaScript, React, ES6, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope I&apos;ve demystified React&apos;s Context API and &lt;code&gt;useContext&lt;/code&gt; Hook so you can successfully use it in your own React project. You won&apos;t regret the cleaner code that it makes possible!&lt;/p&gt;
&lt;h2&gt;References and Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;React &lt;a href=&quot;https://reactjs.org/docs/context.html#updating-context-from-a-nested-component&quot;&gt;Context API&lt;/a&gt; documentation&lt;/li&gt;
&lt;li&gt;React Hooks &lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#usecontext&quot;&gt;useContext&lt;/a&gt; documentation&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category></item><item><title>JavaScript’s Optional Chaining Proposal</title><link>https://www.paigeniedringhaus.com/blog/javascripts-optional-chaining-proposal/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/javascripts-optional-chaining-proposal/</guid><description>Kiss undefined errors that stop you dead in your tracks goodbye.</description><pubDate>Sun, 16 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/javascript-optional-chaining/jumping-hero.webp&quot; alt=&quot;Outline of a woman jumping for joy at sunset&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If you’ve been a JavaScript developer for any length of time, you’ll understand the annoyance I’m describing as soon as I set up this scenario.&lt;/p&gt;
&lt;p&gt;Picture it: you’re coding away, building something cool, fetching data and manipulating objects, and suddenly you see the error, the dreaded &lt;code&gt;undefined&lt;/code&gt; error. And your application breaks. Hard. 😑&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/javascript-optional-chaining/undefined-error.webp&quot; alt=&quot;Undefined error in JavaScript code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The &lt;code&gt;undefined&lt;/code&gt; error every JavaScript developer ever, has encountered.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;You sigh, roll your eyes 🙄, and add &lt;em&gt;yet another&lt;/em&gt; check into your &lt;code&gt;if / else&lt;/code&gt; statement to prevent undefined errors like this in the future (in this case it’s making sure the &lt;code&gt;genres&lt;/code&gt; array has a length of more than 0).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (!loading &amp;amp;&amp;amp; !error &amp;amp;&amp;amp; genres.length) {
  // do something here
} else { 
  // handle if something evaluates to not true in the if statement
}
// program continues on its merry way
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what if there was a better way?&lt;/p&gt;
&lt;p&gt;What if, instead of checking that several objects or object properties existed before finally getting to what you want to do with that data, the good stuff, the interesting stuff, you could move on to that part &lt;em&gt;even if&lt;/em&gt; things did evaluate to &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;? If your code didn’t just throw up as soon as it hit an undefined value, instead of what it was expecting?&lt;/p&gt;
&lt;p&gt;Sounds like the stuff of dreams? Too good to be true? Not anymore.&lt;/p&gt;
&lt;p&gt;Because JavaScript wants to do just that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That’s what I want to talk about today: the optional chaining operator &lt;code&gt;?.&lt;/code&gt; proposal, which lets us read the value of a property located deep within a chain of connected objects &lt;em&gt;without&lt;/em&gt; having to expressly validate that each reference in the chain is valid.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Optional Chaining Operators&lt;/h2&gt;
&lt;p&gt;As I alluded to in the introduction, the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot;&gt;&lt;strong&gt;optional chaining operator&lt;/strong&gt;&lt;/a&gt; is a proposal, which is currently in &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 4&lt;/a&gt;, allowing for a sort of short-circuiting if a reference evaluates to &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt; and returns a value of &lt;code&gt;undefined&lt;/code&gt; instead of throwing an error the program cannot continue on from.&lt;/p&gt;
&lt;p&gt;This boils down to shorter and simpler expressions when accessing chained properties when the possibility exists that a reference may be missing. It can also be immensely helpful while exploring the contents of an object when there’s no guarantee as to which properties are required.&lt;/p&gt;
&lt;h3&gt;Syntax of the optional chaining operator&lt;/h3&gt;
&lt;p&gt;I know this sounds a little complicated in writing, but seeing it in code should make it clearer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optional chaining with object properties&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here’s an example of optional chaining when accessing an object’s properties:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const simpleObj = {
  levelOne: {
    levelTwo: &quot;hello world&quot;
  }
};
let nestedProp = simpleObj.levelOne?.levelThree;
console.log(&quot;There is a not a levelThree prop, it is &quot;, nestedProp); // prints: &quot;There is a not a levelThree prop, it is  undefined&quot;
console.log(&quot;But the program still goes on.&quot;); // prints: &quot;But the program still goes on.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The chaining operator is actually made up of just &lt;code&gt;?.&lt;/code&gt;. If the operand at the left-hand side of the &lt;code&gt;?.&lt;/code&gt; operator evaluates to &lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;, the expression evaluates to &lt;code&gt;undefined&lt;/code&gt;. Otherwise the targeted property access, method or function call is triggered normally.&lt;/p&gt;
&lt;p&gt;And you can add it to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An object: &lt;code&gt;a?.b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;An object expression: &lt;code&gt;a?.[x]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;An array: &lt;code&gt;a?.[index]&lt;/code&gt; or&lt;/li&gt;
&lt;li&gt;A function’s arguments &lt;code&gt;a?.b()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And it can simplify accessing values through connected objects when it’s possible that a reference or function may be &lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Before optional chaining, everything had to be validated&lt;/h3&gt;
&lt;p&gt;Just think about how often you’ve been working with objects that have properties nested more than one level deep, and you’ve had to validate &lt;em&gt;every&lt;/em&gt;. &lt;em&gt;Single&lt;/em&gt;. &lt;em&gt;One&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Without optional chaining, looking up a deeply-nested sub property meant validating the references in between, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let newSubProperty = obj.prop &amp;amp;&amp;amp; obj.prop.subProp;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value of &lt;code&gt;obj.prop&lt;/code&gt; is checked to be non-null and not &lt;code&gt;undefined&lt;/code&gt; and then the value of &lt;code&gt;obj.prop.subProp&lt;/code&gt; is accessed. This prevents the error that would have happened by attempting to access &lt;code&gt;obj.prop.subProp&lt;/code&gt; without first checking that a value for &lt;code&gt;obj.prop&lt;/code&gt; existed.&lt;/p&gt;
&lt;p&gt;I don’t know about you but this felt like a lot of extra, redundant code to me.&lt;/p&gt;
&lt;p&gt;With the optional chaining operator (&lt;code&gt;?.&lt;/code&gt;), however, you don&apos;t have to explicitly test and short-circuit based on the state of obj.prop before trying to access &lt;code&gt;obj.prop.subProp&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let newSubProperty = obj.prop?.subProp;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using the &lt;code&gt;?.&lt;/code&gt; operator, JavaScript knows to implicitly check that &lt;code&gt;obj.prop&lt;/code&gt; isn’t a &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt; value before attempting to access the nested &lt;code&gt;subProp&lt;/code&gt;. If &lt;code&gt;obj.prop&lt;/code&gt; does end up evaluating to either &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, the expression short-circuits and returns an &lt;code&gt;undefined&lt;/code&gt; value, and the program moves on.&lt;/p&gt;
&lt;p&gt;Let’s look at some more examples of the optional chaining operator in action.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optional chaining with function calls&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can use optional chaining when attempting to call a method which may not exist. This can be helpful when using an API in which a method might be unavailable, either due to the age of the implementation or because a feature isn’t available on the user’s device.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let response = someInterface.customFunction?.();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using optional chaining with function calls, the expression will automatically return &lt;code&gt;undefined&lt;/code&gt; instead of throwing an exception if the method isn&apos;t found.&lt;/p&gt;
&lt;p&gt;When using optional chaining with expressions, if the left operand is &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, the expression just won’t be evaluated.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let possibleNull = null;
let value = 0;
let result = possible?.[value++];

console.log(value); // 0 as value was not incremented
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even though the variable &lt;code&gt;possibleNull&lt;/code&gt; was indeed &lt;code&gt;null&lt;/code&gt;, the variable &lt;code&gt;result&lt;/code&gt; didn’t throw an error because the optional chaining operator kicked in. It just skipped over the function and moved on. Useful, no?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optional chaining with object expressions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can also use the optional chaining operator when accessing properties with an expression using the bracket notation of the property accessor. Check this out.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let nestedProp = myObj?.[&quot;prop&quot; + &quot;Name&quot;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Being able to use this with bracket notation might is useful in cases where you have a dynamic key. In my opinion, it&apos;s a little harder to read that dot notation, but it’s there if you need it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Array item access with optional chaining&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Arrays with optional chaining are interesting, by using the optional chaining syntax you can attempt to access items within an array by the index you pass, and if that index doesn’t exist within the array it won’t error out.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let arr = [1,2,3];
let arrayItem = arr?.[3];
console.log(arrayItem) // prints: undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Stacked optional chaining&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another cool thing to note is that you can use optional chaining multiple times within the same nested object.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let customer = {
  name: &quot;Sean&quot;,
   details: {
    age: 43,
    location: &quot;Trinidad&quot; // detailed address and subscription service frequency is unknown
  }
};

let customerSubscription = customer.details?.subscription?.frequency;
console.log(customerSubscription); // prints: undefined

let customerCity = customer.details?.address?.city;
console.log(customerCity); // prints: undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In both variables, &lt;code&gt;customerSubscription&lt;/code&gt; and &lt;code&gt;customerCity&lt;/code&gt;, the value ends up being &lt;code&gt;undefined&lt;/code&gt; because neither is defined on the &lt;code&gt;customer&lt;/code&gt; object. But once again, an error isn’t thrown if this is the case.&lt;/p&gt;
&lt;p&gt;You can do this same thing with functions as well: multiple optional chaining operators within function calls. Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let duration = vacations.trip?.getTime?.();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Combining with the nullish coalescing operator&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is pretty useful on its own but the real power comes when optional chaining is combined with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator&quot;&gt;&lt;strong&gt;nullish coalescing operator&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I won’t go in to great detail about this feature (also in Stage 4 proposal), but in a nutshell, the nullish coalescing operator, written as &lt;code&gt;??&lt;/code&gt; is a logical operator that returns its right-hand side operand when its left-hand side operand is &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, and otherwise returns its left-hand side operand.&lt;/p&gt;
&lt;p&gt;Here’s how the two proposals work together to build a default value when none is found.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let customer2 = {
  name: &quot;Paige&quot;,
  details: { 
    age: 30 // once again a city is not provided on this object
  }
};

const customerCity2 = customer2?.city ?? &quot;City not provided&quot;;
console.log(customerCity2); // prints: &quot;City not provided&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since the &lt;code&gt;city&lt;/code&gt; property is not provided and evaluates to &lt;code&gt;undefined&lt;/code&gt; courtesy of the optional chaining operator, the, the nullish coalescing operator then kicks in and defaults to the right-hand side operand &lt;code&gt;&quot;City not provided&quot;&lt;/code&gt; because the left-hand side operand evaluated to &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Just think, you can create your own default values if one is missing, preventing tons of time spent debugging weird errors caused by bad data. How awesome is that? Pretty awesome in my humble opinion! 😀&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The optional chaining operator aims to make our lives as web developers and our jobs as programmers that much simpler by eliminating errors that will break your application when object values or functions are not present.&lt;/p&gt;
&lt;p&gt;Since the proposal is still in Stage 4 at the time of this writing it is not yet fully supported by all browsers, or standardized into the JavaScript language. Chrome, Firefox and Opera support the functionality, Edge, Safari and Internet Explorer do not.&lt;/p&gt;
&lt;p&gt;But because it has reached Stage 4, it is now only a matter of time before it’s added to the standard ECMAScript syntax and supported across all the major browsers. You can keep an eye on the proposal in &lt;a href=&quot;https://github.com/tc39/proposal-optional-chaining&quot;&gt;Github&lt;/a&gt; or the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot;&gt;MDN Docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cleaner, clearer, easier to maintain code. That’s the end game of all these improvements to the JavaScript language, and I, for one, am really excited to see the optional chaining operator coming into mainstream development soon.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing more about JavaScript, React, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll keep an eye out for when optional chaining gains full support and we can start simplifying our code’s null and undefined checks and putting this into production. This is going to make web development a whole lot easier.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tc39/proposal-optional-chaining&quot;&gt;Optional chaining proposal, GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot;&gt;Optional chaining explanation, MDN docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator&quot;&gt;Nullish coalescing operator, MDN docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category></item><item><title>React Socks and Responsive Web Design With React</title><link>https://www.paigeniedringhaus.com/blog/react-socks-and-responsive-web-design-with-react/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/react-socks-and-responsive-web-design-with-react/</guid><description>A React-specific way to build apps to suit your user’s device size.</description><pubDate>Tue, 04 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-socks/phone-hero.webp&quot; alt=&quot;Close up of phone with widgets on home screen and different computers in background out of focus&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A few months ago, I gave a talk with a coworker at the tech conference &lt;a href=&quot;https://connect.tech/&quot;&gt;Connect.Tech&lt;/a&gt; about the ever-growing need for responsive web design when building websites and applications. We discussed a couple of different ways to approach it, specifically when it comes to the JavaScript framework &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In case you’re unfamiliar with the term, let me quickly define &lt;strong&gt;responsive web design&lt;/strong&gt; so we’re all starting at the same point. The best definition I’ve found comes straight from &lt;a href=&quot;https://www.smashingmagazine.com/&quot;&gt;Smashing Magazine&lt;/a&gt;, a leading editorial voice for web developers and web designers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Responsive web design is the approach that suggests that design and development should respond to the user’s behavior and environment based on screen size, platform, and orientation.” &lt;a href=&quot;https://www.smashingmagazine.com/2011/01/guidelines-for-responsive-web-design/&quot;&gt;— Smashing Magazine&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It should already make sense why it’d be evermore necessary in today’s world to start with responsive design for multiple browser/device sizes in mind as you build applications, but in case you’d like a few statistics, here are some that should help to convince you.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“57% of users say they won’t recommend a business with a poorly designed mobile site.” &lt;a href=&quot;https://www.socpub.com/articles/the-5-mobile-marketing-mistakes-infographic-14849&quot;&gt;— socPub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, a poor mobile presence (or, worse still, no mobile presence at all) can make your organization look unprofessional and out of touch with the modern consumer. Here’s another:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“83% of users say a seamless experience across all devices is very important.” &lt;a href=&quot;https://visual.ly/community/infographic/technology/mobile-web-usage-2015-and-onwards&quot;&gt;— Wolfgang Jaegel&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Consumers today expect a seamless experience and brand consistency regardless of what device they’re using to interact with your brand. Consider this chart from August 2018-August 2019 showing the average screen sizes of users worldwide.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-socks/desktop-tablet-mobile-stats.webp&quot; alt=&quot;Desktop, mobile &amp;amp; tablet screen resolution stats worldwide&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Data source: GlobalStats, showing August 2018-August 2019&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In 2020 and beyond, all signs point to a need for responsive design to meet users wherever they are.&lt;/p&gt;
&lt;p&gt;While I won’t go into all the details we went into in our talk of how to approach responsive design, I’d like to share two possible approaches to responsive design for anyone else looking to get started with it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This piece will cover the second solution for responsive web design, which is specific to the JavaScript framework React: using React Socks to conditionally render elements based on viewport size.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you’d like to see the first solution I talked about (CSS media queries), you can see my post &lt;a href=&quot;./pure-css-media-queries-and-responsive-web-design-with-react&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What is React Socks?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-socks&quot;&gt;&lt;strong&gt;React Socks&lt;/strong&gt;&lt;/a&gt; is a React library designed to render components based on specific viewports.&lt;/p&gt;
&lt;p&gt;While CSS media queries are used to show and hide elements &lt;em&gt;always&lt;/em&gt; present in the DOM, React Socks goes one step further, helping to &lt;em&gt;conditionally&lt;/em&gt; render elements based on viewport size. This means unless the components are the right size for the current viewport, React Socks won’t render the component (or its accompanying CSS) at all.&lt;/p&gt;
&lt;p&gt;What this boils down to is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rendering viewport-specific components without hassle&lt;/li&gt;
&lt;li&gt;The ability to name and define your own breakpoints where you need them (React Socks also has predefined breakpoints as well, if you prefer not to customize them)&lt;/li&gt;
&lt;li&gt;The potential for improved app performance if you lazy load viewport-specific components&lt;/li&gt;
&lt;li&gt;Simpler and sweeter syntax, for ease of use&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Using React Socks&lt;/h3&gt;
&lt;p&gt;Implementing React Socks is actually easy, as well. To begin, you wrap your top-level component (probably &lt;code&gt;App&lt;/code&gt;) with a &lt;code&gt;&amp;lt;BreakpointProvider&amp;gt;&lt;/code&gt; tag, and then you can use the &lt;code&gt;&amp;lt;Breakpoint&amp;gt;&lt;/code&gt; tag anywhere you need inside the rest of the application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BreakpointProvider implementation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here’s how I wrapped my app at the top level with &lt;code&gt;&amp;lt;BreakpointProvider&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;App.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &apos;react&apos;;
import { BrowserRouter as Router, Route, Switch } from &apos;react-router-dom&apos;;
import { BreakpointProvider } from &apos;react-socks&apos;;
import NowPlaying from &apos;./containers/NowPlaying/NowPlaying&apos;;
import Dashboard from &apos;./containers/Dashboard/Dashboard&apos;;
import Upcoming from &apos;./containers/Upcoming/Upcoming&apos;;
import MovieSearch from &apos;./containers/MovieSearch/MovieSearch&apos;;
import Genres from &apos;./containers/Genres/Genres&apos;;
import Header from &apos;./containers/Header/Header&apos;;
import &apos;./App.css&apos;;

function App() {
  return (
    &amp;lt;BreakpointProvider&amp;gt;
      &amp;lt;div className=&quot;App&quot;&amp;gt;
        &amp;lt;Router&amp;gt;
          &amp;lt;LastLocationProvider&amp;gt;
            &amp;lt;Header /&amp;gt;
            &amp;lt;Switch&amp;gt;
              &amp;lt;Route exact path=&quot;/&quot; component={Dashboard} /&amp;gt;
              &amp;lt;Route exact path=&quot;/search&quot; component={MovieSearch} /&amp;gt;
              &amp;lt;Route exact path=&quot;/nowplaying&quot; component={NowPlaying} /&amp;gt;
              &amp;lt;Route exact path=&quot;/upcoming&quot; component={Upcoming} /&amp;gt;
              &amp;lt;Route exact path=&quot;/genres&quot; component={Genres} /&amp;gt;
            &amp;lt;/Switch&amp;gt;
          &amp;lt;/LastLocationProvider&amp;gt;
        &amp;lt;/Router&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/BreakpointProvider&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Import it from React Socks at the top of the file, and wrap the whole app. Done!&lt;/p&gt;
&lt;p&gt;Once that’s taken care of, you’re free to start using the &lt;code&gt;&amp;lt;Breakpoint&amp;gt;&lt;/code&gt; tag throughout your app wherever you need responsiveness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Breakpoint implementation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is an example of setting up breakpoints inside of a component using the &lt;code&gt;&amp;lt;Breakpoint&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;p&gt;In addition to the actual &lt;code&gt;Breakpoint&lt;/code&gt; tag wrapper, you’ll need to include a size [React Socks’ defaults are &lt;code&gt;xsmall&lt;/code&gt; (0px), &lt;code&gt;small&lt;/code&gt; (576px), &lt;code&gt;medium&lt;/code&gt; (768px), &lt;code&gt;large&lt;/code&gt; (992px), and &lt;code&gt;xlarge&lt;/code&gt; (1200px)] and a modifier of &lt;code&gt;down&lt;/code&gt;, &lt;code&gt;up&lt;/code&gt;, or &lt;code&gt;only&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Down&lt;/code&gt; means anything &lt;em&gt;up to&lt;/em&gt; that particular breakpoint and below it, &lt;code&gt;up&lt;/code&gt; means anything &lt;em&gt;down to&lt;/em&gt; that particular breakpoint and above it, and &lt;code&gt;only&lt;/code&gt; (or no modifier) means &lt;em&gt;only within&lt;/em&gt; that particular breakpoint’s pixel ranges. It may make more sense if you look at the example below.&lt;/p&gt;
&lt;p&gt;The first snippet is the JSX code, and the second is the CSS that goes along with the different breakpoints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Genres.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    return (
      &amp;lt;div className=&quot;genres-page&quot;&amp;gt;
        &amp;lt;h1&amp;gt;Choose a Genre&amp;lt;/h1&amp;gt;
        {(error || loading) &amp;amp;&amp;amp; &amp;lt;h3 className=&quot;genre-info&quot;&amp;gt;{info}&amp;lt;/h3&amp;gt;}
        &amp;lt;Breakpoint large up&amp;gt;
          &amp;lt;div className=&quot;genre-list&quot;&amp;gt;
            {this.renderRedirect()}
            {genreInfo}
          &amp;lt;/div&amp;gt;
        &amp;lt;/Breakpoint&amp;gt;
        &amp;lt;Breakpoint medium&amp;gt;
          &amp;lt;div className=&quot;genre-list&quot;&amp;gt;
            {this.renderRedirect()}
            {genreInfo}
          &amp;lt;/div&amp;gt;
        &amp;lt;/Breakpoint&amp;gt;
        &amp;lt;Breakpoint small down&amp;gt;
          &amp;lt;div className=&quot;genre-list&quot;&amp;gt;
            {this.renderRedirect()}
            {genreInfo}
          &amp;lt;/div&amp;gt;
        &amp;lt;/Breakpoint&amp;gt;
      &amp;lt;/div&amp;gt;
    );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Genres.scss&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.genre-list {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    max-width: 1200px;
    grid-gap: 15px;
    justify-items: center;
    margin: auto;
    h3 {
      margin: 200px auto;
    }
  }

.breakpoint__medium-only {
  .genre-list {
    grid-template-columns: repeat(3, 1fr);
  }
  h3 {
    font-size: 18px;
    width: 80%;
  }
  .genre-component {
    width: 170px;
    height: 170px;
    h3 {
      font-size: 22px;
    }
  }
}

.breakpoint__small-down {
  .genre-list {
    grid-template-columns: repeat(2, 1fr);
  }
  h3 {
    font-size: 18px;
    width: 80%;
  }
  .genre-component {
    width: 140px;
    height: 140px;
    font-size: 18px;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the first &lt;code&gt;Breakpoint&lt;/code&gt; wrapper dictates that whenever a viewport is large up (i.e. 992px or greater), the first CSS listed will be rendered (the one with &lt;code&gt;grid-template-columns: repeat(4, 1fr);&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The second &lt;code&gt;Breakpoint&lt;/code&gt; wrapper will render only between the viewport sizes of 991px and 577px because its breakpoint size is set as &lt;code&gt;medium&lt;/code&gt;. And the CSS that goes with it is conditionally rendered by being wrapped inside the class of &lt;code&gt;.breakpoint__medium-only&lt;/code&gt;. This CSS class is added by the addition of the React Socks &lt;code&gt;Breakpoint&lt;/code&gt; package — no modification by you is necessary.&lt;/p&gt;
&lt;p&gt;And the third will render whenever the viewport is 576px or smaller because it’s set as &lt;code&gt;small down&lt;/code&gt; inside the &lt;code&gt;Breakpoint&lt;/code&gt; component. And, likewise, the CSS for including &lt;code&gt;grid-template-columns: repeat(2, 1fr);&lt;/code&gt; will only ever render at that viewport size as well.&lt;/p&gt;
&lt;p&gt;This kind of conditional rendering of components can shrink the CSS bundle size and clean up the CSS being loaded into the browser significantly by only loading what the view requires and nothing else.&lt;/p&gt;
&lt;h2&gt;How I used React Socks in my React app&lt;/h2&gt;
&lt;p&gt;Along with the conference talk we gave, there were three React movie demo sites I built to illustrate my point, using the &lt;a href=&quot;https://developers.themoviedb.org/3/getting-started/introduction&quot;&gt;Movie Database API&lt;/a&gt; for a data source.&lt;/p&gt;
&lt;p&gt;The first site was completely unresponsive to show the poor user experience across multiple devices.&lt;/p&gt;
&lt;p&gt;The second site was built with CSS media queries, making it responsive for tablet and mobile. And the third site was built using the React-specific responsive library React Socks to make it responsive.&lt;/p&gt;
&lt;p&gt;This third demo is what I’m showing snippets of code from in this piece. If you’d like to see the whole codebase, it’s available on &lt;a href=&quot;https://github.com/paigen11/movie-demo-3&quot;&gt;GitHub&lt;/a&gt;, and if you’d like to see a live version of the site, it’s available &lt;a href=&quot;https://movie-demo-3.paigen11.now.sh/&quot;&gt;at this URL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So above was one example of how to use React Socks, but let me show you another example where it really shines. When you have quite different layouts or components, you need to render based on viewport size. This is where React Socks excels.&lt;/p&gt;
&lt;h3&gt;Basic component example&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Desktop and tablet views&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here are two screenshots of my movie app in both desktop and tablet size, showing the header-based navigation bar present throughout the app.&lt;/p&gt;
&lt;p&gt;For both of the larger sizes, the links to the different pages are always visible (&lt;code&gt;Now Playing&lt;/code&gt;, &lt;code&gt;Coming Soon&lt;/code&gt;, &lt;code&gt;Movie Search&lt;/code&gt;, and &lt;code&gt;Genres&lt;/code&gt; — plus a link back to the &lt;code&gt;Dashboard&lt;/code&gt; landing page on the far right side).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Desktop view&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-socks/desktop-view.webp&quot; alt=&quot;Desktop version of movie app&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A page in my application using the desktop Header component for the navigation bar&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And here’s the tablet view. Once again, there’s enough room across the top for all the links to be present.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tablet view&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-socks/tablet-view.webp&quot; alt=&quot;Tablet version of movie app&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The same page in tablet view, still using the Header.js component for the navigation bar.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Now, here’s a shot of the React JSX that goes along with those views.&lt;/p&gt;
&lt;p&gt;As you can see, the &lt;code&gt;Breakpoint&lt;/code&gt; wrapper uses &lt;code&gt;medium up&lt;/code&gt; to display the header, while the viewport is 577px and above. When the viewport is smaller than that, React Socks makes it possible to render a completely different component named &lt;code&gt;&amp;lt;Sidebar&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Header.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const Header = () =&amp;gt; {
  return (
    &amp;lt;nav className=&quot;navbar-wrapper&quot;&amp;gt;
      &amp;lt;Breakpoint medium up&amp;gt;
        &amp;lt;ul className=&quot;navbar-links&quot;&amp;gt;
          &amp;lt;li className=&quot;navbar-link-logo&quot;&amp;gt;
            &amp;lt;NavLink to=&quot;/&quot;&amp;gt;
              &amp;lt;img src={TmdbIcon} alt=&quot;logo&quot; /&amp;gt;
            &amp;lt;/NavLink&amp;gt;
          &amp;lt;/li&amp;gt;
          &amp;lt;div className=&quot;navbar-top-links&quot;&amp;gt;
            &amp;lt;li className=&quot;navbar-link&quot;&amp;gt;
              &amp;lt;NavLink to=&quot;/nowplaying&quot;&amp;gt;Now Playing&amp;lt;/NavLink&amp;gt;
            &amp;lt;/li&amp;gt;
            &amp;lt;li className=&quot;navbar-link&quot;&amp;gt;
              &amp;lt;NavLink to=&quot;/upcoming&quot;&amp;gt;Coming Soon&amp;lt;/NavLink&amp;gt;
            &amp;lt;/li&amp;gt;
            &amp;lt;li className=&quot;navbar-link&quot;&amp;gt;
              &amp;lt;NavLink to=&quot;/search&quot;&amp;gt;Movie Search&amp;lt;/NavLink&amp;gt;
            &amp;lt;/li&amp;gt;
            &amp;lt;li className=&quot;navbar-link&quot;&amp;gt;
              &amp;lt;NavLink to=&quot;/genres&quot;&amp;gt;Genres&amp;lt;/NavLink&amp;gt;
            &amp;lt;/li&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/Breakpoint&amp;gt;
      &amp;lt;Breakpoint small down&amp;gt;
        &amp;lt;Sidebar /&amp;gt;
      &amp;lt;/Breakpoint&amp;gt;
    &amp;lt;/nav&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sidebar component switched in with React Socks&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Mobile size&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But here is a screenshot of what the same header looks like in mobile view: It turns into a sidebar that slides in from the left with the same links available when a user taps the hamburger bar in the top-right corner.&lt;/p&gt;
&lt;p&gt;And, once again, the link back to the homepage (the &lt;code&gt;Dashboard&lt;/code&gt; page) is now in the right-hand corner.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-socks/mobile-view.webp&quot; alt=&quot;Mobile version of movie app&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The mobile view page in the application using the Sidebar.js component.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This view is actually rendered by the &lt;code&gt;Header&lt;/code&gt; component’s child component, &lt;code&gt;Sidebar&lt;/code&gt;, because &lt;code&gt;Sidebar&lt;/code&gt; is wrapped inside of the React Socks breakpoint of &lt;code&gt;small down&lt;/code&gt;. As long as the viewport size is under 576px, the &lt;code&gt;Sidebar&lt;/code&gt; component will render instead of the &lt;code&gt;Header&lt;/code&gt; — with its links across the top.&lt;/p&gt;
&lt;p&gt;Here is the JSX for the &lt;code&gt;Sidebar&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Sidebar.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const Sidebar = () =&amp;gt; {
  const [expandedLinks, setExpandedLinks] = useState(false);

  const toggleLinks = () =&amp;gt; () =&amp;gt; {
    setExpandedLinks(!expandedLinks);
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;ul className=&quot;sidebar-top&quot;&amp;gt;
        &amp;lt;div className=&quot;sidebar-links&quot;&amp;gt;
          &amp;lt;li className=&quot;sidebar-link bars&quot; onClick={toggleLinks()}&amp;gt;
            &amp;lt;i className=&quot;fa fa-bars&quot; aria-hidden=&quot;true&quot; /&amp;gt;
          &amp;lt;/li&amp;gt;
          &amp;lt;li
            className=&quot;sidebar-link-logo&quot;
            onClick={() =&amp;gt; setExpandedLinks(false)}
          &amp;gt;
            &amp;lt;NavLink to=&quot;/&quot;&amp;gt;
              &amp;lt;img src={TmdbIcon} alt=&quot;logo&quot; /&amp;gt;
            &amp;lt;/NavLink&amp;gt;
          &amp;lt;/li&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/ul&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;li className=&quot;sidebar-link&quot; onClick={() =&amp;gt; setExpandedLinks(false)}&amp;gt;
            &amp;lt;NavLink to=&quot;/nowplaying&quot;&amp;gt;Now Playing&amp;lt;/NavLink&amp;gt;
          &amp;lt;/li&amp;gt;
          &amp;lt;li className=&quot;sidebar-link&quot; onClick={() =&amp;gt; setExpandedLinks(false)}&amp;gt;
            &amp;lt;NavLink to=&quot;/upcoming&quot;&amp;gt;Coming Soon&amp;lt;/NavLink&amp;gt;
          &amp;lt;/li&amp;gt;
          &amp;lt;li className=&quot;sidebar-link&quot; onClick={() =&amp;gt; setExpandedLinks(false)}&amp;gt;
            &amp;lt;NavLink to=&quot;/search&quot;&amp;gt;Movie Search&amp;lt;/NavLink&amp;gt;
          &amp;lt;/li&amp;gt;
          &amp;lt;li className=&quot;sidebar-link&quot; onClick={() =&amp;gt; setExpandedLinks(false)}&amp;gt;
            &amp;lt;NavLink to=&quot;/genres&quot;&amp;gt;Genres&amp;lt;/NavLink&amp;gt;
          &amp;lt;/li&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, imagine trying to make those two very different components into one that could work well at both desktop and mobile sizes. It might be possible, but the JSX would be messy and the CSS even messier.&lt;/p&gt;
&lt;p&gt;React Socks makes it so much easier to simply switch out complete components, making for cleaner code and easier development.&lt;/p&gt;
&lt;h2&gt;Pros and Cons of React Socks&lt;/h2&gt;
&lt;p&gt;I’ve covered a few different examples of how to use React Socks to switch React components in and out based on the viewport size, but I feel it’s important to talk about some of the benefits and drawbacks that come along with them.&lt;/p&gt;
&lt;p&gt;As I alluded to above, for some situations they can be a great solution, but they may not perfect for solving every responsive design need.&lt;/p&gt;
&lt;p&gt;Let’s talk about the highlights first.&lt;/p&gt;
&lt;h3&gt;Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ideal when you have very different components or layouts to render based on viewport size — as you’ve seen in the header/sidebar example above, the desktop and mobile views and functionality are quite different.
&lt;ul&gt;
&lt;li&gt;Trying to shoehorn those into one component and use pure CSS media queries to show and hide different pieces of the component at different screen sizes would have been messy and more complex.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Custom breakpoints can be named and set — if you need more specific breakpoints than the default set by React Socks, it’s easy.
&lt;ul&gt;
&lt;li&gt;If you wanted a breakpoint for extra, extra large monitors, you could simply name it &lt;code&gt;giantMonitor&lt;/code&gt; and set a viewport size with it. Likewise, if you wanted one called &lt;code&gt;pizza&lt;/code&gt; or &lt;code&gt;bicycle&lt;/code&gt;, you could do that too. It’s totally up to you and your needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Less CSS is rendered per view than with media queries — as I mentioned before, React Socks &lt;em&gt;only&lt;/em&gt; renders the component that’s wrapped within its &lt;code&gt;Breakpoint&lt;/code&gt; tags (and the CSS that goes along with it).
&lt;ul&gt;
&lt;li&gt;Smaller CSS bundle sizes can mean faster page load times, especially for mobile users, resulting in a better user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;React Socks only has one major drawback I identified while trying it out.&lt;/p&gt;
&lt;h3&gt;Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The biggest drawback to React Socks: It can be overkill for code that keeps its same structure and just needs to adjust its height, width, margin, padding, etc.
&lt;ul&gt;
&lt;li&gt;For minimal changes that keep the same layout and DOM elements, it may be quicker to just add some more CSS wrapped in a media query instead of having to define the same component multiple times wrapped in &lt;code&gt;Breakpoint&lt;/code&gt; tags and the CSS to go with it.&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that’s really the only thing I can point out when you’re considering whether to employ React Socks or not.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Responsive web design is of paramount importance to every designer and developer in today’s multidevice world. We can’t even imagine some of the scenarios where applications might be used, and we can’t afford to give users a bad experience — because our competitors won’t.&lt;/p&gt;
&lt;p&gt;There are plenty of solutions out there, but one of the approaches I chose to investigate is using the React-specific library React Socks to make sites responsive. It’s specifically tailored to work with the React framework, and it’s very easy to get started with.&lt;/p&gt;
&lt;p&gt;React Socks renders only the components and CSS necessary for the viewport and nothing else, it’s easy to create custom breakpoints if needed, and it provides an option for cleaner, easier-to-read code and better app performance. This is a really good option for your responsive needs.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, ES6, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I hope you’ll consider React Socks as you’re designing and building your own responsive React-based web applications. It’s a powerful, versatile solution.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/movie-demo-3&quot;&gt;GitHub repo, React app with React Socks for responsive design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://movie-demo-3.paigen11.now.sh/&quot;&gt;Responsive movie app site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2011/01/guidelines-for-responsive-web-design/&quot;&gt;Responsive web design, Smashing Magazine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://drive.google.com/drive/folders/1oRtHrgzpPorn9ogGpAxA5lPrH3ycCYK9&quot;&gt;Responsive design featuring React.js presentation deck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-socks&quot;&gt;React Socks, npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category><category>css</category></item><item><title>Pure CSS Media Queries and Responsive Web Design With React</title><link>https://www.paigeniedringhaus.com/blog/pure-css-media-queries-and-responsive-web-design-with-react/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/pure-css-media-queries-and-responsive-web-design-with-react/</guid><description>Build your webpages and apps to suit your user’s device’s size.</description><pubDate>Mon, 20 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import CodePen from &apos;../../src/components/CodePen.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-media-queries-react/multi-screens-hero.webp&quot; alt=&quot;Multiple different devices all with different sized screens on a desk&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Recently, I gave a talk with a coworker at the tech conference &lt;a href=&quot;https://connect.tech/&quot;&gt;Connect.Tech&lt;/a&gt; about the ever-increasing need for responsive web design when building applications, and then a couple of different ways to approach it, specifically when it comes to the JavaScript framework, React.&lt;/p&gt;
&lt;p&gt;In case you’re not familiar with the term, let me quickly define &lt;strong&gt;responsive web design&lt;/strong&gt; so we’re all starting at the same place. The best definition I’ve found comes straight from &lt;a href=&quot;https://www.smashingmagazine.com/&quot;&gt;Smashing Magazine&lt;/a&gt;, a leading editorial voice for web developers and web designers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Responsive web design is the approach that suggests that design and development should respond to the user’s behavior and environment based on screen size, platform, and orientation.&quot; &lt;a href=&quot;https://www.smashingmagazine.com/2011/01/guidelines-for-responsive-web-design/&quot;&gt;— Smashing Magazine&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It should already make sense why this would be more and more necessary in today’s world to start with responsive design for multiple browser/device sizes in mind as you build applications, but in case you’d like a few statistics, here are some that should help to convince you.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“In 2018, 52.2% of all website traffic worldwide was generated through mobile phones, up from 50.3% in the previous year.&quot; &lt;a href=&quot;https://www.statista.com/statistics/241462/global-mobile-phone-website-traffic-share/&quot;&gt;— Statista&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;On average, 88% of global consumers report they multiscreen, using 2.42 devices at the same time.&quot; &lt;a href=&quot;https://blogs.adobe.com/creative/files/2015/12/Adobe-State-of-Content-Report.pdf&quot;&gt;— Adobe&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or consider this chart from August 2018-August 2019 showing the average screen sizes of users worldwide.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-media-queries-react/resolution-stats.webp&quot; alt=&quot;Chart of desktop, mobile, and tablet screen resolution stats worldwide&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Data source: GlobalStats August 2018 — August 2019.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In 2020 and beyond, all signs point to a need for responsive design to meet users where ever they are.&lt;/p&gt;
&lt;p&gt;While I won’t go into all the details in our talk of how to approach responsive design (if you’d like, you can see the &lt;a href=&quot;https://t.co/WFHmJsDZ4d?amp=1&quot;&gt;full slide deck of the talk&lt;/a&gt;), I would like to share two possible approaches to responsive design for anyone else looking to get started with it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will cover the first solution for responsive web design, which would really work for any JavaScript application as long as it’s using CSS for its styling: CSS media queries.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;What are CSS media queries?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3schools.com/cssref/css3_pr_mediaquery.asp&quot;&gt;&lt;strong&gt;Media queries&lt;/strong&gt;&lt;/a&gt; are a popular technique for delivering a tailored style sheet (responsive web design) to desktops, laptops, tablets, and mobile phones.&lt;/p&gt;
&lt;p&gt;CSS media queries are usually used to check things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Width and height of the viewport.&lt;/li&gt;
&lt;li&gt;Width and height of the device.&lt;/li&gt;
&lt;li&gt;Orientation (is the device in landscape or portrait mode?).&lt;/li&gt;
&lt;li&gt;Resolution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They can also be used to specify that certain styles are only for printed documents or for screen readers.&lt;/p&gt;
&lt;h3&gt;Anatomy of a CSS media query&lt;/h3&gt;
&lt;p&gt;But by far the most common uses for media queries fall into the first set of bullet points above: checking viewport and device widths and heights to know which CSS styling to serve up.&lt;/p&gt;
&lt;p&gt;And here’s an example of what the CSS media query code will look like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Typical example of a CSS media query&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media only screen and (min-width: 375px) and (max-width: 969px) {  
  body { 
    background: green;
    font-size: 16px;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;@media&lt;/code&gt; rule, introduced with CSS3, is used to apply different styles for different media types/devices. &lt;code&gt;only screen&lt;/code&gt; applies to all computer screens, tablets, smartphones, etc.&lt;/p&gt;
&lt;p&gt;In the example above, this start specifies that the CSS styles &lt;code&gt;( background: green and font-size: 16px )&lt;/code&gt; defined within will only apply to the &lt;code&gt;body&lt;/code&gt; HTML tag for screens between the sizes of at least 375px (&lt;code&gt;min-width: 375px&lt;/code&gt;), all the way up to screens of 969px (&lt;code&gt;max-width: 969px&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This is a very basic example, but CSS media queries are incredibly powerful. They can be used to show and hide different elements of the DOM, resize fonts, and switch around whole page layouts with relative ease.&lt;/p&gt;
&lt;p&gt;Before I show you how I used them though, let’s talk about the two basic design approaches to take with media queries.&lt;/p&gt;
&lt;h2&gt;Approaches to CSS media queries&lt;/h2&gt;
&lt;p&gt;There are two common approaches to writing CSS media queries. They’re known as &lt;strong&gt;subtractive CSS&lt;/strong&gt; and &lt;strong&gt;additive CSS&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Neither one is really better than the other, it depends more on the main audience of the application to help determine which approach is right for you.&lt;/p&gt;
&lt;p&gt;Questions to help figure this out might include: &quot;Will it be used more on mobile devices or desktops, or will it be a large group of diverse users, or a small internal group of users within a company?&quot; Things like that.&lt;/p&gt;
&lt;p&gt;Here are more details about the two approaches.&lt;/p&gt;
&lt;h3&gt;Subtractive CSS&lt;/h3&gt;
&lt;p&gt;The first approach, subtractive CSS, is the one that’s probably more commonly taken with applications that will have smaller, more homogenous user bases.&lt;/p&gt;
&lt;p&gt;Think internal applications used within organizations for very specific purposes, that oftentimes can only be accessed from a specific device — either because of company firewalls and networks or hardwired terminals, etc.&lt;/p&gt;
&lt;p&gt;Subtractive CSS generally starts with the comps and screen styles at the largest resolution first. It begins with the largest displays, and then media queries are added to &lt;em&gt;undo&lt;/em&gt; unneeded CSS for the smaller viewports.&lt;/p&gt;
&lt;p&gt;Basically, it puts in a bunch of styling that undoes some of the more complex layouts that have been laid out at a higher resolution.&lt;/p&gt;
&lt;p&gt;Even though it has subtractive in the name, it usually results in more lines of CSS having to override underlying styles.&lt;/p&gt;
&lt;p&gt;Here’s a CodePen you can look at, illustrating subtractive CSS at work. Check out the amount of CSS I had to add to undo the layout from a widescreen view to accommodate a smaller viewport.&lt;/p&gt;
&lt;p&gt;If you expand and shrink the viewport, you can watch the styles change for large screen, tablet, and mobile.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Subtractive CSS demo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;CodePen url=&quot;https://codepen.io/paigen11/pen/KKwGbJw&quot; /&amp;gt;&lt;/p&gt;
&lt;h3&gt;Additive CSS&lt;/h3&gt;
&lt;p&gt;Additive CSS is the opposite of subtractive, as the name implies. With additive CSS, you start with the smallest resolution styling first and add media queries to &lt;em&gt;build up&lt;/em&gt; the CSS as the screen size increases.&lt;/p&gt;
&lt;p&gt;It begins simply, and gets more complicated with the layout as horizontal screen real estate increases.&lt;/p&gt;
&lt;p&gt;Additive CSS is probably the more recommended way to begin designing a new application in general. It will make the amount of CSS being loaded at different breakpoints smaller if it&apos;s designed mobile-first and has less CSS to override and undo (better for your end-user experience).&lt;/p&gt;
&lt;p&gt;Also, there’s a very good chance users will be accessing the application from a whole variety of different screen sizes and devices you can’t even imagine, and having contingency categories they’ll fall into is vital.&lt;/p&gt;
&lt;p&gt;Here’s another CodePen showing additive CSS at work. You can see that in this example, I start with the smallest viewport first, and slowly add more details and layout complexity as the viewport size increases under media queries.&lt;/p&gt;
&lt;p&gt;Try playing with the viewport size to see the CSS changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Additive CSS demo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;CodePen url=&quot;https://codepen.io/paigen11/pen/BayqMzX&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;I know that both of these examples may seem rather simplistic, but just imagine a larger, multi-screen application (heck, look at most of the apps you use on your phone and your laptop on a regular basis), and think about how you might build them using either approach.&lt;/p&gt;
&lt;h2&gt;How I used CSS media queries with React&lt;/h2&gt;
&lt;p&gt;Along with the conference talk we gave, there were three React movie demo sites I built to illustrate my point, using the &lt;a href=&quot;https://developers.themoviedb.org/3/getting-started/introduction&quot;&gt;Movie Database API&lt;/a&gt; for a data source.&lt;/p&gt;
&lt;p&gt;The first site was completely unresponsive to show the poor user experience across multiple devices.&lt;/p&gt;
&lt;p&gt;The second site was built with CSS media queries making it responsive for tablet and mobile.&lt;/p&gt;
&lt;p&gt;And the third site was built using a React-specific responsive library called &lt;a href=&quot;https://github.com/flexdinesh/react-socks&quot;&gt;React-socks&lt;/a&gt;, to make it responsive.&lt;/p&gt;
&lt;p&gt;This second demo is what I’ll be showing snippets of code from in this blog. If you’d like to see the whole codebase, it’s available on &lt;a href=&quot;https://github.com/paigen11/movie-demo-2&quot;&gt;GitHub&lt;/a&gt;, and if you’d like to see a live version of the site, it’s available &lt;a href=&quot;https://movie-demo-2.paigen11.vercel.app/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Basic component example&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Desktop view&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I’ll be showing you a portion of the CSS for the &lt;code&gt;MovieDetails&lt;/code&gt; React component in my application. Here’s what the desktop page looks like that uses this component.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-media-queries-react/movie-details.webp&quot; alt=&quot;Screenshot of movie details page on desktop showing title, poster, details, and reviews&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As you can see from the screenshot, at desktop size the layout is pretty complex: movie poster backdrop, the official trailer poster on the left side, the movie synopsis, release date, ratings and reviews on the right side, etc.&lt;/p&gt;
&lt;p&gt;And here is a snippet of the CSS involved to make the layout for the movie poster happen. This was the base CSS I used to build my smaller screen views from. Yes, this is an example of subtractive CSS.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MovieDetails.scss&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.movie-details-poster-wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 3% 450px 450px 80px;
  grid-gap: 15px;
  justify-items: center;

  .movie-details-poster {
    border-radius: 10px;
    border: solid #847f86 10px;
    grid-row: 2;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the code, you see I’m using a &lt;a href=&quot;https://css-tricks.com/snippets/css/complete-guide-grid/&quot;&gt;CSS Grid&lt;/a&gt; layout here for the desktop layout. Now, let’s see how the view and component’s CSS changes as the screen size shrinks.&lt;/p&gt;
&lt;h3&gt;Same component with media queries&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Tablet view&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here is the look of that same React component MovieDetails at tablet size.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-media-queries-react/movie-details-tablet.webp&quot; alt=&quot;Screenshot of movie details page on tablet showing title, poster, details, and reviews&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;At tablet viewport size, the movie poster gets centered in the viewport and the synopsis, ratings, and reviews slide underneath it.&lt;/p&gt;
&lt;p&gt;Here’s what a portion of the CSS looks like that goes with this view.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MovieDetails.scss&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media only screen and (min-width: 550px) and (max-width: 1089px) {
    .movie-details-poster-wrapper {
      display: flex;
      flex-direction: column;
      align-items: center;
    
    .movie-details-poster {
        margin: 20px 0;
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the tablet view, the CSS layout switches from Grid, which is a two-dimensional way of designing layouts to &lt;a href=&quot;https://css-tricks.com/snippets/css/a-guide-to-flexbox/&quot;&gt;CSS Flexbox&lt;/a&gt;, which is a more one-dimensional way of arranging layouts. More appropriate for a view where each element is just laid out in order, one after another.&lt;/p&gt;
&lt;p&gt;Straightforward enough.&lt;/p&gt;
&lt;p&gt;On to the last example: the mobile view.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mobile view&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-media-queries-react/movie-details-mobile.webp&quot; alt=&quot;Screenshot of movie details page on mobile showing title, poster, details, and reviews&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The mobile view more closely resembles the tablet view for the &lt;code&gt;MovieDetails&lt;/code&gt; React component. Once again, the movie poster is front and center, the overview and ratings come after.&lt;/p&gt;
&lt;p&gt;For mobile, the font size has also increased and now there’s a toggle on the reviews to &quot;Read more...&quot; instead of the user being able to scroll through the whole review from the start as they can at larger view sizes.&lt;/p&gt;
&lt;p&gt;Here’s the last example of the CSS that accompanies it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MovieDetails.scss&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media only screen and (max-width: 549px) {
    .movie-details-poster-wrapper {
      display: flex;
      flex-direction: column;
      align-items: center;

    .movie-details-poster {
        width: 300px;
        margin: 20px 0;
        overflow-y: scroll;
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the &lt;code&gt;.movie-details-poster-wrapper&lt;/code&gt;&apos;s display property stays in CSS Flexbox at this viewport size, and its &lt;code&gt;flex-direction&lt;/code&gt; remains &lt;code&gt;column&lt;/code&gt; so that all the child elements contained within line up nicely.&lt;/p&gt;
&lt;p&gt;You’ll notice though that for this view, the &lt;code&gt;.movie-details-poster&lt;/code&gt; has a width property set to keep it from going beyond the width of the viewport (the actual image supplied from TMDB’s API is 500px large, by default), along with its other styling properties.&lt;/p&gt;
&lt;p&gt;Makes sense? Good, now I’ll give a quick overview of the pros and cons I encountered while using CSS media queries.&lt;/p&gt;
&lt;h2&gt;Pros and Cons of CSS media queries&lt;/h2&gt;
&lt;p&gt;I’ve covered the basics of CSS media queries and how you’d use them with a component in React, but I feel it’s important to talk about some of the benefits and drawbacks that come along with them.&lt;/p&gt;
&lt;p&gt;Sometimes they can be a great solution, but they may not perfect for solving every responsive design problem.&lt;/p&gt;
&lt;p&gt;Let’s start with the highlights.&lt;/p&gt;
&lt;h3&gt;Benefits of CSS media queries&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Great when reusing the same components just slightly in different layouts — as long as the location or visibility of elements within a component doesn’t differ too much, CSS media queries should be able to do the job. When completely new components need to be added at different viewport sizes, the JavaScript and JSX component code can start to get complicated.&lt;/li&gt;
&lt;li&gt;Breakpoints can be reused across components — this is a nice time-saver. Oftentimes, the breakpoints for viewports you’ll set for one component will also make sense for other components, so there’s less need to reinvent the wheel for each page of an application.&lt;/li&gt;
&lt;li&gt;Separation of concerns — for people who aren’t in the camp of CSS-in-JS (and I know there’s plenty), CSS media queries provide a nice separation of logic and presentation. The CSS strictly handles the layout, and the JavaScript and React framework handles the data fetching and logic manipulation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But while there are a lot of good points about CSS media queries, there are some shortcomings.&lt;/p&gt;
&lt;h3&gt;Drawbacks of CSS media queries&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CSS can get long and messy quickly — if you’ve got three or more breakpoint sizes for one component and you’re using more of a subtractive style of CSS, your CSS file can get long.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;For instance, the &lt;code&gt;MovieDetails.scss&lt;/code&gt; file I referenced for my examples above, is 176 lines long before being bundled up by &lt;a href=&quot;https://webpack.js.org/&quot;&gt;webpack&lt;/a&gt; for deployment. And that’s a relatively less-complex example, it can get much more complicated than that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Very different layouts from one size to another requires duplicated code with &lt;code&gt;display: none&lt;/code&gt; to achieve results.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;This one is pretty self-explanatory, but if you’ve got a desktop layout with a &lt;code&gt;title&lt;/code&gt; element at the top then an image underneath, but the mobile layout has an image above the &lt;code&gt;title&lt;/code&gt;, there’s probably no way to write the JSX so you don’t end up duplicating &lt;code&gt;title&lt;/code&gt; in two places in the code. This means duplicate elements in one component at different viewport levels — which means less readability and more complexity in maintaining your code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CSS media queries are great, but they’re not always the right answer and it’s important for you to know that before employing them.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Responsive web design is something every designer and developer needs to be thinking of today. We can’t even imagine some of the scenarios where applications might be used, and we can’t afford to give users a bad experience, because our competitors won’t.&lt;/p&gt;
&lt;p&gt;There are plenty of solutions out there, but one of the approaches I chose to investigate is using CSS media queries within a React application. They’re native to CSS3, which means, regardless of your JavaScript framework, as long as it uses CSS for the styling, you can leverage them.&lt;/p&gt;
&lt;p&gt;To implement them requires very little extra CSS, at least initially. And if you structure the CSS right (with an additive CSS approach that builds up as the screens get larger), the mobile CSS bundle size can be pretty small meaning a faster load time for users and a better experience. It’s a pretty solid option.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing the second piece of this series on responsive design with React.js. This piece will focus on a React-specific solution for making sites responsive.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll give CSS media queries consideration as you’re designing and building your own responsive web applications. They’re a powerful, versatile solution.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/movie-demo-2&quot;&gt;GitHub repo, React app with CSS media queries for responsive design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://movie-demo-2.paigen11.now.sh/&quot;&gt;Responsive movie app site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2011/01/guidelines-for-responsive-web-design/&quot;&gt;Responsive web design, Smashing Magazine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://drive.google.com/drive/folders/1oRtHrgzpPorn9ogGpAxA5lPrH3ycCYK9&quot;&gt;Responsive design featuring React.js presentation deck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/cssref/css3_pr_mediaquery.asp&quot;&gt;Media queries, W3 Schools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/snippets/css/complete-guide-grid/&quot;&gt;CSS Grid reference, CSS Tricks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/snippets/css/a-guide-to-flexbox/&quot;&gt;CSS Flexbox, CSS Tricks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category><category>css</category></item><item><title>JavaScript Error Handling from Express.js to React</title><link>https://www.paigeniedringhaus.com/blog/javascript-error-handling-from-expressjs-to-react/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/javascript-error-handling-from-expressjs-to-react/</guid><description>Because errors are bound to happen and we need to handle them correctly.</description><pubDate>Mon, 23 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/js-error-handling/stop-signs-hero.webp&quot; alt=&quot;Stop signs in many flavors&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I&apos;ve used a full stack &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;MERN (MySQL, Express, React and Node.js) project&lt;/a&gt; I made from scratch for a whole handful of blog posts now. As I slowly built it out and added more bells and whistles to it, I learned a slew of new things worth sharing to help other devs avoid obstacles that I ran into along the way.&lt;/p&gt;
&lt;p&gt;Past topics included using &lt;a href=&quot;./sequelize-like-mongoose-but-for-sql&quot;&gt;Sequelize&lt;/a&gt; as the ORM for a MySQL database, using &lt;a href=&quot;./implementing-json-web-tokens-passport-js-in-a-react-app&quot;&gt;PassportJS and JWT&lt;/a&gt; for authentication and protected routes, using &lt;a href=&quot;./password-reset-emails-in-your-react-app-made-easy-with-nodemailer&quot;&gt;Nodemailer&lt;/a&gt; to provide password reset capability via email, etc. Honestly, working through building this application, just for the sake of learning more Node, more React, more core JavaScript, taught me &lt;em&gt;so&lt;/em&gt; much.&lt;/p&gt;
&lt;p&gt;If you want to see the rest of my posts pertaining to this repo and the code itself, I’ll link to them all at the bottom of this article.&lt;/p&gt;
&lt;p&gt;And today’s post is no exception.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I’m talking about how to properly handle errors on both sides of a JavaScript application: from throwing errors on the server side in Express, to catching and handling them on the client side with React and Axios.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Express error handling&lt;/h3&gt;
&lt;p&gt;Since the server side is where the majority of the errors occur from, starting with the Node.js / Express server code is where I’ll begin as well.&lt;/p&gt;
&lt;p&gt;I must confess, for quite a while, in the course of building this app, I passed back &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status&quot;&gt;HTTP 200 status&lt;/a&gt; (the OK status) codes from the Express server even when an error like a missing JWT token or user ID was not found in the database.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Improper Express error handling example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res.status(200).json(&quot;404 - no user exists in db to update&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I did this because I wanted to send not just a 401 (unauthorized) or 403 (forbidden) HTTP status code, but because I also wanted to send a written message of what exactly the error was on the server side, and for the longest time, I couldn’t find out how to do both with Express.&lt;/p&gt;
&lt;p&gt;It was either send an error message through &lt;code&gt;res.json(&quot;This is an error message the client can read&quot;)&lt;/code&gt; with a 200 HTTP status, or send a 401 or 403 HTTP status with no further info on what actually went wrong with a &lt;code&gt;res.status(401)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then one day, finally, I found the solution I was looking for buried deep in the &lt;a href=&quot;https://expressjs.com/en/guide/error-handling.html&quot;&gt;Express documentation&lt;/a&gt;, of which there is quite a lot. And it really wasn’t as tricky as I thought — it was similar to how I sent a message along with a 200 HTTP status when something went right, like so:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Express success status code message example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res.status(200).send({ message: &quot;user created&quot; });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could do the same with an error status and message.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Express failure status code and message example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res.status(401).send(&quot;no user exists in db to update&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just by switching from Express’s &lt;code&gt;.json()&lt;/code&gt; to &lt;code&gt;.send()&lt;/code&gt; method meant I could chain together an HTTP error code &lt;em&gt;and&lt;/em&gt; informational message for the client to decipher and then handle appropriately on the browser side. 😄&lt;/p&gt;
&lt;p&gt;It is worth noting that &lt;a href=&quot;https://expressjs.com/en/api.html#res.send&quot;&gt;&lt;code&gt;.send()&lt;/code&gt;&lt;/a&gt; can handle objects, strings, or arrays in JavaScript. The success message example is in the shape of an object with the property of &lt;code&gt;message&lt;/code&gt; while the failure response is just a string because in the event of a successful response things like a message, a JSON Web Token or other data might be sent over to the client from the server. My errors, however, needed nothing more than an HTTP response and error message as a string. Just so you know for the future. 🙂&lt;/p&gt;
&lt;p&gt;Below is an example of one of the server side routes in my application showing the full implementation of sending either a success or failure when a user tries to update their personal info while logged in. (I’ve chosen to include it as both the nicely formatted and highlighted image from VS Code and a copy-able code snippet).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;updateUser.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = (app) =&amp;gt; {
  app.put(&quot;/updateUser&quot;, (req, res, next) =&amp;gt; {
    passport.authenticate(&quot;jwt&quot;, { session: false }, (err, user, info) =&amp;gt; {
      if (err) {
        console.error(err);
      }
      if (info !== undefined) {
        console.error(info.message);
        res.status(403).send(info.message);
      } else {
        User.findOne({
          where: {
            username: req.body.username,
          },
        }).then((userInfo) =&amp;gt; {
          if (userInfo != null) {
            console.log(&quot;user found in db&quot;);
            userInfo
              .update({
                first_name: req.body.first_name,
                last_name: req.body.last_name,
                email: req.body.email,
             })
            .then(() =&amp;gt; {
              console.log(&quot;user updated&quot;);
              res.status(200).send({ auth: true, message: &quot;user updated&quot; });
            });
         } else {
          console.error(&quot;no user exists in db to update&quot;);
          res.status(401).send(&quot;no user exists in db to update&quot;);
         }
       });
      }
    })(req, res, next);
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let me quickly break down what’s happening in this file.&lt;/p&gt;
&lt;p&gt;The first thing that happens when the route is hit is that PassportJS takes over and checks to see if the user’s JSON Web Token both exists and is valid, this happens in another file and is covered in a different &lt;a href=&quot;./implementing-json-web-tokens-passport-js-in-a-react-app&quot;&gt;blog post&lt;/a&gt; so I won’t go in depth about that now.&lt;/p&gt;
&lt;p&gt;Once a user’s been authenticated, the route goes through the process of attempting to find that &lt;code&gt;username&lt;/code&gt; in the MySQL database, and if it is found, the user info is updated and a success message with HTTP status 200 and a message of &lt;code&gt;&quot;user updated&quot;&lt;/code&gt; is sent back.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;username&lt;/code&gt; is not found in the database the server logs that the error that the user doesn’t exist and sends back a 401 HTTP status and message that &lt;code&gt;&quot;no user exists in db to update&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s exactly what gets logged on the server side console that you’d see looking through the logs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Error Express throws in the server logs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The main piece of code to focus on in terms of the error handling is this block right here towards the bottom of the file.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/js-error-handling/express-error-logs.webp&quot; alt=&quot;Express error logs&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The error printed out to the server’s console and sent to the client side.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;That’s about all there is to successfully sending both bad status codes and messages from Express to the browser. Now let’s talk about how the browser handles those errors.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  console.error(&quot;no user exists in db to update&quot;);
  res.status(401).send(&quot;no user exists in db to update&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;React &amp;amp; Axios error handling&lt;/h3&gt;
&lt;p&gt;For the client side of my full stack application I chose to use the extremely popular promise based HTTP library &lt;a href=&quot;https://www.npmjs.com/package/axios&quot;&gt;Axios&lt;/a&gt; instead of the browser’s native &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch&quot;&gt;Fetch API&lt;/a&gt;, as I find it easier to work with. This example will be shown using Axios for all HTTP requests and error handling.&lt;/p&gt;
&lt;p&gt;Just as I was slowly improving the error handling on the server side, I was also improving my error handling on the client side as my application progressed and improved.&lt;/p&gt;
&lt;p&gt;Before I properly handled the errors the server threw, this was all I was doing to interpret errors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Poorly handling errors thrown from the server to the client example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  .catch(error =&amp;gt; {        
    console.log(error.data);             
    this.setState({         
      loadingUser: false,         
      error: true,       
    });
  });

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I would attempt to catch an error, log its message out to the console and then set the React application’s state accordingly. Not terrible for a start, but also not great for a final solution — the second I would try to throw something outside of a 200 HTTP status with a message, the client would just blow up in the &lt;code&gt;catch()&lt;/code&gt; block.&lt;/p&gt;
&lt;p&gt;And just like with the server side, I finally got tired of this half baked error handling I was doing and found some better &lt;a href=&quot;https://github.com/axios/axios#handling-errors&quot;&gt;Axios documentation&lt;/a&gt; around how the library wants you to handle errors, which I’d overlooked before.&lt;/p&gt;
&lt;p&gt;Turns out the way to read and handle errors with Axios is actually &lt;code&gt;error.response.data&lt;/code&gt; instead of just &lt;code&gt;error.data&lt;/code&gt; in the &lt;code&gt;catch()&lt;/code&gt; function. It’s not well highlighted but the documentation notes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; catch(error =&amp;gt; {
  if(error.response) { 
    /* the request was made and the server responded
    with a status code that falls out of the range of 2xx */
    console.log(error.response.data)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that one revelation, suddenly the error catching on the client side suddenly became much easier and more descriptive.&lt;/p&gt;
&lt;p&gt;The way Axios interprets successful responses from the server is almost exactly the same way it interprets error codes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Axios success response handling&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {      
  const response = await axios.get(&quot;api/findUser&quot;, {
    params: {          
      username,        
    },        
    headers: { Authorization: `JWT ${accessString}` },      
  });      
  console.log(response.data); 
  // this.setState and so on after response is received...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Axios failure response handling&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;catch (error) {      
  console.log(error.response.data);      
  this.setState({        
    loadingUser: false,        
    error: true,      
  });    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which turned out to be much easier for me to update all my &lt;code&gt;catch()&lt;/code&gt; blocks to accept this new error format than I expected it to be.&lt;/p&gt;
&lt;p&gt;Once more, here is a large snippet from the file where a user updates their data from the client side and sends it to be saved into the database.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UpdateProfile.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;updateUser = async (e) =&amp;gt; {
  const accessString = localStorage.getItem(&quot;JWT&quot;);
  if (accessString === null) {
    this.setState({
      loadingUser: false,
      error: true,
    });
  }
  const {
    first_name, last_name, email, username
  } = this.state;
  e.preventDefault();
  try {
    const response = await axios.put(
      &quot;http://localhost:3003/updateUser&quot;,
      {
        first_name,
        last_name,
        email,
        username,
      },
      {
        headers: { Authorization: `JWT ${accessString}` },
      },
    );
    // eslint-disable-next-line no-unused-vars
    console.log(response.data);
    this.setState({
      updated: true,
      error: false,
    });
  } catch (error) {
    console.log(error.response.data);
    this.setState({
      loadingUser: false,
      error: true,
    });
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s what’s happening in this function call.&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;updateUser()&lt;/code&gt; pulls the JWT token from local storage, where it was previously added.&lt;/p&gt;
&lt;p&gt;If the token is found, Axios constructs the &lt;code&gt;body&lt;/code&gt; of the PUT request which contains all the user’s new information, and sets the &lt;code&gt;header&lt;/code&gt; to the JWT token the server requires for authentication.&lt;/p&gt;
&lt;p&gt;Finally, the response comes back as either successfully updated or as a failure, in which case the &lt;code&gt;error.response.data&lt;/code&gt; is logged to the console to help the developer figure out what went wrong and the app’s state is set to &lt;code&gt;error&lt;/code&gt; to help the user understand what happened as well.&lt;/p&gt;
&lt;p&gt;This is what a user would see if the dev tools console was open when the failing request was made.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Error React throws in the console logs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/js-error-handling/react-error-logs.webp&quot; alt=&quot;React error logs&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The error a developer would see in the developer tools console in the browser.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The client sees the 401 status code the user sent back as well as the message from the server saying no user was found in the database with the matching user name.&lt;/p&gt;
&lt;p&gt;The code that makes that happen is this snippet in particular.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;} catch (error) {
      console.log(error.response.data);
      this.setState({
        loadingUser: false,
        error: true,
      });
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This wraps up my explanation of how the client can handle and display errors thrown from the server. Once again, not too tough to grasp, but just putting it all together can sometimes prove the trickiest part of all.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Errors in code are like death and taxes, they’re bound to happen. Our job as developers is to make sure we know when they happen and handle them gracefully so the user can have a good experience with our applications.&lt;/p&gt;
&lt;p&gt;Although this type of thing is common place and of paramount importance, sometimes the documentation around such error handling is buried deep or is slightly cryptic with the bare bones code snippets provided. Which is why I wanted to write today detailing exactly how I pass error codes and messages from Express all the way to the Axios library being used on the React front end.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing more about JavaScript, React, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope I’ve given you some good solutions of how to handle errors in your own full stack JavaScript applications in the future. Errors will occur — let’s handle them well.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;Github repo, MERN stack user registration project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status&quot;&gt;HTTP response status codes&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/axios/axios#handling-errors&quot;&gt;Axios, error handling documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://expressjs.com/en/guide/error-handling.html&quot;&gt;Express, error handling documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category><category>express</category><category>errors</category></item><item><title>How To Pass Multiple Route Parameters in a React URL Path</title><link>https://www.paigeniedringhaus.com/blog/how-to-pass-multiple-route-parameters-in-a-react-url-path/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/how-to-pass-multiple-route-parameters-in-a-react-url-path/</guid><description>Redirects are common. Passing more than one piece of dynamic data with them is not.</description><pubDate>Mon, 09 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-route-params/react-routes-hero.webp&quot; alt=&quot;React logo and code snippet of route with multiple parameters&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Recently, I came across an interesting problem I hadn’t encountered before. I wanted to pass more than one route parameter in a React URL route path, then access those parameters in a component upon redirect.&lt;/p&gt;
&lt;p&gt;The reason for this problem arose when I was building a &lt;a href=&quot;https://movie-demo-3.paigen11.now.sh/&quot;&gt;demo project&lt;/a&gt; to illustrate various ways to do &lt;a href=&quot;https://www.smashingmagazine.com/2011/01/guidelines-for-responsive-web-design/&quot;&gt;responsive web design&lt;/a&gt; with React. I was using &lt;a href=&quot;https://developers.themoviedb.org/3/getting-started/introduction&quot;&gt;The Movie Database API&lt;/a&gt; to supply movie data to my React front end project.&lt;/p&gt;
&lt;p&gt;What I wanted was for a user to see a list of movie genres (action, adventure, comedy, etc.), click on a genre, and be redirected to a list of movies that fell into that genre. Seems straightforward enough, right?&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-route-params/movie-demo.webp&quot; alt=&quot;Movie demo project screen showing adventure movies&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is what a user should see after clicking on &quot;Action&quot; in the genres list: movies that are classified as &quot;adventure&quot; movies.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Well, yes, it seems simple...except that the movie API supplying the list of movies based on genre required a &lt;code&gt;genreId&lt;/code&gt; to fetch the data, while what I wanted to display to users along with the movie list was the &lt;code&gt;genreName&lt;/code&gt; that they’d actually clicked on to generate this list. Do you see my problem?&lt;/p&gt;
&lt;p&gt;Two different pieces of data, both required by a different, unrelated component upon redirect (so passing data through &lt;code&gt;props&lt;/code&gt; like with a typical child component was out of the question) from the generic &lt;code&gt;Genres&lt;/code&gt; component to the specific &lt;code&gt;GenreList&lt;/code&gt; component displaying the movies related to that genre.&lt;/p&gt;
&lt;p&gt;Surprisingly, when I started to look for examples of how to pass multiple route parameters in a URL path in React, I couldn’t find much.&lt;/p&gt;
&lt;p&gt;So that’s what I wanted to share today: &lt;strong&gt;How to add, and later access, multiple route parameters in a ReactJS project upon redirect using &lt;a href=&quot;https://reacttraining.com/react-router/web/guides/quick-start&quot;&gt;react-router-dom&lt;/a&gt;, the most popular router for React applications.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;React routes and route parameters&lt;/h2&gt;
&lt;p&gt;Before I go much further, let me clarify what routes and route parameters are in ReactJS, in case you’re not familiar.&lt;/p&gt;
&lt;p&gt;I’ll be using my demo project repo, so if you’d like to see the complete codebase or the working demo, they’re available &lt;a href=&quot;https://github.com/paigen11/movie-demo-3&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://movie-demo-3-git-master.paigen11.now.sh/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re completely new to how routing works in ReactJS, I recommend checking out &lt;strong&gt;react-router-dom’s &lt;a href=&quot;https://reacttraining.com/react-router/web/guides/quick-start&quot;&gt;documentation&lt;/a&gt;&lt;/strong&gt; first. This will not be an in-depth explanation of that, but it is the router I’m using in this article.&lt;/p&gt;
&lt;h3&gt;Routes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Routes&lt;/strong&gt; specify the path to different components in a ReactJS application. When a user clicks a link to a page or hits a button that redirects him/her, the router renders the matching &lt;code&gt;&amp;lt;Route/&amp;gt;&lt;/code&gt; for that component. For instance, this is what the route for the &lt;code&gt;Genres&lt;/code&gt; page in my movie app looks like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional, static route URL in React:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Route exact path=&quot;/genres&quot; component={Genres} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a static route that will always be the same, regardless of who the user is or which page they’re coming from. No matter what, whenever they click a link to go to the &lt;code&gt;Genres&lt;/code&gt; page, this route will always be used to get them there, and it will always render the same component — no dynamic content required.&lt;/p&gt;
&lt;h3&gt;Route parameters&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Route params&lt;/strong&gt; are parameters whose values are set dynamically in a page’s URL. This allows a route to render the same component while passing that component the dynamic portion of the URL, so that it can change its data based on the parameter.&lt;/p&gt;
&lt;p&gt;Examples of URL route params you might recognize include things like IDs for products, books, users, or, in my case, movies. At least with React, in order to get the details for the correct item, the dynamic component would need the unique, specific ID of the item supplied, so it could get the correct data to display.&lt;/p&gt;
&lt;p&gt;Here’s what the &lt;code&gt;MovieDetailsContainer&lt;/code&gt; route with dynamic URL parameters in my app looks like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dynamic route URL in React:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Route exact path=&quot;/movie/:id&quot; component={MovieDetailsContainer} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is an example of a dynamically updating route. The first part of the &lt;code&gt;path&lt;/code&gt;, the &lt;code&gt;&quot;/movie/”&lt;/code&gt; part, doesn’t change, but the &lt;code&gt;:id&lt;/code&gt; is a route parameter that is set dynamically — usually from a user’s actions, like clicking a link or typing an input and clicking a search button.&lt;/p&gt;
&lt;p&gt;This is what changes and it causes the &lt;code&gt;MovieDetailsContainer&lt;/code&gt; to be rendered with the ID of the movie included. The component then pulls this out of the URL path when it renders to get the details of that particular movie to show to a user.&lt;/p&gt;
&lt;h3&gt;Accessing dynamic route params in a component&lt;/h3&gt;
&lt;p&gt;Typically, the component being rendered on redirect will access the dynamic route info it needs from the URL.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Accessing dynamic path parameter in a URL:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;this.props.match.params.id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside a React component that needs URL path data, this is the code you’ll have to use to access the route’s actual ID, which was shown as a placeholder in the route path as &lt;code&gt;:id&lt;/code&gt;. It’s a little verbose, I agree, but up until react-router-dom’s React hooks updates, it was what we had to use to access the data.&lt;/p&gt;
&lt;p&gt;From there it can be set to local component state, used to fetch data, rendered out in the JSX, etc.&lt;/p&gt;
&lt;p&gt;That is pretty much where the online tutorials stop: with a redirect example showing a single &lt;code&gt;:id&lt;/code&gt; path param. This is where my piece picks up.&lt;/p&gt;
&lt;h3&gt;Setting up the new dynamic route path&lt;/h3&gt;
&lt;p&gt;Hopefully, we’re on the same page now. Routes are clear. Route params are clear. Accessing those parameters from a component that a user is redirected to is clear. The only thing that still remains unclear is what to do if you have more than one dynamic route parameter to add to a route path.&lt;/p&gt;
&lt;p&gt;Knowing what I knew about React route paths in react-router-dom, I decided to try creating a route path for the &lt;code&gt;GenreList&lt;/code&gt; component. This is the component that shows the list of movies associated with a particular genre using two dynamic parameters: &lt;code&gt;:genreName&lt;/code&gt; and &lt;code&gt;:genreId&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; All of my actual routing for the app was contained in the &lt;code&gt;App.js&lt;/code&gt; file inside the &lt;code&gt;src/&lt;/code&gt; folder, for clarity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;App.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Route
  exact
  path=&quot;/genres/:genreName/:genreId&quot;
  component={GenreList}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was step one of handling a route containing more than one route parameter. The next step is setting the genre ID and genre name in the &lt;code&gt;Genres&lt;/code&gt; component.&lt;/p&gt;
&lt;h3&gt;Adding more than one route parameter to a URL&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Genres&lt;/code&gt; component contains, among other things, two state objects: &lt;code&gt;selectedGenre&lt;/code&gt; (a number initially set to &lt;code&gt;0&lt;/code&gt;) and &lt;code&gt;selectedGenreName&lt;/code&gt; (a string initially set to &lt;code&gt;&quot;&quot;&lt;/code&gt;). These are the two pieces of state which will be set by a user clicking one of the genres listed in the list.&lt;/p&gt;
&lt;p&gt;As soon as a user clicks a single genre, the genre’s ID and name are set in the &lt;code&gt;Genres&lt;/code&gt; component’s state. This triggers the &lt;code&gt;renderRedirect()&lt;/code&gt; function you see below, to redirect the user to the &lt;code&gt;GenresList&lt;/code&gt; component, as defined by the route path.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;this.state.selectedGenreName&lt;/code&gt; is inserted as the route placeholder &lt;code&gt;:genreName&lt;/code&gt;. &lt;code&gt;this.state.selectedGenre&lt;/code&gt; is replaced with the route placeholder &lt;code&gt;:genreId&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Genres.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;renderRedirect = () =&amp;gt; {
  if (this.state.selectedGenre !== 0 &amp;amp;&amp;amp; this.state.selectedGenreName !== &apos;&apos;) {
    return (
      &amp;lt;Redirect 
        to={`/genres/${this.state.selectedGenreName}/${this.state.selectedGenre}`}
      /&amp;gt;
    );
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step two is now complete. A particular genre ID, required by the unrelated &lt;code&gt;GenreList&lt;/code&gt; component to fetch movies of that genre is part of the URL, and the genre name, to display which genre the user’s viewing movies for, is also included. Let’s go to the redirect component, &lt;code&gt;GenreList&lt;/code&gt;, that now needs this data.&lt;/p&gt;
&lt;h3&gt;Accessing the route parameters from a URL&lt;/h3&gt;
&lt;p&gt;OK, last step: the component being redirected to, &lt;code&gt;GenreList&lt;/code&gt;, needs to pull out the different pieces of the dynamic React route path. It needs the &lt;code&gt;genreId&lt;/code&gt; to fetch the movie list from The Movie Database API, which it extracts with &lt;code&gt;this.props.match.params.genreId&lt;/code&gt;, and it needs &lt;code&gt;genreName&lt;/code&gt; to display in the component’s JSX , showing which genre the user clicked on, which is accessed via &lt;code&gt;this.props.match.params.genreName&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pretty cool!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GenreList.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (this.props.match.params) {
  try {
    const movies = await movieAPI.getMoviesByGenre(
      this.props.match.params.genreId,
    );
    this.setState({ movies, loading: false });
  } catch (err) {
      this.setState({ loading: false, error: true });
    }
  }
}
render() {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;div className=&quot;genre-search-title&quot; onClick={() =&amp;gt; this.props.history.push(&apos;/genres&apos;)} &amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;i className=&quot;fa fa-chevron-left&quot; aria-hidden=&quot;true&quot; /&amp;gt;
          &amp;lt;p&amp;gt;Back to Genres&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;    
        &amp;lt;h1&amp;gt;{this.props.match.params.genreName} Movies&amp;lt;/h1&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;MovieList
       loading={this.state.loading}
       error={this.state.error}
       movies={this.state.movies}
      /&amp;gt;
    &amp;lt;/&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I didn’t believe it could be that simple for a redirect, but it was!&lt;/p&gt;
&lt;p&gt;Just by using the correct URL path params syntax &lt;code&gt;(this.props.match.params...)&lt;/code&gt; and passing the corresponding variable name (&lt;code&gt;genreId&lt;/code&gt; or &lt;code&gt;genreName&lt;/code&gt;), I was able to pull out the correct value.&lt;/p&gt;
&lt;p&gt;This sort of thing can be done anywhere you need dynamic data when redirecting from one unrelated component to another.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Dynamic redirects are a fairly common occurrence in any web application, React apps included, but despite this, tutorials illustrating them are not so easy to come by. And examples of redirects with more than one piece of dynamic data are non-existent, which is why I decided to write a piece about just that.&lt;/p&gt;
&lt;p&gt;With the help of react-router-dom&apos;s route paths and dynamic parameters, it really isn’t as complicated as I once thought to pass more than one piece of data from one component to another unrelated component via a redirect.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing more about JavaScript, React, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope I’ve made ReactJS redirects with dynamic URL route params a little clearer and that this was something you’ll find useful in your own applications.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://movie-demo-3.paigen11.now.sh/genres/Animation/16&quot;&gt;Live demo movie website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/movie-demo-3&quot;&gt;Github repo, movie website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.themoviedb.org/3/getting-started/introduction&quot;&gt;The Movie Database API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reacttraining.com/react-router/web/guides/quick-start&quot;&gt;react-router-dom documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category></item><item><title>Destructuring Arrays &amp; Objects: JavaScript ES6 Feature Series (Pt 10)</title><link>https://www.paigeniedringhaus.com/blog/destructuring-arrays-objects-javascript-es6-feature-series-pt-10/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/destructuring-arrays-objects-javascript-es6-feature-series-pt-10/</guid><description>For concise variable syntax, curly braces have never been more critical</description><pubDate>Sun, 24 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt10-destructuring/library-hero.webp&quot; alt=&quot;Grand library filled with people studying at tables&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration for these pieces is simple: JavaScript, and especially some of the new ES6+ releases, can be more than a little perplexing at first glance to many developers. To put it bluntly: what they once thought they understood becomes a completely new beast when another layer of syntactic sugar, designed to make our lives easier, is added.&lt;/p&gt;
&lt;p&gt;That being said, according to Wikipedia, JavaScript still powers almost 95% of the 10 million most popular webpages today.&lt;/p&gt;
&lt;p&gt;JavaScript only continues to play an evermore crucial part in the web, and I wanted to provide a bunch of articles and examples of ES6+ features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these pieces to be short, in-depth explanations of various improvements to the language that I hope will inspire you to write some really cool stuff using JS. Who knows, you might even learn something new along the way. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For my final installment in this series, I will tackle array and object destructuring: the most concise way to pull out values and properties into individual variables with very little effort.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Destructuring sounds so simple at first...&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;&lt;strong&gt;destructuring assignment&lt;/strong&gt;&lt;/a&gt;, first introduced with ES 2015, is one of my favorite additions to the JavaScript standard syntax. As I said above, destructuring makes it possible to unpack values from arrays, or properties from objects, into distinct variables.&lt;/p&gt;
&lt;p&gt;This may sound simple when you first hear it, but actually putting it into effect, especially with deeply nested arrays or objects, is a little trickier to grasp. But before I get into the parts that might trip you up, let’s just talk about what destructuring looks like in both arrays, and more recently, objects.&lt;/p&gt;
&lt;h2&gt;Array destructuring&lt;/h2&gt;
&lt;p&gt;Array destructuring was introduced and finalized into the ECMAScript language before object destructuring.&lt;/p&gt;
&lt;p&gt;And just as object and array literal expressions provide an easy way to create packages of data, at will, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const a = [&quot;alpha&quot;,&quot;beta&quot;, &quot;gamma&quot;, &quot;delta&quot;, &quot;epsilon&quot;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The destructuring assignment of those same arrays uses similar syntax, but on the left-hand side of the assignment to define what values to unpack from the sourced variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anatomy of array destructuring syntax&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let b, c, more;

const a = [&quot;alpha&quot;,&quot;beta&quot;, &quot;gamma&quot;, &quot;delta&quot;, &quot;epsilon&quot;];
[b, c] = a;

console.log(b); // &quot;alpha&quot;
console.log(c); // &quot;beta&quot;

[b, c, ...more] = [&quot;alpha&quot;,&quot;beta&quot;, &quot;gamma&quot;, &quot;delta&quot;, &quot;epsilon&quot;];

console.log(more); // [ &quot;gamma&quot;, &quot;delta&quot;, &quot;epsilon&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The short example above demonstrates array destructuring and using the rest pattern to assign extra values, which I wrote about &lt;a href=&quot;./spread-rest-parameters-java-script-es-6-feature-series-pt-4&quot;&gt;here&lt;/a&gt;, on the array named &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Notice that the variables &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; are wrapped in brackets &lt;code&gt;([b, c])&lt;/code&gt;, and are assigned to equal the &lt;code&gt;a&lt;/code&gt; array. &lt;code&gt;[b, c] = a;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When those values are called they will take the first and second elements in the array. &lt;code&gt;console.log(b); // &quot;alpha&quot;&lt;/code&gt; and &lt;code&gt;console.log(c); // &quot;beta&quot;;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The rest pattern comes in with the variable &lt;code&gt;more&lt;/code&gt;. That variable is designed to inherit all the rest of the values in the a array by putting the rest syntax &lt;code&gt;(...more)&lt;/code&gt; ahead of the variable name when adding it to the array. Then, when &lt;code&gt;more&lt;/code&gt; is called, it prints out the rest of the values in its own array. &lt;code&gt;console.log(more); // [ &quot;gamma&quot;, &quot;delta&quot;, &quot;epsilon&quot; ]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alright, let’s go through some different uses for array destructuring.&lt;/p&gt;
&lt;h3&gt;Basic variable assignment&lt;/h3&gt;
&lt;p&gt;The most basic type of array destructuring is taking one array of values and assigning those values to an equal amount of new variables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of basic array variable destructuring assignment&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const govtBranches = [ &quot;executive&quot;, &quot;judicial&quot;, &quot;legislative&quot; ];

const [branch1, branch2, branch3] = govtBranches;

console.log(branch1); // &quot;executive&quot;
console.log(branch2); // &quot;judicial&quot;
console.log(branch3); // &quot;legislative&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of the three values of govtBranches has a corresponding variable wrapped in the array brackets, &lt;code&gt;branch1&lt;/code&gt;, &lt;code&gt;branch2&lt;/code&gt;, or &lt;code&gt;branch3&lt;/code&gt; that it is assigned to.&lt;/p&gt;
&lt;p&gt;Then, if any of those variables are called, they reflect one of the individual values from the &lt;code&gt;govtBranches&lt;/code&gt; array.&lt;/p&gt;
&lt;h3&gt;Assignment separation from declaration&lt;/h3&gt;
&lt;p&gt;Next up is when a variable can be declared first (either using the keywords &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt;, not &lt;code&gt;const&lt;/code&gt;), and then have its value assigned via destructuring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of variable declaration and then value assignment with destructuring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let agency1, agency2;

[agency1, agency2] = [ &quot;FBI&quot;, &quot;CIA&quot; ];

console.log(agency1); // &quot;FBI&quot;
console.log(agency2); // &quot;CIA&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the variables &lt;code&gt;agency1&lt;/code&gt; and &lt;code&gt;agency2&lt;/code&gt; are declared as undefined variables first. Next, they’re wrapped in array brackets and assigned to the array containing the values &lt;code&gt;&quot;FBI&quot;&lt;/code&gt; and &lt;code&gt;&quot;CIA&quot;&lt;/code&gt;. From there, each variable can be called individually, and it represents one of the values in that array.&lt;/p&gt;
&lt;h3&gt;Default values&lt;/h3&gt;
&lt;p&gt;Interestingly, you can assign variables a default value, similar to &lt;a href=&quot;./enhanced-object-literal-value-shorthand-java-script-es-6-feature-series-pt-6&quot;&gt;default function parameter values&lt;/a&gt;, in case a value unpacked from an array turns out to be undefined.&lt;/p&gt;
&lt;p&gt;This kind of thing may happen when there’s more variables created than values in the array it’s destructuring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of default values in array destructuring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let one, two;

[one=&quot;a&quot;, two=&quot;b&quot;] = [&quot;c&quot;];

console.log(one); // &quot;c&quot;
console.log(two); // &quot;b&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two variables &lt;code&gt;one&lt;/code&gt; and &lt;code&gt;two&lt;/code&gt; are assigned the default values &lt;code&gt;&quot;a&quot;&lt;/code&gt; and &lt;code&gt;&quot;b&quot;&lt;/code&gt; before being assigned to the array containing the single value of &lt;code&gt;&quot;c&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And when the variable &lt;code&gt;one&lt;/code&gt; is called after the array destructuring takes place, its value is overwritten to be &lt;code&gt;&quot;c&quot;&lt;/code&gt; due to the value in the array. The value of &lt;code&gt;two&lt;/code&gt; does not change though because the array doesn’t contain a second value, so that value, if it existed, would be &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Swapping variables&lt;/h3&gt;
&lt;p&gt;Did you know that two variable values can be swapped in one destructuring assignment? They can, and it’s pretty handy that you don’t need a temporary variable to make this possible anymore.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example swapping variable values with array destructuring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let boots = &quot;cat&quot;;
let rocky = &quot;dog&quot;;

[boots, rocky] = [rocky, boots];

console.log(boots); // &quot;dog&quot;
console.log(rocky); // &quot;cat&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Initially, the variable &lt;code&gt;boots&lt;/code&gt; is a &lt;code&gt;&quot;cat&quot;&lt;/code&gt; and the variable &lt;code&gt;rocky&lt;/code&gt; is a &lt;code&gt;&quot;dog&quot;&lt;/code&gt;, but simply by switching the order of the values in the array they’re being assigned to, their values can be swapped so &lt;code&gt;boots&lt;/code&gt; becomes the &lt;code&gt;&quot;dog&quot;&lt;/code&gt; and &lt;code&gt;rocky&lt;/code&gt; becomes the &lt;code&gt;&quot;cat&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is a really useful trick in certain scenarios.&lt;/p&gt;
&lt;h3&gt;Parsing an array returned from a function&lt;/h3&gt;
&lt;p&gt;Getting an array returned from a function is nothing new, but now you can destructure the values being returned to make working with them more concise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example parsing an array returned from a function&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function color() {
  return [&quot;red&quot;, &quot;yellow&quot;, &quot;green&quot;, &quot;blue&quot;]
}

let r, y, g;

[r, y, g] = color();

console.log(r); // &quot;red&quot;
console.log(g); // &quot;green&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;color()&lt;/code&gt; function returns an array of colors. By destructuring the variables &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;g&lt;/code&gt; against the function, those values in the array are assigned to those variables.&lt;/p&gt;
&lt;h3&gt;Ignoring some returned values&lt;/h3&gt;
&lt;p&gt;In the same vein, destructuring lets you ignore certain array values you aren’t interested in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example ignoring values from an array with destructuring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function ignoreColor() {
  return [&quot;indigo&quot;, &quot;orange&quot;, &quot;lime&quot;]
}

const [i, ,l] = ignoreColor();

console.log(i); // &quot;indigo&quot;
console.log(l); // &quot;lime&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simply by adding an empty space in the destructured array, you can choose not to return the value &lt;code&gt;&quot;orange&quot;&lt;/code&gt; from the function &lt;code&gt;ignoreColor()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also choose to ignore all the values from a function if you’d like (though I don’t really see much of a use case for that).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ , , ] = ignoreColor();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Assigning the rest of an array to a variable&lt;/h3&gt;
&lt;p&gt;And I’m back again to part of what I showed in the very first array destructuring example: using the rest operator &lt;code&gt;(...)&lt;/code&gt; to pick up any leftover values from an array.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example assigning leftover values to a variable via array destructuring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const [commanderInChief, ...staff] = [&quot;President&quot;, &quot;Vice President&quot;, &quot;Chief of Staff&quot;, &quot;Press Secretary&quot;];

console.log(commanderInChief); // &quot;President&quot;
console.log(staff); // [ &quot;Vice President&quot;, &quot;Chief of Staff&quot;, &quot;Press Secretary&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just as before, &lt;code&gt;commanderInChief&lt;/code&gt; takes the first value in the array, and by using the rest syntax, &lt;code&gt;...staff&lt;/code&gt; takes all the remaining values in the array as a new array of its own.&lt;/p&gt;
&lt;p&gt;Simple as that. Now let’s take a look at how destructuring works on objects.&lt;/p&gt;
&lt;h2&gt;Object destructuring&lt;/h2&gt;
&lt;p&gt;Object destructuring takes a similar tack as array destructuring, except instead of values being pulled out of an array, properties (keys) and their values can be pulled out of an object.&lt;/p&gt;
&lt;p&gt;Here’s some examples of how that can look.&lt;/p&gt;
&lt;h3&gt;Basic object destructuring assignment&lt;/h3&gt;
&lt;p&gt;Once again, I’ll start with the most basic example of how object destructuring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of basic object destructuring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pieIngredients = { pumpkin: &quot;1 can&quot;, pieCrust: &quot;1 crust&quot;, spice: &quot;2 tsp&quot;};

const { pumpkin, pieCrust, spice} = pieIngredients;

console.log(pumpkin); // &quot;1 can&quot;
console.log(pieCrust); // &quot;1 crust&quot;
console.log(spice); // &quot;2 tsp&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By wrapping the properties in the object &lt;code&gt;pieIngredients&lt;/code&gt; and setting them equal to the object, each property, &lt;code&gt;pumpkin&lt;/code&gt;, &lt;code&gt;pieCrust&lt;/code&gt;, and &lt;code&gt;spice&lt;/code&gt;, becomes its own variable and the value attached to it becomes the value for the new variable.&lt;/p&gt;
&lt;h3&gt;Assignment without declaration&lt;/h3&gt;
&lt;p&gt;A variable can also be assigned its value with destructuring separate from its declaration, just like you can do it with array destructuring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of assigning variables after declaring the variables separately&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let hobby, sports;

({hobby, sports} = {hobby: &quot;knitting&quot;, sports: &quot;croquet&quot;});

console.log(hobby); // &quot;knitting&quot;
console.log(sports); // &quot;croquet&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the parentheses &lt;code&gt;( ... )&lt;/code&gt; around the assignment statement are required when using object literal destructuring assignment without a declaration.&lt;/p&gt;
&lt;p&gt;Otherwise, the syntax is considered invalid because the syntax on the lefthand side, the &lt;code&gt;{hobby, sports}&lt;/code&gt;, is considered a block and not an object literal. Putting the parentheses around the whole line though, clarifies the intent and makes it valid.&lt;/p&gt;
&lt;h3&gt;Assigning to new variable names&lt;/h3&gt;
&lt;p&gt;One helpful thing is that a property can be unpacked from an object and assigned to a variable with a different name than the object property.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example reassigning destructured object properties to new variable names&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const car = {speed: 110, color: &quot;red&quot;};

const { speed: fast, color: cherry } = car;

console.log(fast); // 110
console.log(cherry); // &quot;red&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, for example, &lt;code&gt;const {speed: fast} = car;&lt;/code&gt; takes from the object &lt;code&gt;car&lt;/code&gt; the property named &lt;code&gt;speed&lt;/code&gt; and assigns it to a local variable named &lt;code&gt;fast&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Default values&lt;/h3&gt;
&lt;p&gt;Just like with array destructuring, variables for destructured objects can be assigned a default, in the case that the value unpacked from the object is &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of assigning default values to object destructuring variables&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { redWine = &quot;cabernet&quot;, whiteWine = &quot;pinot grigio&quot;} = { redWine: &quot;malbec&quot;};

console.log(redWine); // &quot;malbec&quot;
console.log(whiteWine); // &quot;pinot grigio&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the variables &lt;code&gt;redWine&lt;/code&gt; and &lt;code&gt;whiteWine&lt;/code&gt; are assigned default values of &lt;code&gt;&quot;cabernet&quot;&lt;/code&gt; and &lt;code&gt;&quot;pinot grigio&quot;&lt;/code&gt;. Then the redWine variable is reassigned the value of &lt;code&gt;&quot;malbec&quot;&lt;/code&gt;, but since &lt;code&gt;whiteWine&lt;/code&gt; is not defined in the object being destructured, it retains its original value.&lt;/p&gt;
&lt;h3&gt;Unpacking fields from objects passed as function parameters&lt;/h3&gt;
&lt;p&gt;Another feature of object destructuring is that you can actually use destructuring syntax &lt;em&gt;inside&lt;/em&gt; of function calls to get just those values back. Take a look at this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of passing destructured object properties as function parameters&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const girl = {
  name: &quot;Paige&quot;,
  age: 30,
  eyeColor: &quot;blue&quot;,
  hair: {
    type: &quot;curly&quot;,
    color: &quot;red&quot;,
    length: &quot;shoulder-length&quot;
  }
}

const getUserName = ({name}) =&amp;gt; {
  return {name};
}

console.log(getUserName(girl)); // { name: &quot;Paige&quot; }

const getUserHair = ({hair: {type, color}}) =&amp;gt; {
  return `Her hair is ${color} and ${type}`;
}

console.log(getUserHair(girl)); // Her hair is red and curly
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example here, the object &lt;code&gt;girl&lt;/code&gt; is a pretty standard one. It’s got two levels of nested properties but other than that, it’s unremarkable.&lt;/p&gt;
&lt;p&gt;The thing to notice is the two functions &lt;code&gt;getUserName()&lt;/code&gt; and &lt;code&gt;getUserHair()&lt;/code&gt;. You’ll see with &lt;code&gt;getUserName()&lt;/code&gt; the function parameter being passed to it is actually the destructured version of the property name from the object it receives.&lt;/p&gt;
&lt;p&gt;So when the whole &lt;code&gt;girl&lt;/code&gt; object is passed to the function, it returns just the property and value of &lt;code&gt;name&lt;/code&gt; as the function’s output.&lt;/p&gt;
&lt;p&gt;The second function, &lt;code&gt;getUserHair()&lt;/code&gt; is even more interesting because the value it’s trying to access is actually located two levels down within the object being passed to the function, so first, the property of &lt;code&gt;hair&lt;/code&gt; must be accessed, and then the properties unique to hair, which are &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; can be accessed.&lt;/p&gt;
&lt;p&gt;That function will then return a string stating the object’s hair color and hair type as the output when it’s called with the object of &lt;code&gt;girl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is also an example of how to access nested objects using destructuring, which I’ll talk about next.&lt;/p&gt;
&lt;h3&gt;Nested object destructuring&lt;/h3&gt;
&lt;p&gt;This was a topic that took me some time to wrap my head around (and to be honest, I usually still have to go back and look at the documentation again when I want to destructure multi-level nested objects).&lt;/p&gt;
&lt;p&gt;The basic gist though is: if your object is more than one level deep within your object, you must first access its parent property, and its parents’ parent property, and so on, until you reach the outermost object property value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of deeply nested object destructuring&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const girl = {
  name: &quot;Paige&quot;,
  age: 30,
  eyeColor: &quot;blue&quot;,
  hobbies: {
    primaries: [
      {
        mostFavorite: [
          &quot;drawing&quot;,
          &quot;art&quot;
        ],
        frequentlyDone: &quot;cooking&quot;,
        relaxing: {
          reading: &quot;fictionBooks&quot;
        }
      }
    ]
  }
}

const {
  hobbies: {
      primaries: [
      {
        mostFavorite
      }
    ]
  }
} = girl;

console.log(mostFavorite[0]); // &quot;drawing&quot;
console.log(mostFavorite[1]); // &quot;art&quot;

const {
  hobbies: {
    primaries: [
      {
        relaxing: {
          reading
        }
      }
    ]
  }
} = girl;

console.log(reading); // &quot;fictionBooks&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used the same &lt;code&gt;girl&lt;/code&gt; object from the previous example but I added the property of &lt;code&gt;hobbies&lt;/code&gt; to the object and added some new arrays and objects within them so I could show how you can pull values out of either.&lt;/p&gt;
&lt;p&gt;The first new object I create pulls out the nested object property of &lt;code&gt;mostFavorite&lt;/code&gt;, which happens to be an array with two values. To reach these values, first, I have to wrap the outermost property of &lt;code&gt;girl&lt;/code&gt;, which is &lt;code&gt;hobbies&lt;/code&gt; in curly braces. Next, I have to wrap &lt;code&gt;hobbies&quot;&lt;/code&gt; property of &lt;code&gt;primaries&lt;/code&gt;. Then, I must dive into both the array and the object that &lt;code&gt;primaries&lt;/code&gt; contains to reach the &lt;code&gt;mostFavorite&lt;/code&gt; property which actually holds the values I seek.&lt;/p&gt;
&lt;p&gt;From there, it’s a simple exercise to log out any values that &lt;code&gt;mostFavorite&lt;/code&gt; has.&lt;/p&gt;
&lt;p&gt;In the same vein, to reach the value of the property &lt;code&gt;reading&lt;/code&gt; buried deep within the &lt;code&gt;girl&lt;/code&gt; object, I have to again start out by wrapping &lt;code&gt;hobbies&lt;/code&gt; in curly braces, then proceed on to &lt;code&gt;primaries&lt;/code&gt;, dive into the array and find the object property of &lt;code&gt;relaxing&lt;/code&gt; and finally wrap the property of &lt;code&gt;reading&lt;/code&gt;, which belongs to the parent object of &lt;code&gt;relaxing&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, I can simply call &lt;code&gt;reading&lt;/code&gt; as its own variable and get back the value nested deeply in the &lt;code&gt;girl&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;It definitely takes some practice to get the hang of, but look at how much less syntax is needed to get those values than before.&lt;/p&gt;
&lt;p&gt;So long &lt;code&gt;const reading = girl.hobbies.primaries[0].relaxing.reading;&lt;/code&gt;. I won’t miss that.&lt;/p&gt;
&lt;p&gt;If you’d like to read more about nested object destructuring, I wrote another article specifically about it a few months back, as well as ways to avoid undefined errors if values weren’t available. Here’s the &lt;a href=&quot;./use-es-6-to-destructure-deeply-nested-objects-in-javascript&quot;&gt;link&lt;/a&gt; to it. 😄&lt;/p&gt;
&lt;h3&gt;Rest syntax in object destructuring&lt;/h3&gt;
&lt;p&gt;Last example, which is still in ECMAScript stage 4 proposal, I might add, at the time of writing this article: rest syntax plus object destructuring.&lt;/p&gt;
&lt;p&gt;I showed this in the very first array destructuring demo, but I haven’t shown it with object destructuring yet. Turns out, it works about the same for objects as it does for arrays.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of object destructuring with the rest syntax&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let myObjectOfNums = {
  ex: &quot;ten&quot;,
  why: &quot;twenty&quot;,
  zed: &quot;thirty&quot;,
  dee: &quot;forty&quot;,
  ee: &quot;fifty&quot;
}

let {ex, why, zed, ...allOthers} = myObjectOfNums;

console.log(ex); // &quot;ten&quot;
console.log(why); // &quot;twenty&quot;
console.log(zed); // &quot;thirty&quot;
console.log(allOthers); // { dee: &quot;forty&quot;, ee: &quot;fifty&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See how easy it is to pull out the first three properties and their values from the object &lt;code&gt;myObjectOfNums&lt;/code&gt;, as well as using the rest parameter to keep the other properties contained together in a new object called &lt;code&gt;allOthers&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;And the other rules of destructuring still apply just the same here. If you wanted to change the variable names from &lt;code&gt;ex&lt;/code&gt; or why to &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; you could do so just the same as before.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of object destructuring with the rest syntax AND variable reassignment&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let { ex: a, why: b, zed, ...allOthers } = myObjectOfNums;

console.log(a); // &quot;ten&quot;
console.log(b); // &quot;twenty&quot;
console.log(zed); // &quot;thirty&quot;
console.log(allOthers); // { dee: &quot;forty&quot;, ee: &quot;fifty&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is also totally valid. Pretty cool, huh? 😃&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Array and object destructuring is something that&apos;s existed in languages like Perl and Python for years, but it wasn’t until ECMAScript 2015 that JavaScript began to get some parity in this area.&lt;/p&gt;
&lt;p&gt;This new syntax utilizing curly braces makes it possible to easily access individual variables from arrays, and even objects, with very concise code. And I, for one, am a big fan of it.&lt;/p&gt;
&lt;p&gt;My goal with this series is to examine parts of the ES6 syntax you use everyday but may not know all the subtleties and nuances of, so you can be an even better web developer.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope I’ve made array and object destructuring a little more clear and something you’re excited to try out in your own code bases.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;Destructuring assignments&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Object Keys, Values, and Entries: JavaScript ES6 Feature Series (Pt 9)</title><link>https://www.paigeniedringhaus.com/blog/object-keys-values-and-entries-javascript-es6-feature-series-pt-9/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/object-keys-values-and-entries-javascript-es6-feature-series-pt-9/</guid><description>Finally, ECMAScript has introduced some much-needed object manipulation methods</description><pubDate>Tue, 12 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt9-obj-methods/notebook-and-coffee.webp&quot; alt=&quot;overhead view of coffee cup, laptop, hands writing in notebook&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration for these pieces is simple: it’s the fact that there are still plenty of developers for whom JavaScript is sometimes completely confusing— or, at least, doesn’t always make a whole lot of sense.&lt;/p&gt;
&lt;p&gt;But JavaScript still powers almost 95% of the 10 million most popular webpages, according to &lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript&quot;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And since it only continues to increase in usage as time goes by, I wanted to provide a bunch of articles and examples of ES6+ features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these pieces to be short, in-depth explanations of various improvements to the language that I hope will inspire you to write some really cool stuff using JS. Who knows, you might even learn something new along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This piece will focus on JavaScript objects and some handy new methods concerning keys, values, and the combination of the two that were standardized into the language in the last few years.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Object.keys()&lt;/h2&gt;
&lt;p&gt;This may sound hard to believe, especially if you’re coming from another programming language like Java, but up until ES2015, there was no built-in method in JavaScript to easily access an object’s property names, otherwise known as its &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys&quot;&gt;&lt;strong&gt;keys&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Really?&lt;/p&gt;
&lt;p&gt;Shocking, I know. Prior to this, a library like &lt;a href=&quot;https://lodash.com/docs/4.17.15#keys&quot;&gt;Lodash&lt;/a&gt; might be employed to do something that should be a basic, standardized method.&lt;/p&gt;
&lt;p&gt;Happily, the ECMAScript committee got their act together with the release of ES2015, and the method &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys&quot;&gt;&lt;strong&gt;&lt;code&gt;Object.keys()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; was introduced. The method returns an array of a given object&apos;s own enumerable property names, in the same order as we get with a normal &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of Object.keys() on an object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const resistanceFighter = {
  name: &quot;John Connor&quot;,
  age: 30,
  title: &quot;Resistance Leader&quot;,
  fight() {
    return `${this.name} leads the resistance fight against the machines.`
  }
};

console.log(Object.keys(resistanceFighter)); // [ &quot;name&quot;, &quot;age&quot;, &quot;title&quot;, &quot;fight()&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Object.keys()&lt;/code&gt; syntax is very simple: You pass an object, like &lt;code&gt;resistanceFighter&lt;/code&gt;, into the method as its parameter, and the method returns the keys, or names, of that object’s properties and methods.&lt;/p&gt;
&lt;p&gt;In this case, it returns the three property names: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;, and &lt;code&gt;title&lt;/code&gt;, plus the method attached to the object, &lt;code&gt;fight()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The elements are returned as strings in an array that correspond to the enumerable properties found directly on the &lt;code&gt;object&lt;/code&gt;. The ordering of the properties is the same as that given by manually looping over the properties of the object.&lt;/p&gt;
&lt;p&gt;Let’s take a look at some other examples of how &lt;code&gt;Object.keys()&lt;/code&gt; will interact with various JavaScript data structures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.keys() with a simple array:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const resistanceTeam = [ &quot;Sarah J Connor&quot;, &quot;Terminator&quot;, &quot;John Connor&quot;];

console.log(Object.keys(resistanceTeam)); // [ &quot;0&quot;, &quot;1&quot;, &quot;2&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When running the method against an actual array, the &lt;code&gt;keys&lt;/code&gt; returned are the “stringified” indexes of each item contained in the array.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.keys() with an array-like object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieTitles = {
  0: &quot;The Terminator&quot;,
  1: &quot;Judgment Day&quot;,
  2: &quot;Rise of the Machines&quot;,
  3: &quot;Salvation&quot;,
  4: &quot;Genesis&quot;,
  5: &quot;Dark Fate&quot;
}

console.log(Object.keys(movieTitles)); // [ &quot;0&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar to a true array, an object that’s like an array with index numbers listed as its keys will return an array of numbers as strings when it’s run through the &lt;code&gt;Object.keys()&lt;/code&gt; method.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Object.keys() on an array-like object with random key ordering:

const movieReleaseYears = {
  1991: &quot;Judgment Day&quot;,
  2015: &quot;Genisys&quot;,
  2003: &quot;Rise of the Machines&quot;,
  1984: &quot;The Terminator&quot;,
  2019: &quot;Dark Fate&quot;,
  2009: &quot;Salvation&quot;
}

console.log(Object.keys(movieReleaseYears)); // [ &quot;1984&quot;, &quot;1991&quot;, &quot;2003&quot;, &quot;2009&quot;, &quot;2015&quot;, &quot;2019&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you run &lt;code&gt;Object.keys()&lt;/code&gt; on an object with randomly ordered keys, like, say, keys that happen to be the years the different &lt;em&gt;Terminator&lt;/em&gt; movies were released, the array of keys produced will be ordered from least to greatest.&lt;/p&gt;
&lt;p&gt;If, however, you run this same method on an object where the keys are non-numerical strings, they will not be printed out in a sorted order. To get them sorted, you’ll still need to run the &lt;code&gt;.sort()&lt;/code&gt; method on the array. See the example below for reference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.keys() on an object with keys, both unsorted and sorted:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieDirectorsUnordered = {
  director2: &quot;Tim Miller&quot;,
  director4: &quot;Jonathan Mostow&quot;,
  director1: &quot;James Cameron&quot;,
  director3: &quot;McG&quot;
}

console.log(Object.keys(movieDirectorsUnordered)) // [ &quot;director2&quot;, &quot;director4&quot;, &quot;director1&quot;, &quot;director3&quot; ]
console.log(Object.keys(movieDirectorsUnordered).sort()); // [ &quot;director1&quot;, &quot;director2&quot;, &quot;director3&quot;, &quot;director4&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One more thing you can do with &lt;code&gt;Object.keys()&lt;/code&gt; in ES2015: You can coerce non-object things like strings to objects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.keys() coercing a string to an object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const animal = &quot;canine&quot;;

console.log(Object.keys(animal)); // [ &quot;0&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you try to call this method in ES5 or below, a TypeError will be thrown, just as an FYI.&lt;/p&gt;
&lt;p&gt;Now, let’s move on to the other half of the object equation: the values that go with the keys.&lt;/p&gt;
&lt;h2&gt;Object.values()&lt;/h2&gt;
&lt;p&gt;For whatever reasons, the method &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values&quot;&gt;&lt;strong&gt;&lt;code&gt;Object.values()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; wasn’t standardized in the JavaScript language until ES2017 (Why not sooner?)&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Object.values()&lt;/code&gt; method returns an array of a given object&apos;s own enumerable property values, in the same order as that provided by a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in&quot;&gt;&lt;code&gt;for...in&lt;/code&gt;&lt;/a&gt; loop (the difference being that a &lt;code&gt;for-in&lt;/code&gt; loop enumerates properties in the prototype chain as well).&lt;/p&gt;
&lt;p&gt;If you’ve ever run a relatively strict set of &lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint rules&lt;/a&gt;, like &lt;a href=&quot;https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb&quot;&gt;Airbnb’s&lt;/a&gt;, against your repo, you may have seen a warning about using &lt;code&gt;for...in&lt;/code&gt; loops for the reason mentioned above.&lt;/p&gt;
&lt;p&gt;Looping through the prototype chain will reveal inherited properties as well as properties that belong to the object itself, which is usually not desired.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of Object.values() on an object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const resistanceFighter = {
  name: &quot;John Connor&quot;,
  age: 30,
  title: &quot;Resistance Leader&quot;,
  fight() {
    return `${this.name} leads the resistance fight against the machines.`
  }
};

console.log(Object.values(resistanceFighter)); // [ &quot;John Connor&quot;, 30, &quot;Resistance Leader&quot;, [Function: fight] ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the same &lt;code&gt;resistanceFighter&lt;/code&gt; object I used in the &lt;code&gt;Object.keys()&lt;/code&gt; example above, when I call &lt;code&gt;Object.values()&lt;/code&gt; and pass it as the parameter, I get back an array of the values in the object: &lt;code&gt;&quot;John Connor&quot;&lt;/code&gt;, &lt;code&gt;30&lt;/code&gt;, &lt;code&gt;&quot;Resistance Leader&quot;&lt;/code&gt;, and the &lt;code&gt;fight()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Unlike the array of strings that &lt;code&gt;Object.keys()&lt;/code&gt; returns, &lt;code&gt;Object.values()&lt;/code&gt; returns an array whose elements are the &lt;em&gt;actual&lt;/em&gt; enumerable property values found on the object. Once again, the ordering of the properties is the same as that given by looping over the property values of the object manually.&lt;/p&gt;
&lt;p&gt;Here are some examples of &lt;code&gt;Object.values()&lt;/code&gt; in action.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.values() with a simple array:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const resistanceTeam = [ &quot;Sarah J Connor&quot;, &quot;Terminator&quot;, &quot;John Connor&quot;];

console.log(Object.values(resistanceTeam)); // [ &quot;Sarah J Connor&quot;, &quot;Terminator&quot;, &quot;John Connor&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just as when &lt;code&gt;Object.keys()&lt;/code&gt; prints out the index of each item in the array, calling &lt;code&gt;Object.values()&lt;/code&gt; prints out the actual items in the array, just as they are currently listed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.values() on an array-like object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieTitles = {
  0: &quot;The Terminator&quot;,
  1: &quot;Judgment Day&quot;,
  2: &quot;Rise of the Machines&quot;,
  3: &quot;Salvation&quot;,
  4: &quot;Genisys&quot;,
  5: &quot;Dark Fate&quot;
}

console.log(Object.values(movieTitles));
/* [ &quot;The Terminator&quot;,
  &quot;Judgment Day&quot;,
  &quot;Rise of the Machines&quot;,
  &quot;Salvation&quot;,
  &quot;Genisys&quot;,
  &quot;Dark Fate&quot; ] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When &lt;code&gt;Object.values()&lt;/code&gt; is called on the array-like object with numbers as its keys, the resulting array is printed out in the order of the keys. This can be proven by the following example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.values() on an array-like object with random key ordering:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieReleaseYears = {
  1991: &quot;Judgment Day&quot;,
  2015: &quot;Genisys&quot;,
  2003: &quot;Rise of the Machines&quot;,
  1984: &quot;The Terminator&quot;,
  2019: &quot;Dark Fate&quot;,
  2009: &quot;Salvation&quot;
}

console.log(Object.values(movieReleaseYears));
/* [ &quot;The Terminator&quot;,
  &quot;Judgment Day&quot;,
  &quot;Rise of the Machines&quot;,
  &quot;Salvation&quot;,
  &quot;Genisys&quot;,
  &quot;Dark Fate&quot; ] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, even though the &lt;code&gt;movieReleaseYears&lt;/code&gt;&apos;s keys are in a random order, when the resulting array is printed out from &lt;code&gt;Object.values()&lt;/code&gt;, the values are in the numerical order of their keys’ values.&lt;/p&gt;
&lt;p&gt;This same sorting does not hold true when the object’s keys are non-numerical values.&lt;/p&gt;
&lt;p&gt;In that case, as with the &lt;code&gt;Object.keys()&lt;/code&gt; example, you must manually sort the resulting array yourself with &lt;code&gt;.sort()&lt;/code&gt;. The array will sort according to the values in it, not the keys the values were once attached to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.values() on an object’s values, both unsorted and sorted:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieDirectorsUnordered = {
  director2: &quot;Tim Miller&quot;,
  director4: &quot;Jonathan Mostow&quot;,
  director1: &quot;James Cameron&quot;,
  director3: &quot;McG&quot;
}

console.log(Object.values(movieDirectorsUnordered)); // [ &quot;Tim Miller&quot;, &quot;Jonathan Mostow&quot;, &quot;James Cameron&quot;, &quot;McG&quot; ]
console.log(Object.values(movieDirectorsUnordered).sort()); // [ &quot;James Cameron&quot;, &quot;Jonathan Mostow&quot;, &quot;McG&quot;, &quot;Tim Miller&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And just like &lt;code&gt;Object.keys()&lt;/code&gt;, &lt;code&gt;Object.values()&lt;/code&gt; has the power to coerce non-object primitives like strings into objects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Behold, Object.values() coercing a string to an object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const animal = &quot;canine&quot;;

console.log(Object.values(animal)); // [ &quot;c&quot;, &quot;a&quot;, &quot;n&quot;, &quot;i&quot;, &quot;n&quot;, &quot;e&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OK, time to go to part three of this piece: the combination of object keys and values, courtesy of Object.entries().&lt;/p&gt;
&lt;h2&gt;Object.entries()&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries&quot;&gt;&lt;strong&gt;&lt;code&gt;Object.entries()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; method was also introduced with ES2017, and the method returns an array of a given object’s own enumerable string-keyed property &lt;code&gt;[key, value]&lt;/code&gt; pairs, in the same order as that provided by a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in&quot;&gt;&lt;code&gt;for...in&lt;/code&gt;&lt;/a&gt; loop.&lt;/p&gt;
&lt;p&gt;As I stated above in the &lt;code&gt;Object.values()&lt;/code&gt; section, a &lt;code&gt;for-in&lt;/code&gt; loop, which could achieve a similar outcome as &lt;code&gt;Object.entries()&lt;/code&gt;, iterates over the prototype chain as well, which isn’t usually the desired behavior of the code. This method provides a more recommended way to iterate through an object’s keys and values.&lt;/p&gt;
&lt;p&gt;The order of the array returned by &lt;code&gt;Object.entries()&lt;/code&gt; does not depend on how an object is defined. If there is a need for certain ordering then the array should be sorted first like &lt;code&gt;Object.entries(obj).sort((a, b) =&amp;gt; b[0].localeCompare(a[0]));&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of Object.entries() on an object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const resistanceFighter = {
  name: &quot;John Connor&quot;,
  age: 30,
  title: &quot;Resistance Leader&quot;,
  fight() {
    return `${this.name} leads the resistance fight against the machines.`
  }
};

console.log(Object.entries(resistanceFighter));
/* [ 
    [ &quot;name&quot;, &quot;John Connor&quot; ],
    [ &quot;age&quot;, 30 ],
    [ &quot;title&quot;, &quot;Resistance Leader&quot; ],
    [ &quot;fight&quot;, [Function: fight] ] 
   ] */

for(let [key, value] of Object.entries(resistanceFighter)){
  console.log(`${key}: ${value}`);
}
/* name: John Connor
  age: 30
  title: Resistance Leader
  fight: function fight() {
    return this.name + &quot; leads the resistance fight against the machines.&quot;;
} */

Object.entries(resistanceFighter).forEach(([key, value]) =&amp;gt; console.log(`${key}: ${value}`))
/* name: John Connor
  age: 30
  title: Resistance Leader
  fight: function fight() {
    return this.name + &quot; leads the resistance fight against the machines.&quot;;
} */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, calling &lt;code&gt;Object.entries()&lt;/code&gt; on the &lt;code&gt;resistanceFighter&lt;/code&gt; object produces an array of nested arrays, each inner array corresponding to one of the object’s key-value pairs.&lt;/p&gt;
&lt;p&gt;The second and third parts of the example are a way to elegantly iterate through an object’s values with a &lt;code&gt;for...of&lt;/code&gt; loop or the &lt;code&gt;Array.forEach()&lt;/code&gt; method, both of which I find particularly useful when I need to debug or transform an object for future use.&lt;/p&gt;
&lt;p&gt;Let’s look at some other uses for &lt;code&gt;Object.entries()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.entries() with a simple array:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const resistanceTeam = [ &quot;Sarah J Connor&quot;, &quot;Terminator&quot;, &quot;John Connor&quot;];

console.log(Object.entries(resistanceTeam));
/* [ 
    [ &quot;0&quot;, &quot;Sarah J Connor&quot; ],
    [ &quot;1&quot;, &quot;Terminator&quot; ],
    [ &quot;2&quot;, &quot;John Connor&quot; ] 
   ] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling the &lt;code&gt;Object.entries()&lt;/code&gt; method on a simple array will print out all the values in the array with their corresponding index values as their keys — pretty straightforward and similar to calling &lt;code&gt;Object.keys()&lt;/code&gt; on an array.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.entries() on an array-like object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieTitles = {
  0: &quot;The Terminator&quot;,
  1: &quot;Judgment Day&quot;,
  2: &quot;Rise of the Machines&quot;,
  3: &quot;Salvation&quot;,
  4: &quot;Genisys&quot;,
  5: &quot;Dark Fate&quot;
}

console.log(Object.entries(movieTitles));
/* [ 
    [ &quot;0&quot;, &quot;The Terminator&quot; ],
    [ &quot;1&quot;, &quot;Judgment Day&quot; ],
    [ &quot;2&quot;, &quot;Rise of the Machines&quot; ],
    [ &quot;3&quot;, &quot;Salvation&quot; ],
    [ &quot;4&quot;, &quot;Genisys&quot; ],
    [ &quot;5&quot;, &quot;Dark Fate&quot; ] 
   ] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, calling the method on an object with index numbers as its names, it will produce an array of arrays with the keys and values of each object property.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.entries() on an array-like object with random key ordering:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieReleaseYears = {
  1991: &quot;Judgement Day&quot;,
  2015: &quot;Genisys&quot;,
  2003: &quot;Rise of the Machines&quot;,
  1984: &quot;The Terminator&quot;,
  2019: &quot;Dark Fate&quot;,
  2009: &quot;Salvation&quot;
}

console.log(Object.entries(movieReleaseYears));
/* [ 
    [ &quot;1984&quot;, &quot;The Terminator&quot; ],
    [ &quot;1991&quot;, &quot;Judgment Day&quot; ],
    [ &quot;2003&quot;, &quot;Rise of the Machines&quot; ],
    [ &quot;2009&quot;, &quot;Salvation&quot; ],
    [ &quot;2015&quot;, &quot;Genisys&quot; ],
    [ &quot;2019&quot;, &quot;Dark Fate&quot; ] 
   ] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As in previous pieces of this blog, &lt;code&gt;Object.entries()&lt;/code&gt; on &lt;code&gt;movieReleaseYears&lt;/code&gt;, with its currently unordered number keys, will return a list of arrays sorted by their index values in ascending order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.entries() on an object’s values, both unsorted and sorted:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const movieDirectorsUnordered = {
  director2: &quot;Tim Miller&quot;,
  director4: &quot;Jonathan Mostow&quot;,
  director1: &quot;James Cameron&quot;,
  director3: &quot;McG&quot;
}

console.log(Object.entries(movieDirectorsUnordered));
/* [ 
    [ &quot;director2&quot;, &quot;Tim Miller&quot; ],
    [ &quot;director4&quot;, &quot;Jonathan Mostow&quot; ],
    [ &quot;director1&quot;, &quot;James Cameron&quot; ],
    [ &quot;director3&quot;, &quot;McG&quot; ] 
   ] */

console.log(Object.entries(movieDirectorsUnordered).sort());
/* [ 
    [ &quot;director1&quot;, &quot;James Cameron&quot; ],
    [ &quot;director2&quot;, &quot;Tim Miller&quot; ],
    [ &quot;director3&quot;, &quot;McG&quot; ],
    [ &quot;director4&quot;, &quot;Jonathan Mostow&quot; ] 
   ] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But, if the object being made into an array of arrays has keys that are strings or something besides numbers that are easy to order, it will just print out the contents as they are listed in the object unless you manually call the &lt;code&gt;.sort()&lt;/code&gt; method afterward. Fair enough?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object.entries() coercing a string to an object:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const animal = &quot;canine&quot;;
console.log(Object.entries(animal));
/* [ 
    [ &quot;0&quot;, &quot;c&quot; ],
    [ &quot;1&quot;, &quot;a&quot; ],
    [ &quot;2&quot;, &quot;n&quot; ],
    [ &quot;3&quot;, &quot;i&quot; ],
    [ &quot;4&quot;, &quot;n&quot; ],
    [ &quot;5&quot;, &quot;e&quot; ] 
   ] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A final example. A string can be mutated into an object with the help of &lt;code&gt;Object.entries()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you see in the code above, the string &lt;code&gt;&quot;canine&quot;&lt;/code&gt; becomes an array of arrays, with each character in the string becoming the value portion of the array and the index of that string becoming the key portion.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Surprisingly, until the releases of ES2015 and ES2017 JavaScript objects lacked some seemingly basic methods to read and manipulate keys and values. Luckily for us, accessing an object’s keys, its values, and even iterating through those keys and values together is now standard.&lt;/p&gt;
&lt;p&gt;Keeping up with all the improvements the ECMAScript committee is coming out with can be more than a little overwhelming, which is why I started writing these pieces.&lt;/p&gt;
&lt;p&gt;My goal with this series is to go in-depth on pieces of the ES6 syntax you may use daily (or may not even be aware of), so you can be an even more effective web developer.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll give ES6&apos;s newest object methods a spin in your JavaScript code — it will make your development life easier, I promise.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys&quot;&gt;Object.keys()&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values&quot;&gt;Object.values()&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries&quot;&gt;Object.entries()&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Classes and Inheritance: JavaScript ES6 Feature Series (Pt 8)</title><link>https://www.paigeniedringhaus.com/blog/classes-and-inheritance-javascript-es6-feature-series-pt-8/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/classes-and-inheritance-javascript-es6-feature-series-pt-8/</guid><description>Prototypes are still there... under the hood</description><pubDate>Sun, 27 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt8-classes-inheritance/cars-hero.webp&quot; alt=&quot;super fast Japanese cars with their hoods popped&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind these pieces is simple: there are still plenty of developers for whom JavaScript is a bit baffling— or at the very least, has some odd quirks in its behavior.&lt;/p&gt;
&lt;p&gt;Despite that, JavaScript is responsible for powering almost 95% of the 10 million most popular web pages, according to Wikipedia.&lt;/p&gt;
&lt;p&gt;Since it only continues to increase in usage and popularity, I wanted to provide a bunch of articles and examples of ES6+ features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these pieces to be short, in-depth explanations of various improvements to the language that I hope will inspire you to write some really cool stuff using JS. Who knows? You might even learn something new along the way. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For my eighth blog post, I’ll dive into JavaScript classes and class-based inheritance: the cleaner, more straightforward way to handle JavaScript’s existing prototype-based inheritance system.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Before there were classes, there were prototypes&lt;/h2&gt;
&lt;p&gt;I can’t talk about JavaScript classes without first talking about &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes&quot;&gt;&lt;strong&gt;prototypes&lt;/strong&gt;&lt;/a&gt; — the original mechanism by which JavaScript objects inherit features from each other.&lt;/p&gt;
&lt;p&gt;It’s outside the scope of this blog do to a deep dive into the prototype object and how prototype-based inheritance works, but I’ll give you a brief overview.&lt;/p&gt;
&lt;p&gt;Each object in JavaScript has a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes&quot;&gt;&lt;strong&gt;prototype object&lt;/strong&gt;&lt;/a&gt;, which acts as a template that it inherits methods and properties from. That same prototype object may also have a prototype object that it inherits from as well, and so on, and so forth. This is referred to sometimes as the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes#the_prototype_chain&quot;&gt;&lt;strong&gt;prototype chain&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When a property or method is called on an object, the browser first checks to see if the actual object has the method on it, if not it checks if the method is available to it through its prototype object. If the method’s not defined on the object’s personal constructor (where its prototype object comes from), the browser checks up another level to see if the &lt;em&gt;constructor’s&lt;/em&gt; prototype object has the method available to it. The browser will do this all the way up until it reaches the object at the top with &lt;code&gt;null&lt;/code&gt; as its prototype.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt8-classes-inheritance/i-love-lucy.webp&quot; alt=&quot;Lucy and Ethel hmmm faces&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Hmm…?&lt;/p&gt;
&lt;p&gt;Check out this example, this should help illustrate what I’m saying.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of traditional prototype-based inheritance&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Superhero(superName, realName, powers){
  this.superName = superName,
  this.realName = realName,
  this.powers = powers
}

const wonderWoman = new Superhero(&quot;Wonder Woman&quot;, &quot;Diana Prince&quot;, &quot;Strength and flight&quot;);
console.log(wonderWoman); 
/* Superhero {
  superName: &quot;Wonder Woman&quot;,
  realName: &quot;Diana Prince&quot;,
  powers: &quot;Strength and flight&quot; } */

Superhero.prototype.equipment = &quot;Lasso of truth&quot;;
console.log(wonderWoman.realName); // Diana Prince
console.log(wonderWoman.equipment); // Lasso of truth
console.log(wonderWoman.catchPhrase); // undefined
console.log(wonderWoman.hasOwnProperty(&quot;equipment&quot;)); // false
console.log(Superhero.hasOwnProperty(&quot;equipment&quot;)); // false
console.log(Superhero.prototype.hasOwnProperty(&quot;equipment&quot;)); // true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above in the example is a constructor called &lt;code&gt;Superhero&lt;/code&gt;, which defines a new super-powered crime fighter.&lt;/p&gt;
&lt;p&gt;I created &lt;code&gt;wonderWoman&lt;/code&gt;, and gave her the properties of &lt;code&gt;superName&lt;/code&gt;, &lt;code&gt;realName&lt;/code&gt;, and &lt;code&gt;powers&lt;/code&gt;. Then, I added a property called &lt;code&gt;equipment&lt;/code&gt; to the &lt;code&gt;Superhero&apos;s&lt;/code&gt; prototype object, with a value of &lt;code&gt;&quot;Lasso of truth&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When I called the object’s &lt;code&gt;realName&lt;/code&gt; property, &lt;code&gt;&quot;Diana Prince”&lt;/code&gt; is found on the object itself. When I called &lt;code&gt;equipment&lt;/code&gt;, &lt;code&gt;&quot;Lasso of truth”&lt;/code&gt; is found on the object constructor’s prototype. And when I try to call the property &lt;code&gt;catchPhrase&lt;/code&gt;, it comes back as &lt;code&gt;undefined&lt;/code&gt; because nowhere in the prototype chain does that property exist.&lt;/p&gt;
&lt;p&gt;It’s proved by the lines where I check if either &lt;code&gt;wonderWoman.hasOwnProperty()&lt;/code&gt; and &lt;code&gt;Superhero.hasOwnProperty()&lt;/code&gt; of &lt;code&gt;&quot;equipment&quot;&lt;/code&gt;, and both return false, but &lt;code&gt;Superhero.prototype.hasOwnProperty(&quot;equipment&quot;)&lt;/code&gt; returns &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That is JavaScript’s prototype-based inheritance in a nutshell. Keep in mind, this is what’s happening in the background when we’re using class-based syntax going forward.&lt;/p&gt;
&lt;p&gt;Now let’s get on to the new ES6 classes.&lt;/p&gt;
&lt;h2&gt;Then came classes&lt;/h2&gt;
&lt;p&gt;Unlike other object oriented programming (OOP) languages like Java, which have always been class-based, JavaScript chose prototypes for its way of handling inheritance, but with the release of ECMAScript 2015, classes were introduced to the language’s syntax.&lt;/p&gt;
&lt;p&gt;Let me be absolutely clear though: &lt;strong&gt;classes are just syntactical sugar over JavaScript’s existing prototype-based inheritance.&lt;/strong&gt; They are NOT a new object-oriented inheritance model.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes&quot;&gt;&lt;strong&gt;Classes&lt;/strong&gt;&lt;/a&gt; are what might be defined as &quot;special functions&quot;, and just like with all functions, which I wrote about &lt;a href=&quot;./arrow-functions-java-script-es-6-feature-series-pt-2&quot;&gt;here&lt;/a&gt;, they can defined in two ways: class expressions and class declarations.&lt;/p&gt;
&lt;h3&gt;Class declarations&lt;/h3&gt;
&lt;p&gt;The first way to define a class is using a &lt;strong&gt;class declaration&lt;/strong&gt;. To declare a class, you use the &lt;code&gt;class&lt;/code&gt; keyword with the name of the class.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of class declaration&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Book {
  constructor(title, author) {
    this.title = title;
    this.author = author;
  }
}

const novel = new Book(&quot;Moby Dick&quot;, &quot;Herman Melville&quot;);
console.log(novel); // Book { title: &quot;Moby Dick&quot;, author: &quot;Herman Melville&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One important thing to note is that unlike function declarations, &lt;strong&gt;class declarations ARE NOT hoisted&lt;/strong&gt;. You must first declare your class, and then access it, otherwise you’ll get a &lt;code&gt;ReferenceError&lt;/code&gt; thrown.&lt;/p&gt;
&lt;h3&gt;Class expressions&lt;/h3&gt;
&lt;p&gt;The other way to define a class is with a &lt;strong&gt;class expression&lt;/strong&gt;. Class expressions can be named or unnamed. If a class expression is named, the name given to a named class expression is local to the class’s body.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of class expressions, both unnamed and named&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// unnamed class expression
let Drama = class {
  constructor(title, author){
    this.title = title;
    this.author = author;
  }
};
console.log(Drama.name); // Drama

// named class expression
let Comedy = class Book2 {
  constructor(title, author){
    this.title = title;
    this.author = author;
  }
};
console.log(Comedy.name); // Book2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, the basics of creating classes are out of the way, time to dive into the nitty-gritty details.&lt;/p&gt;
&lt;h2&gt;Class body &amp;amp; method definitions&lt;/h2&gt;
&lt;p&gt;Similar to functions once again, the body of the class is the part contained within the &lt;code&gt;{}&lt;/code&gt;. In here is where the class members like the constructor and methods are defined.&lt;/p&gt;
&lt;h3&gt;Strict mode&lt;/h3&gt;
&lt;p&gt;The first thing you need to know is that the body of a class is always executed in &lt;code&gt;strict&lt;/code&gt; mode.&lt;/p&gt;
&lt;p&gt;All this means is code written here is subject to stricter syntax for increased performance, some otherwise silent errors will be thrown, and certain keywords are reserved for future versions of ECMAScript.&lt;/p&gt;
&lt;p&gt;If you’ve been using any of the newer React, Angular or Vue frameworks, you’ve probably already been developing in strict mode by default, so it shouldn’t pose too much of a shift in your way of developing.&lt;/p&gt;
&lt;h3&gt;The constructor&lt;/h3&gt;
&lt;p&gt;Next up in the anatomy of a class is, potentially, a constructor. The &lt;code&gt;constructor&lt;/code&gt; method is a special method for creating and initializing an object created with a &lt;code&gt;class&lt;/code&gt;. There can only be one special method with the name &quot;constructor&quot; in each class. If a class contains more than one occurrence of a &lt;code&gt;constructor&lt;/code&gt; method, a &lt;code&gt;SyntaxError&lt;/code&gt; will be thrown.&lt;/p&gt;
&lt;p&gt;A constructor can also use the super keyword to call the constructor of the &lt;code&gt;super&lt;/code&gt; class, but I’ll get to that in more detail later in this post.&lt;/p&gt;
&lt;h3&gt;Prototype methods&lt;/h3&gt;
&lt;p&gt;Prototype methods can also be known as &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions&quot;&gt;&lt;strong&gt;method definitions&lt;/strong&gt;&lt;/a&gt;, and they’re a shorthand for a function assigned to the method’s name. These tend to make up the bulk of the class’s body.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of a prototype method on a class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Book {
  constructor(title, author){
    this.title = title;
    this.author = author;
  }

  publicizeBook() {
    return `This book ${this.title} is written by renowned author ${this.author}.`;
  }
}

const novel = new Book(&quot;Harry Potter&quot;, &quot;J.K. Rowling&quot;);
console.log(novel.publicizeBook()); // This book Harry Potter is written by renowned author J.K. Rowling.

console.log(Book.prototype.hasOwnProperty(&quot;publicizeBook&quot;)); // true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this class &lt;code&gt;Book&lt;/code&gt;, the method &lt;code&gt;publicizeBook()&lt;/code&gt; is defined on it, so any objects created with the class of &lt;code&gt;Book&lt;/code&gt;, will automatically also have the prototype method &lt;code&gt;publicizeBook()&lt;/code&gt; available to them.&lt;/p&gt;
&lt;p&gt;And check out the last line in the example. I check if the &lt;code&gt;Book&lt;/code&gt; class owns the &lt;code&gt;publicizeBook()&lt;/code&gt; method by testing if the &lt;code&gt;Book&lt;/code&gt;&apos;s prototype object &lt;code&gt;.hasOwnProperty(&quot;publicizeBook&quot;)&lt;/code&gt;, and it returns true. Which shows it’s actually prototype-based inheritance happening underneath at all.&lt;/p&gt;
&lt;p&gt;Starting to make sense now?&lt;/p&gt;
&lt;h3&gt;Static methods&lt;/h3&gt;
&lt;p&gt;When you use the &lt;code&gt;static&lt;/code&gt; keyword, it can be applied to either a method or a class. Static methods are called without instantiating their class and &lt;em&gt;cannot&lt;/em&gt; be called through a class instance. These types of methods are often used to create utility functions for an application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of a static method on a class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Book {
  constructor(title, author){
    this.title = title;
    this.author = author;
  }

  static youMightLike(title, similarTitle) {
    return `If you like ${title}, you might also like ${similarTitle}.`
  }
}

const novel = new Book(&quot;Moby Dick&quot;, &quot;Herman Melville&quot;);
console.log(novel.youMightLike); // undefined

console.log(Book.youMightLike(novel.title, &quot;A Midsummer Night&apos;s Dream&quot;)); // If you like Moby Dick, you might also like A Midsummer Night&apos;s Dream.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this example, if you try to call the static method &lt;code&gt;youMightLike()&lt;/code&gt; on the actual class-based object &lt;code&gt;novel&lt;/code&gt;, you only get back an &lt;code&gt;undefined&lt;/code&gt; value. If you call it, however, on the class &lt;code&gt;Book&lt;/code&gt;, with two parameters, you’ll get back a response recommending one book based on another book.&lt;/p&gt;
&lt;h3&gt;Beware of boxing with prototype &amp;amp; static methods&lt;/h3&gt;
&lt;p&gt;When a method, either static or not, is called without a value for &lt;code&gt;this&lt;/code&gt; assigned to it, the &lt;code&gt;this&lt;/code&gt; value will be &lt;code&gt;undefined&lt;/code&gt; inside the method. It’s because the body of the class always runs in &lt;code&gt;strict mode&lt;/code&gt; regardless of whether it’s explicitly set or not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of undefined ‘this’ inside a class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Dog {
  eat() {
    return this;
  }
  
  static speak() {
    return this;
  }
}

let shibaInu = new Dog();
console.log(shibaInu.eat()); // Dog {}
let chowDown = shibaInu.eat;
console.log(chowDown); // undefined
console.log(Dog.speak.toString()); // Class Dog
let greet = Dog.speak;
console.log(greet); // undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you write the above class in the traditional function-based syntax, then autoboxing in method calls will happen in non–strict mode based on the initial &lt;code&gt;this&lt;/code&gt; value. If the initial value is &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;this&lt;/code&gt; will be set to the global object.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of this taking the global scope if it’s not assigned the function&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Dog() { };

Dog.prototype.eat = function() {
  return this;
}

Dog.speak = function() {
  return this;
}

let husky = new Dog();
console.log(husky.eat()); // Dog {}

let munch = husky.eat;
console.log(munch()); // global object (long list of available options)

let bark = Dog.speak;
console.log(bark()); // global object again (long list of available options)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just be aware of this little difference between classes and functions, so it doesn’t unwittingly trip you up for a few hours.&lt;/p&gt;
&lt;h3&gt;Instance properties&lt;/h3&gt;
&lt;p&gt;Instance properties must be defined inside of class methods.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of defined instance properties inside the class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Cat {
  constructor(eats, sleeps){
    this.eats = eats;
    this.sleeps = sleeps;
  }
  
  knocksThingsOver(obj) {
    return `Woops, the cat just knocked ${obj} over...`
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While static data properties and prototype data properties must be defined outside of the ClassBody declaration:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example defining static data &amp;amp; prototype data properties&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cat.plays = true;

Cat.prototype.eatsCatnip = &quot;Goes nuts for it&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Field declarations (still experimental)&lt;/h3&gt;
&lt;p&gt;These next features: public and private field declarations are still in the experimental feature (stage 3), proposed at TC39, by the JavaScript standards committee. But they’re still worth knowing about as they’ll probably make it into the standard syntax sometime soon.&lt;/p&gt;
&lt;p&gt;Native support in browsers is limited as of now, but the feature can be used through a build step with systems like Babel, courtesy of your Webpack config.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Public declarations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the JavaScript field declaration syntax, the previous example of &lt;code&gt;Cat&lt;/code&gt; can be written like so.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of public declarations in a class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Cat {
  eats = &quot;mice&quot;;
  sleeps;

  constructor(eats, sleeps){
    this.eats = eats;
    this.sleeps = sleeps;
  }

  knocksThingsOver(obj) {
    return `Woops, the cat just knocked ${obj} over...`
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By declaring fields up-front, class definitions become more self-documenting, and the fields are always present. It’s also cool that the fields can be declared with or without a default value, just like default values in functions, which I wrote about &lt;a href=&quot;./default-function-parameter-values-java-script-es-6-feature-series-pt-3&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Private declarations&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Private declarations aren’t too different syntactically from their public counterparts. But they are slightly different in usage and execution.&lt;/p&gt;
&lt;p&gt;Private fields can only be declared up-front in a field declaration. They cannot be created later through assigning to them, the way normal properties can.&lt;/p&gt;
&lt;p&gt;It’s also an error to reference private fields from outside of the class; they can only be read or written within the class body. By defining things which are not visible outside of the class, you ensure that your classes’ users can’t depend on internals, which may change version to version.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of private declarations in a class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Cat {
  #eats = &quot;mice&quot;;
  #sleeps;

constructor(eats, sleeps){
    this.#eats = eats;
    this.#sleeps = sleeps;
  }

knocksThingsOver(obj) {
    return `Woops, the cat just knocked ${obj} over...`
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Like I said before, not widely in use yet, and I probably wouldn’t put it into production, but keep an eye out for these in future ES releases.&lt;/p&gt;
&lt;h3&gt;Sub classing with &lt;code&gt;extends&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;extends&lt;/code&gt; keyword is used in &lt;strong&gt;class declarations&lt;/strong&gt; or &lt;strong&gt;class expressions&lt;/strong&gt; to create a class as a child of another class.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of extending one class into a child as a sub class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(`${this.name} makes a noise`);
  }
}

class Horse extends Animal {
  constructor(name) {
    super(name);
  }
  speak() {
    console.log(`${this.name} whinnies.`)
  }
}

let thoroughbred = new Horse(&quot;Seabiscuit&quot;);
console.log(thoroughbred.speak()); // Seabiscuit whinnies.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The class &lt;code&gt;Horse&lt;/code&gt; extends the other class &lt;code&gt;Animal&lt;/code&gt;, to take in its methods, and since &lt;code&gt;Horse&lt;/code&gt; also has its own constructor present, it needs to call &lt;code&gt;super()&lt;/code&gt; before referencing &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This syntax of &lt;code&gt;extends&lt;/code&gt; is very similar to React’s class-based components, if you’ve ever worked with that framework.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;React class-based component syntax&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { Component } from &quot;react&quot;;

class Nav extends Component {
  // ...do something
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s also worth noting, when methods for a parent and child class are named similarly, the child’s method takes precedence over the parent’s method when calling it.&lt;/p&gt;
&lt;h3&gt;Super class calls with &lt;code&gt;super&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Now we’re back to that &lt;code&gt;super&lt;/code&gt; keyword that’s been mentioned above a few times. The &lt;code&gt;super&lt;/code&gt; keyword is used to call corresponding methods of super class. This is one distinct advantage over prototype-based inheritance, because technically, both methods from the parent and child class could be invoked just by using &lt;code&gt;super&lt;/code&gt; instead of one or the other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of accessing the parent class methods from the child class&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise`);
  }
}

class Hippo extends Animal {
  speak() {
    super.speak();
    console.log(`${this.name} roars.`);
  }
}

let hippo = new Hippo(&quot;Bertha&quot;);
console.log(hippo.speak()); // Bertha makes a noise.
// Bertha roars.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;Hippo&lt;/code&gt;&apos;s &lt;code&gt;speak()&lt;/code&gt; method actually calls both &lt;code&gt;Animal&lt;/code&gt;&apos;s &lt;code&gt;speak()&lt;/code&gt; method as well as its own unique one, by simply using &lt;code&gt;super.speak()&lt;/code&gt; inside of &lt;code&gt;Hippo&lt;/code&gt;&apos;s &lt;code&gt;speak()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that’s really all there is to &lt;code&gt;super&lt;/code&gt;, it’s not so complicated once some examples are shown. Right?&lt;/p&gt;
&lt;p&gt;And this, is really the most important parts about classes you’ll need to know while developing in JavaScript. Well done for making it to the end of this article! 😃&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Classes have existed in other programming languages for decades, and JavaScript finally got on board (sort of) with the release ES 2015. Although classes in JavaScript look the same syntactically as other OOP languages, it’s still really prototype-based inheritance taking place under the hood.&lt;/p&gt;
&lt;p&gt;This new way of thinking about methods and properties may take a little getting used to for all of us familiar with traditional prototype object, but classes provide some really great improvements to make our development lives easier, and I hope you’ll try them out to see for yourself.&lt;/p&gt;
&lt;p&gt;My aim with this series is to deeply explain pieces of the ES6 syntax you use every day so you can use them for maximum impact and avoid common pitfalls.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll give ES6 class-syntax a chance in your JavaScript for easier prototype inheritance.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes&quot;&gt;Object prototypes&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes&quot;&gt;Classes&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Built-in Module Imports and Exports: JavaScript ES6 Feature Series (Pt 7)</title><link>https://www.paigeniedringhaus.com/blog/built-in-module-imports-and-exports-javascript-es6-feature-series-pt-7/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/built-in-module-imports-and-exports-javascript-es6-feature-series-pt-7/</guid><description>Import means never having to write &quot;require&quot; again</description><pubDate>Mon, 14 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt7-import-export/pencils-hero.webp&quot; alt=&quot;wooden pencil holder full of colored pencils&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind these pieces is simple: There are still plenty of developers for whom JavaScript doesn’t make a whole lot of sense — or at the very least, is perplexing at times.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript&quot;&gt;Wikipedia&lt;/a&gt;, JavaScript powers just under 95% of the 10 million most popular web pages, as of May 2017.&lt;/p&gt;
&lt;p&gt;Since JS powers so much of the web, I wanted to provide a slew of pieces and examples of ES6+ features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these pieces to be short, in-depth explanations of various improvements to the language that I hope will inspire you to write some really cool stuff using JS. Who knows? You might even learn something new along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Piece seven in my series concerns built-in module support in JavaScript, the easier way to make objects, functions, classes, and variables available anywhere in your codebase, with minimal syntax.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Require is replaced by ES modules&lt;/h2&gt;
&lt;p&gt;Before I dive into built-in modules, let me give you a very brief history lesson on CommonJS and the &lt;code&gt;require&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;Pre-ES2015, the most widely used approach to adding various library modules to JavaScript files’ scope was via &lt;a href=&quot;http://www.commonjs.org/&quot;&gt;CommonJS&lt;/a&gt;. Node.js uses it, and it’s the system used by most packages on npm today. The main concept in CommonJS modules is a function called &lt;code&gt;require()&lt;/code&gt;. When you call this with the module name of a dependency, it makes sure the module is loaded and returns its interface to be used in the file’s scope.&lt;/p&gt;
&lt;p&gt;If you’ve ever worked with Node.js scripts, or even older client-side JavaScript files, you’ve likely seen this syntax before. Here’s an example that imports ExpressJS, a widely used server-side framework, into a Node.js &lt;code&gt;app.js&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anatomy of CommonJS&apos;s require&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const express = require(&quot;express&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simply by declaring the variable &lt;code&gt;express&lt;/code&gt; and calling &lt;code&gt;require(&quot;express&quot;)&lt;/code&gt;, all of ExpressJS’s various methods are now available to the file.&lt;/p&gt;
&lt;p&gt;For a long while, CommonJS modules worked quite well and allowed the JavaScript community, via npm, to share code on a large scale.&lt;/p&gt;
&lt;p&gt;But CommonJS has a few quirks that make it a less than ideal solution: namely, the fact that &lt;code&gt;require()&lt;/code&gt; is a normal function call taking any kind of argument, not just a string literal, which makes it hard to determine the dependencies of a module without running its code. There are more issues than this, but I won’t get into them here. This is a brief history, after all.&lt;/p&gt;
&lt;p&gt;Suffice it to say, ES2015 introduced its own module system, and in doing so, integrated the new module support notation into the language. The main concepts of dependencies and interfaces remain the same, but the details differ — which is what I’ll be discussing now.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you’d like a deeper dive into modules, packages, and CommonJS, I’d recommend reading &lt;a href=&quot;https://eloquentjavascript.net/10_modules.html&quot;&gt;this chapter&lt;/a&gt; out of Eloquent JavaScript.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But for now, let’s get on with ES6’s built-in module support.&lt;/p&gt;
&lt;h2&gt;Import all the things&lt;/h2&gt;
&lt;p&gt;One of the biggest departures from CommonJS’s module syntax, when ES modules came to town, is the special new keyword &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import&quot;&gt;&lt;strong&gt;&lt;code&gt;import&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; to access a dependency.&lt;/p&gt;
&lt;p&gt;Let’s go through all the different types of imports that are available. In the section below this, I’ll go through the export options as well.&lt;/p&gt;
&lt;h3&gt;Import default exports&lt;/h3&gt;
&lt;p&gt;The very first type of import revolves around &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#default_import&quot;&gt;&lt;strong&gt;default imports&lt;/strong&gt;&lt;/a&gt;. This is the most frequently used type of import, and there are a few different ways default exports can be combined with other types of imports.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Simplest example importing only the default export:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import carTires from &quot;./autoParts/tires.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this first example, &lt;code&gt;carTires&lt;/code&gt; is the default export from the file &lt;code&gt;tires.js&lt;/code&gt;. To get access to it in this file, all that needs to be done is to declare the export by the same name.&lt;/p&gt;
&lt;p&gt;If a file has more than one value you’d like access to (like say, a function or variable, plus a default export) the syntax would look like the following example of import of a default export and an additional function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import carTires, { shineTires } from &quot;./autoParts/tires.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The destructured export &lt;code&gt;{ shineTires }&lt;/code&gt; is what’s known as a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import&quot;&gt;&lt;strong&gt;named import&lt;/strong&gt;&lt;/a&gt; in this particular import statement, since it’s wrapped in curly braces and exported by the same name from the &lt;code&gt;tires.js&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;There’s one other option where default exports can be combined with an entire module’s contents via a wildcard import &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of importing a default export plus all the other exports in a file:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import carTires, * as tireOptions from &quot;./autoParts/tires.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If there was a variable called &lt;code&gt;tireType&lt;/code&gt; and a function called &lt;code&gt;rotateTires()&lt;/code&gt; from the file &lt;code&gt;tires.js&lt;/code&gt;, the importing file could access them both by calling &lt;code&gt;tireOptions.tireType&lt;/code&gt; or &lt;code&gt;tireOptions.rotateTires()&lt;/code&gt;. Since the additional exports were imported with the syntax &lt;code&gt;* as tireOptions&lt;/code&gt;, all exports from the file can be referenced &lt;code&gt;tireOptions.xyz&lt;/code&gt;. This is known as a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#namespace_import&quot;&gt;&lt;strong&gt;namespace import&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you’re importing a default export along with named or namespace imports, be aware that the default export will have to be declared first.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But I’m getting ahead of myself. Let’s move on from importing default exports to all the other import types, and then the details should become more clear.&lt;/p&gt;
&lt;h3&gt;An entire module&apos;s contents: namespace imports&lt;/h3&gt;
&lt;p&gt;As I alluded to above, if a file has lots of individual exports you’d like access to, without having to import them all by name, there’s a way to do so with the help of &lt;code&gt;import * as abc&lt;/code&gt; or a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#namespace_import&quot;&gt;&lt;strong&gt;namespace import&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This inserts abc into the current scope, containing all the exports from the module in the file located in &lt;code&gt;/romanAlphabet/letters.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of importing multiple exports all at once from a file:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as abc from &quot;/romanAlphabet/letters.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, accessing the exports means using the module name (&lt;code&gt;abc&lt;/code&gt; in this case) as a &lt;strong&gt;namespace&lt;/strong&gt;. For example, if the module imported above includes an export &lt;code&gt;singMyAbcs()&lt;/code&gt;, you would call it like this: &lt;code&gt;abc.singMyAbcs()&lt;/code&gt;;&lt;/p&gt;
&lt;p&gt;Simple enough, right? Now let’s move on.&lt;/p&gt;
&lt;h3&gt;A single export from a module: named import&lt;/h3&gt;
&lt;p&gt;The second example above, in the default export section, touched on is named imports, a simple way to bring in just one object or value into the importing file’s scope using ES6 object destructuring.&lt;/p&gt;
&lt;p&gt;Here’s another example of a single named import to make it even more clear:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { apples } from &quot;./plants/fruits.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The object &lt;code&gt;apples&lt;/code&gt; is exported from the file &lt;code&gt;fruits.js&lt;/code&gt;, either &lt;em&gt;implicitly&lt;/em&gt; because the whole module is exported or &lt;em&gt;explicitly&lt;/em&gt; using the &lt;code&gt;export&lt;/code&gt; statement, and is then inserted into the current scope.&lt;/p&gt;
&lt;p&gt;This same syntax can be used for multiple imports too.&lt;/p&gt;
&lt;h3&gt;Multiple exports from a single module&lt;/h3&gt;
&lt;p&gt;Similar to a single named import, multiple values and objects from a file can be exported using the same code style.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of multiple named imports:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { carrots, potatoes, onions } from &quot;./plants/veggies.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All the exports from &lt;code&gt;veggies.js&lt;/code&gt; are imported into the current file’s scope, and are accessible by name, just the same as a single imported value.&lt;/p&gt;
&lt;h3&gt;Alias an import with a more convenient name&lt;/h3&gt;
&lt;p&gt;Now suppose you have an export you’d like to import into your file, but it has a terribly long name like &lt;code&gt;mySuperCaliFragilisticExpialidociusObject&lt;/code&gt;. That’s quite a pain to type out, right?&lt;/p&gt;
&lt;p&gt;Well, there’s a solution: aliasing an export with a more convenient name when importing it. Check this out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example renaming a named export for convenience:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { mySuperCaliFragilisticExpialidociusObject as mySuperObject } from &quot;./maryPoppins.js&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whenever you need to access the imported value in the current scope, you can simply call it with &lt;code&gt;mySuperObject&lt;/code&gt; instead of the original, much longer exported name. How convenient!&lt;/p&gt;
&lt;h3&gt;Rename multiple exports during import&lt;/h3&gt;
&lt;p&gt;But say you have multiple long, named export objects. Can you rename all of them on import? Well, as it turns out, you can.&lt;/p&gt;
&lt;p&gt;Just like renaming one export, you can rename multiple exports on import.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of aliasing multiple exports:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { ladyMaryCrawley as ladyMary, ladyEdithCrawley as ladyEdith, ladyCoraCrawley as ladyGrantham } from &quot;./downtonAbbeyFamily/ladies.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of the ladies from Downton Abbey being imported into the current file have quite long titles, so, for convenience, the current scope will access them all with their shortened aliases of &lt;code&gt;ladyMary&lt;/code&gt;, &lt;code&gt;ladyEdith&lt;/code&gt;, and &lt;code&gt;ladyGrantham&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Import side effects only&lt;/h3&gt;
&lt;p&gt;This next example I’ve never used personally, but you have the option to import an entire module for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#import_a_module_for_its_side_effects_only&quot;&gt;&lt;strong&gt;side effects&lt;/strong&gt;&lt;/a&gt; only, without importing anything. This has the side effect of running the module’s global code, while not actually importing any values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of importing a module without importing anything in particular:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import &quot;./helperFunctions.js&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If anything, this syntax reminds me quite a bit of the way CSS files are now imported into individual JavaScript files.&lt;/p&gt;
&lt;h3&gt;Dynamic imports&lt;/h3&gt;
&lt;p&gt;Ok, last import to go over: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import#module_namespace_object&quot;&gt;&lt;strong&gt;dynamic imports&lt;/strong&gt;&lt;/a&gt;. This proposal is due to be finalized in the ES2020 release, so I wouldn’t put it into production just yet, but it’s worth being aware of.&lt;/p&gt;
&lt;p&gt;The import keyword may be called as a function to dynamically import a module. When used this way, it returns a promise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of dynamic imports with promise syntax:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import (&quot;./waysToTravel.js&quot;)
  .then((vehicles) =&amp;gt; {
    // do something with planes, trains and automobiles
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can also be used with the newer ES6 &lt;code&gt;async/await&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of dynamic imports with async / await syntax:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let vehicles = await import(&quot;./waysToTravel.js&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I haven’t used this type of import myself yet, but it’s quite nice that they’re working on so many different ways to access objects and values across scopes with the help of built-in module support.&lt;/p&gt;
&lt;h2&gt;Export all the other things&lt;/h2&gt;
&lt;p&gt;All right, we’ve covered the import side of ES6’s module support. Now let’s look at the other half of the equation: the ES6 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export&quot;&gt;&lt;strong&gt;&lt;code&gt;export()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; keyword and syntax.&lt;/p&gt;
&lt;h3&gt;Default exports&lt;/h3&gt;
&lt;p&gt;If you’ve worked in ReactJS at all, you’ll probably be very familiar with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export&quot;&gt;&lt;strong&gt;default exports&lt;/strong&gt;&lt;/a&gt;. If you simply place the &lt;code&gt;default&lt;/code&gt; keyword after the variable that you’re defining for export, it becomes the default export. Therefore, you’ve excluded it from needing curly braces when being imported into another file. Let’s take a look at some examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of a default function, variable or class export from a file:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// this is how to export a function as a default
export default function getMovies() {
  // fetch some movie data and return it
};

// this is how to export a variable as a default
export default const movie = {
 title: &quot;The Lion King&quot;, 
 releaseDate: &quot;July 19, 2019&quot;,
 synopsis: &quot;Simba idolizes his father, King Mufasa, and takes to heart his own royal destiny on the plains of Africa.&quot;
};

// this is how to export an ES6 class (a React class to be exact)
export default class Movies extends Component {
  // render some movie data in JSX
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Take note: each JavaScript file can only have one default export. All other exports in that same file will just have the &lt;code&gt;export&lt;/code&gt; keyword in front of them.&lt;/p&gt;
&lt;h3&gt;Individual named exports&lt;/h3&gt;
&lt;p&gt;The next type of export to cover is individual &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#using_named_exports&quot;&gt;&lt;strong&gt;named exports&lt;/strong&gt;&lt;/a&gt;, which I touched on when discussing the imports of such values in the import section above.&lt;/p&gt;
&lt;p&gt;Named exports aren’t very complicated — as I said before, anything besides a default export in a file you’d like to make available for use in other JavaScript files can be a named export.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of multiple named exports in a file:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// this first array of pets is available to be imported into any other file because it has the &quot;export&quot; keyword
export const myPets = [ &quot;dog&quot;, &quot;cat&quot;, &quot;guinea pig&quot;, &quot;gold fish&quot;];

// mySecretPets can&apos;t be directly accessed outside the scope of this file because it lacks the &quot;export&quot; keyword ahead of it
const mySecretPets = [ &quot;dragon&quot;, &quot;griffin&quot;, &quot;Loch Ness monster&quot;, &quot;Big Foot&quot;]

// nameMyPets can be called in the scope of other files
export function nameMyPets() {
  console.log(myPets, mySecretPets)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see from the examples above, both the variable myPets and the function &lt;code&gt;nameMyPets&lt;/code&gt; are explicitly exported from the file and can thus be imported into another file using the named import syntax: &lt;code&gt;import { myPets, nameMyPets } from &quot;./pets.js&quot;;&lt;/code&gt;. The other variable &lt;code&gt;mySecretPets&lt;/code&gt;, however, is not exported from the file and therefore cannot be accessed explicitly outside of its original scope.&lt;/p&gt;
&lt;h3&gt;Multiple named exports in a single line&lt;/h3&gt;
&lt;p&gt;There’s another way you can export multiple values from a single file in JavaScript, as well, if you prefer not to type &lt;code&gt;export&lt;/code&gt; multiple times throughout the file.&lt;/p&gt;
&lt;p&gt;At the end of the module, with syntax almost identical to importing multiple named imports, you can declare any values you’d like to make exportable to other scopes outside of the current file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of a single line with multiple named exports:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export { cakes, cookies, makeDessert, makeTea };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you can imagine in the example above that the variables cakes and cookies existed along with the functions &lt;code&gt;makeDessert()&lt;/code&gt; and &lt;code&gt;makeTea()&lt;/code&gt;, and you wanted all of those values to be accessible in other areas of your codebase, simply by exporting them all at the end of the module, you could have access to them wherever else you desired.&lt;/p&gt;
&lt;p&gt;It’s a slightly cleaner syntax, but really, explicit exports for each value or a single export for all the values at the end of the module will achieve exactly the same thing for you.&lt;/p&gt;
&lt;h3&gt;Exporting with aliases&lt;/h3&gt;
&lt;p&gt;The final export option I’ll cover is exporting with aliases, which is similar to importing with aliases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example of aliasing exports:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export { dumplings, xiaoLongBao as soupDumplings, bbqPorkBuns, orderDimSum, pickUpSteamerBaskets, pourTea as fillTeaCups };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just as with renaming named exports in the import file, you can actually rename the exports as you export them. In the example above, I renamed the variable &lt;code&gt;xiaoLongBao&lt;/code&gt; to &lt;code&gt;soupDumplings&lt;/code&gt;, and the function &lt;code&gt;pourTea&lt;/code&gt; to &lt;code&gt;fillTeaCups&lt;/code&gt; for importing into any other scope.&lt;/p&gt;
&lt;p&gt;Honestly, I’m not really sure why you’d give a value one name in a file and then choose to export it with a different name to all other files. (If there was a naming collision in another file’s scope, why not just rename the import then?) But it’s an option, and I want to arm you with all the knowledge I can.&lt;/p&gt;
&lt;p&gt;And this concludes our tour through the ins and outs of imports and exports via ES6’s built-in module support!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;JavaScript’s ES6 syntax has been out for a number of years now (and gaining wider and wider adoption as time passes), but it introduced some groundbreaking changes to the language, which were too foreign for some developers to be excited about learning immediately.&lt;/p&gt;
&lt;p&gt;And while I can agree that it’s quite different, it’s also incredibly powerful and makes writing JavaScript code so much easier than it was just a few years prior.&lt;/p&gt;
&lt;p&gt;My aim with this series of pieces is to highlight bits of the ES6 syntax you use every day and explain how you can use these new parts of the JavaScript language for maximum impact.&lt;/p&gt;
&lt;p&gt;Up until now, there was no standardized, built-in module support for all the wonderfully helpful JavaScript library modules out there in npm. ES2015 changed that and brought in new specialized keywords and a myriad of ways to import and export all sorts of JS values from one scope to another with a lot less fuss and bother than before. It’s been quite a game-changer.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll start to take advantage of built-in module support in your own projects if you haven’t already.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import&quot;&gt;import&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export&quot;&gt;export&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eloquentjavascript.net/10_modules.html&quot;&gt;ES modules&lt;/a&gt;, Eloquent JavaScript&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Enhanced Object Literal Value Shorthand: JavaScript ES6 Feature Series (Pt 6)</title><link>https://www.paigeniedringhaus.com/blog/enhanced-object-literal-value-shorthand-javascript-es6-feature-series-pt-6/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/enhanced-object-literal-value-shorthand-javascript-es6-feature-series-pt-6/</guid><description>Because typing the same thing twice in an object is crazy.</description><pubDate>Sun, 29 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/glasses.jpeg&quot; alt=&quot;pair of glasses resting on a desk in front of screens filled with code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind these posts is simple: there are still plenty of developers for whom, JavaScript doesn’t make a whole lot of sense — or at the very least, is perplexing at times.&lt;/p&gt;
&lt;p&gt;According to Wikipedia, JavaScript powers just under 95% of the 10 million most popular web pages, as of May 2017.&lt;/p&gt;
&lt;p&gt;Since JS powers so much of the web, I wanted to provide a slew of articles and examples of ES6+ features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these articles to be short, in-depth explanations about various improvements to the language, that I hope will inspire you to write some really cool stuff using JS. Who knows, you might even learn something new along the way. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My sixth post in this series will be about the new object property and method value shorthands introduced by ES2015, the most concise ways yet to initialize object properties from variables and define functions.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Objects: everything in JavaScript is one&lt;/h2&gt;
&lt;p&gt;When it comes to JavaScript, you may have heard the phrase thrown around that &quot;everything in JavaScript is an object.&quot; Functions, strings, arrays, objects — they’re all objects. It can also be something else, but except for primitives, everything else is also an object in JS.&lt;/p&gt;
&lt;p&gt;This article, however, concerns itself with object objects; the ones commonly initialized using the &lt;code&gt;new Object()&lt;/code&gt;, &lt;code&gt;Object.create()&lt;/code&gt; or literal notation initializers.&lt;/p&gt;
&lt;p&gt;Let’s look at them before we get to the new changes courtesy of ES2015.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object initializer examples: new Object()&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// object constructor
function Pet(type, name, age, greeting) {
  this.breed = type;
  this.name = name;
  this.age = age;
  this.greeting = greeting;
  this.sayHello = function () {
    return `${this.name} says &quot;hello&quot; as ${this.greeting}`;
  }
}

// new Object()
const pet1 = new Pet(&quot;cat&quot;, &quot;Felina&quot;, 3, &quot;meow&quot;);
console.log(pet1);

/* prints: Pet {
breed: &quot;cat&quot;,
name: &quot;Felina&quot;,
age: 3,
greeting: &quot;meow&quot;,
sayHello: [Function] } */

console.log(pet1.sayHello());
// prints: Felina says &quot;hello&quot; as meow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This first example shows how to create an object using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new&quot;&gt;&lt;strong&gt;&lt;code&gt;new Object()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; keywords. First, an object constructor called &lt;code&gt;Pet&lt;/code&gt; is defined, which takes in a number of parameters, and even has its own method, &lt;code&gt;sayHello()&lt;/code&gt; attached to it.&lt;/p&gt;
&lt;p&gt;Then, the variable &lt;code&gt;pet1&lt;/code&gt; is declared and &lt;code&gt;new Pet()&lt;/code&gt; is called with the appropriate parameters passed to it. Voilà — a new object named &lt;code&gt;pet1&lt;/code&gt; now exists when you call it or its method, &lt;code&gt;pet1.sayHello()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object initializer examples: Object.create()&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Object.create()
const pet2 = Object.create(pet1);
pet2.breed = &quot;dog&quot;;
pet2.name = &quot;Rufus&quot;;
pet2.age = 4;
pet2.greeting = &quot;woof&quot;;
console.log(pet2);

/* prints: Pet {
breed: &quot;dog&quot;,
name: &quot;Rufus&quot;,
age: 4,
greeting: &quot;woof&quot; } */

console.log(pet2.sayHello());
// prints: Rufus says &quot;hello&quot; as woof
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second example above demonstrates using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create&quot;&gt;&lt;strong&gt;&lt;code&gt;Object.create()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; initializer. This option requires an already existing object exist as the prototype for the newly created object.&lt;/p&gt;
&lt;p&gt;In this instance, &lt;code&gt;pet2&lt;/code&gt; takes &lt;code&gt;pet1&lt;/code&gt; from the first example as its prototype. Then, &lt;code&gt;pet2&lt;/code&gt; assigns all the properties from &lt;code&gt;pet1&lt;/code&gt; with new values, and it also inherits the method &lt;code&gt;sayHello()&lt;/code&gt; from pet1 as well.&lt;/p&gt;
&lt;p&gt;So when &lt;code&gt;pet2.sayHello()&lt;/code&gt; is called, it prints out &lt;code&gt;Rufus says &quot;hello&quot; as woof&lt;/code&gt;. Simple as that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object initializer examples: object literals {}&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// object literal initialization
const pet3 = {
  type: &quot;guinea pig&quot;,
  name: &quot;Holly&quot;,
  age: 6,
  greeting: &quot;snuffle&quot;,
  sayHello: function() {
    return `${this.name} says &quot;hello&quot; as ${this.greeting}`
  }
}

console.log(pet3);
/* prints: { type: &quot;guinea pig&quot;,
name: &quot;Holly&quot;,
age: 6,
greeting: &quot;snuffle&quot;,
sayHello: [Function] } */

console.log(pet3.sayHello());
// prints: Holly says &quot;hello&quot; as snuffle

// object literal property and method assignment by variables
const type = &quot;fish&quot;;
const name = &quot;Nemo&quot;;
const age = 2;
const greeting = &quot;bloop&quot;;
function sayHello() {
  return `${this.name} says &quot;hello&quot; as ${this.greeting}`;
}

const pet4 = {
  type: type,
  name: name,
  age: age,
  greeting: greeting,
  sayHello: sayHello
}

console.log(pet4);
/* prints: { type: &quot;fish&quot;,
name: &quot;Nemo&quot;,
age: 2,
greeting: &quot;bloop&quot;,
sayHello: [Function: sayHello] } */

console.log(pet4.sayHello()); 
// prints: Nemo says &quot;hello&quot; as bloop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This final object initialization is the most frequently used one in day-to-day coding, by far: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer&quot;&gt;&lt;strong&gt;object literal initialization&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It can be done two ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;By declaring the object and assigning all its properties and methods at the same time its initialized: like &lt;code&gt;pet3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;By declaring any variables and functions ahead of time, then assigning those to a new object, like &lt;code&gt;pet4&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However you choose to do it, both ways are perfectly acceptable, and frequently used.&lt;/p&gt;
&lt;p&gt;Object literals, in particular, are what ECMAScript 2015 improves dramatically upon, let’s see how.&lt;/p&gt;
&lt;h3&gt;Shorthand property names&lt;/h3&gt;
&lt;p&gt;The first thing ES2015 improved upon regarding object literals is the abbreviated initialization of a property within an object, provided that the property key matches an existing variable name. This is known by most as: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions&quot;&gt;&lt;strong&gt;shorthand property names&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional syntax for assigning variables to an object&apos;s properties&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// traditional object property assignment
const breed = &quot;chinchilla&quot;;
const howOld = 1;
const nickname = &quot;Chi Chi&quot;;
const activities = &quot;dust baths&quot;;

function funFact() {
  return `${this.nickname}&apos;s fun fact is she likes ${this.activities}`;
}

const exoticPet = {
  breed: breed,
  nickname: nickname,
  howOld: howOld,
  activities: activities,
  funFact: funFact
};

console.log(exoticPet);
/* { breed: &quot;chinchilla&quot;,
nickname: &quot;Chi Chi&quot;,
howOld: 1,
activities: &quot;dust baths&quot;,
funFact: [Function: funFact] } */

console.log(exoticPet.funFact()); 
// prints: Chi Chi&apos;s fun fact is she likes dust baths
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above is the traditional way to assign variables to an object’s properties. Seems a lot of extra typing in creating &lt;code&gt;exoticPet&lt;/code&gt; when the properties already match the variable names doesn’t it?&lt;/p&gt;
&lt;p&gt;Let’s fix that redundancy in the next example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES2015 shorthand example of assigning like-named variables to an object’s properties&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// es2015 shorthand object property assignment
const otherBreed = &quot;alpaca&quot;;
const firstName = &quot;Alfie&quot;;
const likes = &quot;frolicking&quot;;
function timeSpent() {
  return `${this.firstName} enjoys ${this.likes} whenever he can.`;
}

const exoticPet2 = {
  otherBreed,
  firstName,
  likes,
  timeSpent
};

console.log(exoticPet2);
/* { otherBreed: &quot;alpaca&quot;,
firstName: &quot;Alfie&quot;,
likes: &quot;frolicking&quot;,
timeSpent: [Function: timeSpent] } */

console.log(exoticPet2.timeSpent());
// prints: Alfie enjoys frolicking whenever he can.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the syntax for &lt;code&gt;exoticPet2&lt;/code&gt; is much cleaner than the previous example. Since &lt;code&gt;exoticPet2&lt;/code&gt;’s property names match the variables declared above: &lt;code&gt;otherBreed&lt;/code&gt;, &lt;code&gt;firstName&lt;/code&gt;, and so on, you can simply declare the property names once and ES2015 understands how to insert the variables of the same name into the object.&lt;/p&gt;
&lt;p&gt;Pretty neat trick, huh? I do so appreciate this particular nicety of the ES6 improvements. I use it frequently.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Beware of using the same name for your properties, the second property will overwrite the first.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Beware: Duplicate properties assume the last value assignment&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// duplicate properties assume the last value assigned

const exoticPet3 = { type: &quot;parrot&quot;, type: &quot;cockatoo&quot;};

console.log(exoticPet3.type); // prints: cockatoo
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Shorthand method definitions&lt;/h3&gt;
&lt;p&gt;Next up in our improvements to object literals courtesy of ES2015: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#method_definitions&quot;&gt;&lt;strong&gt;method shorthand definitions&lt;/strong&gt;&lt;/a&gt;. Method definition shorthand syntax omits the &lt;code&gt;function&lt;/code&gt; keyword and colon, just like with the property assignments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional syntax to create methods (functions) in an object&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// traditional method definitions
const person = {
  play: function() {
    return &quot;I like to play board games with my friends.&quot;;
  },
  swim: function() {
    return &quot;When I exercise, I like to swim laps in the pool.&quot;;
  }
};

console.log(person.play()); // prints: I like to play board games with my friends.

console.log(person.swim()); // prints: When I exercise, I like to swim laps in the pool.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In traditional JavaScript, methods (functions attached to objects), similar to normal object properties, are declared on an object with a property name like &lt;code&gt;play&lt;/code&gt; or &lt;code&gt;swim&lt;/code&gt;, and then assigned values with the traditional anonymous function declaration syntax of &lt;code&gt;function() { /* ...do something here */ };&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, the object’s method can be called just like its properties are: &lt;code&gt;person.play()&lt;/code&gt; or &lt;code&gt;person.swim()&lt;/code&gt;. Nothing too earth shattering there.&lt;/p&gt;
&lt;p&gt;But does anyone really like anonymous functions much? Nah. It doesn’t seem to add much except unnecessary code, and if we have concise &lt;a href=&quot;./arrow-functions-java-script-es-6-feature-series-pt-2&quot;&gt;arrow function expressions&lt;/a&gt; now for traditional functions, why not make something similar for object methods too?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES2015 shorthand to create methods (functions) in an object&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// es2015 shorthand method definitions
const person2 = {
  play() {
    return &quot;I like to play the violin in my free time.&quot;;
  },
  swim() {
    return &quot;Swimming in the ocean is my favorite thing to do at the beach.&quot;;
  }
};

console.log(person2.play()); // prints: I like to play the violin in my free time.

console.log(person2.swim()); // prints: Swimming in the ocean is my favorite thing to do at the beach
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Introducing ES2015 method shorthands for object literal notation. The &lt;code&gt;person2&lt;/code&gt; object has two methods similar to &lt;code&gt;person1&lt;/code&gt;, &lt;code&gt;play()&lt;/code&gt;, and &lt;code&gt;swim()&lt;/code&gt;, and as you also see, the declarations on the the object itself lack the &lt;code&gt;function&lt;/code&gt; keyword, instead taking the property name and making that the function name instead.&lt;/p&gt;
&lt;p&gt;Cleaner, more succinct, and to be honest, it makes more sense to me when I read the code written this way than with the anonymous functions of old.&lt;/p&gt;
&lt;p&gt;Ok, time to move to the last ES2015 object literal improvement: computed property names.&lt;/p&gt;
&lt;h3&gt;Computed property names&lt;/h3&gt;
&lt;p&gt;Starting with ECMAScript 2015, the object initializer syntax supports computed property names. This feature allows you to put an expression in brackets &lt;code&gt;[]&lt;/code&gt;, that will be computed and used as the property name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES2015 shorthand for computing property keys / names via bracket notation&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// computed property names / keys
let i = 1;
const items = {
  [&apos;item&apos; + i++] : i,
  [&apos;otherItem&apos; + i++] : i,
  [&apos;aThirdItem&apos; + i++] : i
}

console.log(items); // prints: { item1: 2, otherItem2: 3, aThirdItem3: 4 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To be honest, I haven’t used this computed property names functionality once in daily life, but it’s nice to know it’s there if the situation should call for it, right?&lt;/p&gt;
&lt;p&gt;And that’s it. That’s what you need to know about object literals in JavaScript as of ES2015.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;All JS developers have gotten familiar with the language’s many quirks and gotchas over time, but lately, each year the ECMAScript committee releases new updates to the JavaScript language designed to make our lives easier. Some updated syntax changes look more foreign that others, but I’m happy to say the improvements to how we work with object literals are more similar to the older syntax than most.&lt;/p&gt;
&lt;p&gt;Happily, the changes result in concise objects that can be more easily assigned variables, methods and even new, computed property names. It’s pretty great.&lt;/p&gt;
&lt;p&gt;My aim with this blog series is to dive into some of my favorite parts of the JavaScript and ES6 syntax in use today, and show you how to use the best bits to maximum effect.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’re able to use this new object literal shorthand to make your own JavaScript objects more compact and manageable in the future.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer&quot;&gt;Object literal notation&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions&quot;&gt;Object property definitions shorthand&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Method_definitions&quot;&gt;Object method definitions shorthand&lt;/a&gt;, MDN docs&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>String Template Literals: JavaScript ES6 Feature Series (Pt 5)</title><link>https://www.paigeniedringhaus.com/blog/string-template-literals-javascript-es6-feature-series-pt-5/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/string-template-literals-javascript-es6-feature-series-pt-5/</guid><description>Why developers need to know where the backticks key is.</description><pubDate>Mon, 16 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt5-str-temp-literals/pen-hero.webp&quot; alt=&quot;Close up of ink pen writing on paper&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind these pieces is simple: there are still plenty of developers for whom JavaScript is somewhat mysterious. I agree, there’s a lot to understand — it’s a complex language, once you’ve scratched the surface.&lt;/p&gt;
&lt;p&gt;However, JavaScript powers 95% of the most popular web pages online today, according to Wikipedia, and on top of that the ECMAScript committee keeps releasing updates on a yearly basis. It’s a lot to keep up with.&lt;/p&gt;
&lt;p&gt;Since these changes are coming so fast and furious, I wanted to provide articles and examples of ES6+ features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is to keep these articles short. I will provide in-depth explanations of various improvements to the language, that I hope will inspire you to write some really cool stuff using JavaScript. Who knows, you might even learn something new along the way!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In my fifth piece, I’ll be discussing template literals: the newest, easiest way to work with strings in JavaScript.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Template Literals&lt;/h2&gt;
&lt;p&gt;Strings are one of the main JavaScript objects types. All they are is sequences of characters wrapped between single-quotes &lt;code&gt;&apos;&apos;&lt;/code&gt; or double-quotes &lt;code&gt;&quot;&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Anatomy of a traditional string&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const string1 = &apos;this is a string in single quotes&apos;;

const string2 = &quot;this is a string in double quotes&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The string type values above are immutable (unchangeable), but string objects, created by using the &lt;code&gt;String()&lt;/code&gt; constructor, are mutable, because they are objects and you can add new properties to them.&lt;/p&gt;
&lt;p&gt;But that’s JavaScript 101 and besides the point of this article. What I’m excited to talk about is &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot;&gt;&lt;strong&gt;template literals&lt;/strong&gt;&lt;/a&gt; (known as &quot;template strings&quot; pre-ES2015).&lt;/p&gt;
&lt;p&gt;To get us started, here’s the official MDN definition of template literals:&lt;/p&gt;
&lt;p&gt;&quot;Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them.&quot; — &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot;&gt;MDN web docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What do I mean when I say &quot;embedded expressions&quot; or &quot;string interpolation features&quot;? I’m so glad you asked, let me show you!&lt;/p&gt;
&lt;h3&gt;Template literals syntax&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// just a normal string in one line - not much different from a traditional string
const simpleString = `a template literal is surrounded by backticks`;

// a string spread across multiple lines
const multiLineString = `it can be spread across
multiple lines with just 
one set of enclosing backticks`;

const name = &quot;Paige&quot;;

// an expression placeholder allowing a variable to be injected into the string
const greetByName = `Hello, ${name}`;

console.log(greetByName); // &apos;Hello, Paige&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These three examples show what you can do with template literals.&lt;/p&gt;
&lt;p&gt;The first, &lt;code&gt;simpleString&lt;/code&gt;, is a single line string much like a normal JavaScript string surrounded by traditional quotes.&lt;/p&gt;
&lt;p&gt;The second, &lt;code&gt;multiLineString&lt;/code&gt;, is a multi-line string (return characters included even though you don’t see the &lt;code&gt;\r&lt;/code&gt; characters for them), that will print out exactly the way it’s written above.&lt;/p&gt;
&lt;p&gt;The third is an example of an expression placeholder, where the variable &lt;code&gt;name&lt;/code&gt; is inserted into the string &lt;code&gt;greetByName&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that I’ve shown you the quick way to use template literals, let’s get into the details of what you need to know about them.&lt;/p&gt;
&lt;h3&gt;Defining traits of template literals&lt;/h3&gt;
&lt;p&gt;Template literals have a number of characteristics that make them different from JavaScript strings of yesteryear. These same subtle differences also make them a lot more useful, in my opinion.&lt;/p&gt;
&lt;p&gt;Here’s what makes template literals unique.&lt;/p&gt;
&lt;h3&gt;Backticks&lt;/h3&gt;
&lt;p&gt;The easiest way to identify template literals is by the backticks (``) (also known as the grave accent) surrounding the characters instead of single or double quotes.&lt;/p&gt;
&lt;p&gt;For Mac users, the backtick key is located in the top left of the keyboard. It’s the same key you use for tildes &lt;code&gt;~&lt;/code&gt; in the command line terminal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Backtick string examples:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* your basic JavaScript strings, but with backticks. 
notice the lack of escape characters needed for things 
like single quotes, double quotes, and apostrophes
when backticks are employed */

const fooString = `A string called &apos;fooString&apos;`;

const barString = `Another string named &quot;barString&quot;`;

const bazString = `Without fooString and barString, you can&apos;t have bazString, right?`;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you need to write a backtick inside a template string, you must escape it with a backslash. &lt;code&gt;\&lt;/code&gt; is the same as &quot;`&quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some JavaScript developers have even suggested using Prettier and other auto-formatters to change all their strings to use backticks all the time. I myself default to using single quotes, unless I need the power of template literals, but that’s just me!&lt;/p&gt;
&lt;h3&gt;Expression placeholders&lt;/h3&gt;
&lt;p&gt;Template literals can contain placeholders, which are indicated within the string by the dollar sign and curly braces (&lt;code&gt;${variableExpression}&lt;/code&gt;). The expressions in the placeholders and the text between the backticks (&lt;code&gt; &lt;/code&gt;) get passed to a function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Expression placeholder examples:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function authorize(user, action) {
  if (!user.hasPermission(action)) {
    throw new Error(
      `User ${user.name} is not allowed to ${action}.`
    );
  }
}

const person = {
  name: &quot;Sean&quot;
};
const activity = &quot;bake&quot;;

console.log(authorize(person, activity)); 
// &quot;User Sean is not allowed to bake.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Multi-line strings&lt;/h3&gt;
&lt;p&gt;Any newline characters inserted in the source are part of the template literal. Instead of having to use the &lt;code&gt;\n&lt;/code&gt; and &lt;code&gt;+&lt;/code&gt; sign to concatenate two strings together to have a multi-line string, the whole string can be done as one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Original way to create a multi-line string example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&quot;To make a multi-line string this way\n&quot; + 
&quot;I have to concatenate two separate strings with a + sign&quot;);

/* prints: To make a multi-line string this way
I have to concatenate two separate strings with a + sign */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Template literal way to create a multi-line string example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(`With template literal backticks, I can spread strings across
as many lines as I want
with
no
problem.`);

/* prints: With template literal backticks, I can spread strings across
as many lines as I want
with
no
problem. */
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Expression interpolation&lt;/h3&gt;
&lt;p&gt;Embedding expressions (like simple math calculations) into strings used to be quite cumbersome to write out (and interpret) in code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;String concatenation to insert expression values into them:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const c = 10;
const d = 5;

console.log(&apos;It used to be harder to calculate that &apos; + (c + d) 
+ &apos;\n is not the same as &apos; + (2 * c) + &apos; in a string.&apos;);

/* prints: It used to be harder to calculate that 15
is not the same as 20 in a string. */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Template literals make use of syntactic sugar to make substitutions like this much more readable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Expression interpolation inside of string template literals:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const c = 10;
const d = 5;

console.log(`With the syntactic sugar of ES6 template literals, 
doing math in strings like this: ${c + d} 
and that: ${2 * c} is a cinch.`);

/* prints: With the syntactic sugar of ES6 template literals, 
doing math in strings like this: 15
and that: 20 is a cinch. */
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Nesting templates&lt;/h3&gt;
&lt;p&gt;Sometimes nesting a template is the easiest and most readable way to have configurable strings. It’s simple to allow inner backticks within a backticked template by using them inside a placeholder, &lt;code&gt;${ }&lt;/code&gt;, within the template. This could be useful in cases where you’re using a ternary to determine which template literal return.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configuring strings prior to nested templates:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var classes = &apos;header&apos;;

function isDesktopSize(){
  window.innerWidth &amp;gt; 1400 ? true : false;
};

var navbar = {
  isOpen: false
};

classes += (isDesktopSize() ?
   &apos;&apos; : navbar.isOpen ?
     &apos; collapse-navbar&apos; : &apos; expand-navbar&apos;);

console.log(classes);

// prints: header expand-navbar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Nested templates to create configured strings:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function isDesktopSize(){
  window.innerWidth &amp;gt; 1400 ? true : false;
}

var navbar = {
  isOpen: true
};

classes = `header ${ isDesktopSize() ? &apos;&apos; :
 `icon-${navbar.isOpen ? &apos;collapse&apos; : &apos;expand&apos;}` }`;

 console.log(classes);

 // prints: header icon-collapse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nested ternaries (which are used in both configurable string examples) are a generally frowned-upon coding practice, but I used them anyway in the examples to illustrate how the classes variable can be configured so much more cleanly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; in actual coding, it’s suggested to use &lt;code&gt;if / else / if&lt;/code&gt; statements if you find yourself dealing with nested ternaries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Tagged templates&lt;/h3&gt;
&lt;p&gt;More advanced forms of template literals are &lt;strong&gt;tagged templates&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tags allow you to parse template literals with a function. The first argument in a tag function contains an array of string values. The remaining arguments are related to the expressions. In the end, the function can return a manipulated string (or it can return something completely different). The name of the function used for the tag can be whatever you want.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tagged template example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var guy = &apos;Paul&apos;;
var age = 96;

function myTag(strings, personExp, ageExp) {
  var str0 = strings[0]; // &quot;That &quot;
  var str1 = strings[1]; // &quot; is a &quot;

  var ageStr;
  if (ageExp &amp;gt; 99){
    ageStr = &apos;centenarian&apos;;
  } else {
    ageStr = &apos;youngster&apos;;
  }

  // You can even return a string built using a template literal - just to be fancy
  return `${str0}${personExp}${str1}${ageStr}`;
}

var output = myTag`That ${ guy } is a ${ age }`;

console.log(output);
// prints: That Paul is a youngster

var lady = &apos;Elizabeth&apos;;
var age = 107;

var output = myTag`That ${ lady } is a ${ age }`;

console.log(output);
// prints: That Elizabeth is a centenarian
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty neat!&lt;/p&gt;
&lt;h3&gt;Raw strings&lt;/h3&gt;
&lt;p&gt;The special &lt;code&gt;raw&lt;/code&gt; property, available on the first argument of the &lt;code&gt;tag&lt;/code&gt; function below, lets you access raw strings as they were entered, without processing escape sequences (&lt;code&gt;\t&lt;/code&gt;, &lt;code&gt;\v&lt;/code&gt;, &lt;code&gt;\n&lt;/code&gt;, &lt;code&gt;\r&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Raw property on a template literal string example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function tag(strings) {
  console.log(strings.raw[0]);
}

tag`I&apos;d like this line 1 \n to ignore the newline and be in line with 1 
\n even though I should be on line 3 at this point`;

/* prints: I&apos;d like this line 1 \n to ignore the newline and be in line with 1
\n even though I should be on line 3 at this point */

// including the two characters &apos;\&apos; and &apos;n&apos; multiple times
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw&quot;&gt;&lt;code&gt;String.raw()&lt;/code&gt;&lt;/a&gt; method exists to create raw strings just like the default template function and string concatenation would.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Raw property with expression interpolation and string methods example:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var str = String.raw`What&apos;s up \n${4+7}?`;
console.log(str);
// prints: What&apos;s up \n11?

console.log(str.length);
// prints: 15

console.log(str.split(&apos;&apos;).join(&apos;,&apos;));
// prints: W,h,a,t,&apos;,s, ,u,p, ,\,n,1,1,?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m not sure how often you’ll need this in the real world, but it’s nice to know it’s there.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Every year ECMAScript releases new updates to the JavaScript language designed to make developers’ lives easier. At first glance, the syntax can seem quite alien — even to veteran JavaScript developers. However, it’s well worth your time to learn the new tricks — they’ll bring so much power to your development.&lt;/p&gt;
&lt;p&gt;My aim with this blog series is to explain some of my favorite parts of the JavaScript and ES6 syntax being used everywhere now, and show you how to use the newest parts to maximum effect.&lt;/p&gt;
&lt;p&gt;Strings are one of the most basic parts of the JavaScript language, but when ES2015 came around it introduced template literals and these once humble objects got a lot of upgrades. Injecting variables, performing expressions, even making multi-line strings — once complicated code is a breeze thanks to template literals.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll give template literals in their many forms a try — they make strings in JavaScript so much easier to work with.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String&quot;&gt;String&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot;&gt;Template literals&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/paigen11&quot;&gt;All the Gist examples on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Spread &amp; Rest Parameters: JavaScript ES6 Feature Series (Pt 4)</title><link>https://www.paigeniedringhaus.com/blog/spread-rest-parameters-javascript-es6-feature-series-pt-4/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/spread-rest-parameters-javascript-es6-feature-series-pt-4/</guid><description>The syntax so nice ES6 used it twice.</description><pubDate>Sun, 01 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt4-spread-rest/highlighters-hero.webp&quot; alt=&quot;Overhead view of hands holding highlighters over notes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind these posts is simple: there are still plenty of developers for whom, JavaScript doesn’t make a whole ton of sense — what with its asynchronous behavior and being an interpreted language and all.&lt;/p&gt;
&lt;p&gt;Add to that the yearly updates the ECMAScript committee is releasing, and it’s a lot of info to keep abreast of. 🤯 And check out this statistic below from Wikipedia.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As of May 2017 94.5% of 10 million most popular web pages used JavaScript. — &lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript#Use_in_Web_pages&quot;&gt;JavaScript, Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since JS powers so much of the web, I wanted to provide a bunch of articles and examples of ES6+ features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these articles to be short, in-depth explanations about various improvements to the language, that I hope will inspire you to write some really cool stuff using JS. Who knows, you might even learn something new along the way. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For my fourth post, I’ll be discussing rest parameters and the spread syntax: the most concise ways to condense or expand arguments, elements and object values with ease.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;... Rest Parameters&lt;/h2&gt;
&lt;p&gt;Before I dive into rest parameters, I recommend you familiarize yourself with the three main types of functions in use in JavaScript today: function declarations, function expressions and arrow functions. I wrote a blog post about them, for a quick refresher.&lt;/p&gt;
&lt;p&gt;Now that we’re on the same page, let’s get into what exactly rest parameters are.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters&quot;&gt;&lt;strong&gt;Rest parameters&lt;/strong&gt;&lt;/a&gt; are a new syntax that allows us to represent an indefinite number of arguments passed to a function as an array. Make sense? Not quite? 🤔 No problem, code examples usually help me grasp concepts easier too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anatomy of rest parameters in a function declaration&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function f (x, y, ...a) {
  return (x + y) * a.length;
}

console.log(f( 1, 2, “hello”, true, 7)) // prints: 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you’re looking at the example above, everything stays the same as with a normal function declaration &lt;em&gt;except&lt;/em&gt; that the last argument declared, argument &lt;code&gt;a&lt;/code&gt; has a suspicious &lt;code&gt;...&lt;/code&gt; in front of it. This is an example of a rest parameter.&lt;/p&gt;
&lt;p&gt;What this means when the function executes is &quot;take all remaining arguments being passed to this function, shove them all into an array, and do with them whatever the function body dictates in its statement body.&quot;&lt;/p&gt;
&lt;p&gt;Here’s another example, but this time with an arrow function (which easily translates to a function expression in non-ES6 syntax, as well).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rest parameters in an arrow function&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const product = (e, f, ...g) =&amp;gt; {
  return e * f + g.length; 
}

console.log(product(4, 7, 2, 6, 3)); // prints: 31
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now at this point, you may have some questions about exactly how rest parameters can be used (I know I sure did), so let me lay out the rules for you.&lt;/p&gt;
&lt;h3&gt;Rest parameter rules, traits &amp;amp; use cases&lt;/h3&gt;
&lt;h3&gt;Only the last param can have ...&lt;/h3&gt;
&lt;p&gt;No, I didn’t lose my train of thought there, what I’m saying is: only the last parameter defined in a function, can be prefixed with the &lt;code&gt;...&lt;/code&gt;, making it a rest parameter.&lt;/p&gt;
&lt;p&gt;When the last parameter is prefixed with &lt;code&gt;...&lt;/code&gt;, all remaining (user supplied) arguments are placed within a &quot;standard&quot; Javascript array.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output of arguments with a rest parameter&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here’s the kind of output you’ll see when you have a rest parameter as the final argument in a function call. As you can see, the first three arguments passed to &lt;code&gt;myNumberFunction&lt;/code&gt;, the &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, and &lt;code&gt;3&lt;/code&gt; are printed out individually as the first three parameters defined in function: &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;c&lt;/code&gt;. All the remaining numbers passed to the rest parameter &lt;code&gt;d&lt;/code&gt;, however, are printed out as an array &lt;code&gt;[4, 5, 6, 7, 8]&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function myNumberFunction(a, b, c, ...d) {
  console.log(&quot;a&quot;, a);  // a 1
  console.log(&quot;b&quot;, b); // b 2
  console.log(&quot;c&quot;, c); // c 3
  console.log(&quot;...d&quot;, d); //...d [ 4, 5, 6, 7, 8]
}

myNumberFunction(1, 2, 3, 4, 5, 6, 7, 8);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Rest parameters are not just an arguments object&lt;/h3&gt;
&lt;p&gt;There are three main differences to know about between the arguments object and new rest parameters.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rest parameters are only the ones that haven’t been given a separate name (i.e. formally defined in function expression), while the arguments object contains all &lt;code&gt;arguments&lt;/code&gt; passed to the function.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;arguments&lt;/code&gt; object is not a real array, while rest parameters are &lt;code&gt;Array&lt;/code&gt; instances, meaning methods like &lt;code&gt;sort()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;forEach(),&lt;/code&gt; or &lt;code&gt;pop()&lt;/code&gt; can be applied on it directly.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;arguments&lt;/code&gt; object has additional functionality specific to itself (like the &lt;code&gt;callee&lt;/code&gt; property).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rest parameters were originally introduced to reduce the boilerplate code caused by &lt;code&gt;arguments&lt;/code&gt;. Before, it was a major pain to convert &lt;code&gt;arguments&lt;/code&gt; to a &quot;normal array&quot;. Now, they can simply be passed in and then actioned upon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Easy actioning on rest parameter arrays&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function doubleUp(...simpleArgs){
  const arr = simpleArgs;
  const secondArr = arr.map(num =&amp;gt; num * 2);
  return secondArr;
}

console.log(doubleUp(2, 6, 12, 18)); // [ 4, 12, 24, 36 ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Rest parameters can be destructured&lt;/h3&gt;
&lt;p&gt;One of my favorite new things about ES6 is array and object destructuring. I haven’t gone into detail about destructuring yet, but just wait, I will, before this series of articles is finished.&lt;/p&gt;
&lt;p&gt;In a nutshell, destructuring makes it possible to unpack values from arrays, or properties from objects, into distinct variables. If you’re dying to learn more in the meantime, here’s a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;link&lt;/a&gt; to get more familiar with how destructuring works.&lt;/p&gt;
&lt;p&gt;Moving on for the purposes of this post though, here’s rest parameters and destructuring at work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Array destructuring with a rest parameter&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const [captain, coCaptain, ...devs] = [ &quot;Bridget&quot;, &quot;Joe&quot;, &quot;Kyle&quot;, &quot;Drew&quot;, &quot;Patrick&quot;, &quot;Francisco&quot;];
console.log(captain); // &quot;Bridget&quot;
console.log(coCaptain); // &quot;Joe&quot;
console.log(devs); // [&quot;Kyle&quot;, &quot;Drew&quot;, &quot;Patrick&quot;, &quot;Francisco&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above declared array of variables, &lt;code&gt;captain&lt;/code&gt;, &lt;code&gt;coCaptain&lt;/code&gt; and &lt;code&gt;devs&lt;/code&gt;, the rest parameter is applied to &lt;code&gt;devs&lt;/code&gt;, so when the array of names is passed in, &lt;code&gt;&quot;Bridget&quot;&lt;/code&gt; becomes the &lt;code&gt;captain&lt;/code&gt;, &lt;code&gt;&quot;Joe&quot;&lt;/code&gt; is the &lt;code&gt;coCaptain&lt;/code&gt; and the &lt;code&gt;devs&lt;/code&gt; are &lt;code&gt;[&quot;Kyle&quot;, &quot;Drew&quot;, &quot;Patrick&quot;, &quot;Francisco&quot;]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Handy, right? Just imagine the scenarios you’ve encountered where you either needed to pull out individual pieces of an array or keep other pieces together. Trust me, you’ll be so thankful for destructuring and rest params when you do.&lt;/p&gt;
&lt;p&gt;The same type of thing can be done with object destructuring too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object destructuring with a rest parameter&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const {pm1, pm2, ...restOfTeam} = {
  pm1: &quot;Jeremy&quot;,
  pm2: &quot;Tung&quot;,
  developer1: &quot;Casey&quot;,
  developer2: &quot;Mark&quot;,
  ux: &quot;Christina&quot;
};

console.log(pm1); // Jeremy
console.log(pm2); // Tung
console.log(restOfTeam); // { developer1: &quot;Casey&quot;, developer2: &quot;Mark&quot;, ux: &quot;Christina&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example deconstructs &lt;code&gt;pm1&lt;/code&gt; and &lt;code&gt;pm2&lt;/code&gt; from the rest of the team members in the object, and the remaining object properties: &lt;code&gt;developer1&lt;/code&gt;, &lt;code&gt;developer2&lt;/code&gt;, and &lt;code&gt;ux&lt;/code&gt; are grouped together in a new object variable called &lt;code&gt;restOfTeam&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Again, think about using this type of syntax to create new variables, objects, pull object properties apart into individual pieces, etc.&lt;/p&gt;
&lt;p&gt;And those are the main things you need to know about rest parameters. At this point we can move on to the other use of &lt;code&gt;...&lt;/code&gt; in JavaScript, the spread syntax.&lt;/p&gt;
&lt;h2&gt;Spread syntax&lt;/h2&gt;
&lt;p&gt;While it resembles the rest parameter a great deal, the spread syntax has quite different uses.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax&quot;&gt;&lt;strong&gt;spread syntax&lt;/strong&gt;&lt;/a&gt; allows an iterable such as an array or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.&lt;/p&gt;
&lt;p&gt;Uh... What now?&lt;/p&gt;
&lt;p&gt;Ok, that definition sounds technical, I know, believe me. But here’s what it means in practice:&lt;/p&gt;
&lt;p&gt;If you’ve got a string, an array or an object, and you want to use all the values, you can spread all of them into function calls, new arrays, or new objects, with a very concise syntax.&lt;/p&gt;
&lt;h3&gt;The spread syntax at work in functions, arrays, strings, and objects&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// For function calls:
function multiply(x, y, z) {
  return x * y * z;
}

const args = [1, 2, 3];

console.log(multiply(...args)); // 6

// For array literals or strings:
const iterableObj = [ {protein: &quot;steak&quot;}, {carb: &quot;potato&quot;}, &quot;milkshake&quot;];
const randomList = [...iterableObj, &quot;4&quot;, &quot;five&quot;, 6];
console.log(randomList); // [ { protein: &quot;steak&quot; }, { carb: &quot;potato&quot; }, &quot;milkshake&quot;, &quot;4&quot;, &quot;five&quot;, 6 ]
const str = &quot;foo&quot;
const chars = [ ...str ] 
console.log(chars); // [ &quot;f&quot;, &quot;o&quot;, &quot;o&quot; ]

// For object literals (new in ECMAScript 2018):
const powerTool = { skuNumber: &quot;996655&quot;, skuDescription: &quot;Drill Bit&quot; };
let secondPowerTool = { ...powerTool, toolDepartment: 25, toolClass: 7 };
console.log(secondPowerTool); // { skuNumber: &quot;996655&quot;, skuDescription: &quot;Drill Bit&quot;, toolDepartment: 25, toolClass: 7 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The different examples above show what happens when you spread various items.&lt;/p&gt;
&lt;p&gt;For the first example, the &lt;code&gt;multiply()&lt;/code&gt; function, I spread my args array into the function call, which simply takes the three values from the array (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, and &lt;code&gt;3&lt;/code&gt;) and puts them in the places of the function’s accepted parameters &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;z&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the case of the second and third examples, spreading arrays and strings, the original list, &lt;code&gt;iterableObj&lt;/code&gt;, and the original string, &lt;code&gt;&quot;foo&quot;&lt;/code&gt;, are both spread into new variables, &lt;code&gt;randomList&lt;/code&gt; and &lt;code&gt;chars&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;All the values in &lt;code&gt;iterableObj&lt;/code&gt; are added to the new &lt;code&gt;randomList&lt;/code&gt; array along with the new values assigned specifically to &lt;code&gt;randomList&lt;/code&gt;. And the original string of &lt;code&gt;&quot;foo&quot;&lt;/code&gt; is spread apart, character by character, into the new chars array.&lt;/p&gt;
&lt;p&gt;The final example, only possible since the release of ECMAScript 2018, is of spreading the object &lt;code&gt;powerTool&lt;/code&gt;&apos;s properties into a new object called &lt;code&gt;secondPowerTool&lt;/code&gt;, and adding two new properties to that object as well: &lt;code&gt;toolDepartment&lt;/code&gt; and &lt;code&gt;toolClass&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Spread syntax rules, traits &amp;amp; use cases&lt;/h3&gt;
&lt;p&gt;Just like the rest parameter, the spread syntax is syntactic sugar that replaces complex methods and boilerplate code-filled ways of doing things that should be relatively easy.&lt;/p&gt;
&lt;p&gt;That being said, there are things that you need to be aware of regarding spread.&lt;/p&gt;
&lt;h3&gt;Spread Replaces Apply in Function Calls&lt;/h3&gt;
&lt;p&gt;Up to now, it’s been common to use &lt;code&gt;Function.prototype.apply()&lt;/code&gt; in cases where you want to use the elements of an array as arguments to a function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Using apply() to assign array elements in a function call&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With spread, the syntax is much cleaner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spreading a list of array elements into a function call&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And something else that’s cool: any argument in the argument list can use spread syntax and it can be used multiple times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple spreads in a single function call&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Spread syntax can be used with the new keyword&lt;/h3&gt;
&lt;p&gt;Unlike when calling a constructor with &lt;code&gt;new&lt;/code&gt;, where it&apos;s not possible to directly use an array and &lt;code&gt;apply&lt;/code&gt;, with spread, an array can be easily used with &lt;code&gt;new&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spread syntax with the new constructor&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var dateFields = [1989, 3, 13];
var d = new Date(...dateFields);
console.log(d); // 13 Apr 1989
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Spread in array literals&lt;/h3&gt;
&lt;p&gt;Spread makes array manipulation so much easier, and methods like &lt;code&gt;push()&lt;/code&gt;, &lt;code&gt;concat()&lt;/code&gt;, and &lt;code&gt;splice()&lt;/code&gt; a lot less necessary. Let’s go over what it can help you do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Creating new array literals is a snap&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a new array using an existing array as one part of it requires no additional array methods like it would have in the past.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spreading one array into another new array&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const fruits = [&quot;watermelon&quot;, &quot;peaches&quot;];
const fruitBasket = [&quot;apples&quot;, &quot;grapes&quot;, ...fruits, &quot;bananas&quot;, &quot;kiwis&quot;, &quot;mango&quot;];
console.log(fruitBasket); // [ &quot;apples&quot;, &quot;grapes&quot;, &quot;watermelon&quot;, &quot;peaches&quot;, &quot;bananas&quot;, &quot;kiwis&quot;, &quot;mango&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How easy is that to add the &lt;code&gt;fruits&lt;/code&gt; array to &lt;code&gt;fruitsBasket&lt;/code&gt;? Super easy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Copying arrays is a breeze too&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With spread, copying the values of one array into another array is a piece of cake. Then you can continue to modify the newly copied array without affecting the original array (which lends itself well to the style of immutable, functional programming so popular today with frameworks like React and state management tools like Redux).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const arr1 = [1, 2, 3];

const arr2 = [...arr1];

console.log(arr2); // [1, 2, 3]

arr2.push(4);

console.log(arr1); // [1, 2, 3]

console.log(arr2); // [1, 2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before I pushed &lt;code&gt;4&lt;/code&gt; onto &lt;code&gt;arr2&lt;/code&gt;, when the values were printed out, they were exactly the same as &lt;code&gt;arr1&lt;/code&gt;. And once again, even after &lt;code&gt;4&lt;/code&gt; is added to &lt;code&gt;arr2&lt;/code&gt;, &lt;code&gt;arr1&lt;/code&gt; remains unaltered.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Spread syntax only effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays, for that using a function like lodash’s &lt;a href=&quot;https://lodash.com/docs/4.17.15#cloneDeep&quot;&gt;_.cloneDeep()&lt;/a&gt; is recommended.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Concatenating arrays has never been easier&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Array.prototype.concat()&lt;/code&gt; was the go-to when concatenating an array onto the end of an existing array. Without spread syntax this is done as:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;.concat() Arrays Together&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const germanCars = [ &quot;BMW&quot;, &quot;Audi&quot;, &quot;Mercedes&quot; ];
const japaneseCars = [ &quot;Honda&quot;, &quot;Toyota&quot;, &quot;Datsun&quot; ];

const concatCarMakers = germanCars.concat(japaneseCars);

console.log(concatCarMakers); // [ &quot;BMW&quot;, &quot;Audi&quot;, &quot;Mercedes&quot;, &quot;Honda&quot;, &quot;Toyota&quot;, &quot;Datsun&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With spread syntax this becomes:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spreading arrays together&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const germanCars = [ &quot;BMW&quot;, &quot;Audi&quot;, &quot;Mercedes&quot; ];
const japaneseCars = [ &quot;Honda&quot;, &quot;Toyota&quot;, &quot;Datsun&quot; ];

const carMakers = [...germanCars, ...japaneseCars];

console.log(carMakers); // [ &quot;BMW&quot;, &quot;Audi&quot;, &quot;Mercedes&quot;, &quot;Honda&quot;, &quot;Toyota&quot;, &quot;Datsun&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spread syntax can also take the place of &lt;code&gt;unshift()&lt;/code&gt; and make adding new elements to the front of an array much simpler than it used to be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spread elements into the beginning of an array&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let numbers = [ 6, 5, 4 ];
const moreNumbers = [ 1, 2, 3 ];

numbers = [...moreNumbers, ...numbers];

console.log(numbers); // [ 1, 2, 3, 6, 5, 4 ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Spread in object literals&lt;/h3&gt;
&lt;p&gt;As of ECMAScript 2018, spread properties came to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer&quot;&gt;object literals&lt;/a&gt;. This lets an object copy its own enumerable properties from a provided object onto a new object.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shallow cloning and merging objects is simple&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While &lt;code&gt;Object.assign()&lt;/code&gt; made shallow-cloning and merging objects together possible, using the spread syntax is even more concise.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// duplicate object properties
const markerSet = { copicMarkers: [&quot;green&quot;, &quot;blue&quot;, &quot;red&quot;]};
const duplicateMarkerSet = {...markerSet};

console.log(duplicateMarkerSet); // { copicMarkers: [ &quot;green&quot;, &quot;blue&quot;, &quot;red&quot; ] }

// merge two objects into a new one
const markerSet2 = { copicSketchMarkers: [&quot;pink&quot;, &quot;yellow&quot;, &quot;orange&quot;]};
const giantMarkerSet = { ...markerSet, ...markerSet2 };

console.log(giantMarkerSet); // { copicMarkers: [ &quot;green&quot;, &quot;blue&quot;, &quot;red&quot; ], copicSketchMarkers: [ &quot;pink&quot;, &quot;yellow&quot;, &quot;orange&quot; ] }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s also worth noting that &lt;code&gt;Object.assign()&lt;/code&gt; triggers &lt;code&gt;setters&lt;/code&gt;, which binds an object property to a function to be called when there is an attempt to set that property, whereas the spread syntax does not.&lt;/p&gt;
&lt;h3&gt;Spread (aside from object properties) is only for iterables&lt;/h3&gt;
&lt;p&gt;The spread syntax (other than in the case of spread properties) can be applied only to iterable objects: Arrays, Maps, Sets, Strings and the like.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// spreading in an object to an array does NOT work
const obj = { key1: &quot;value1&quot;};
let array = [...obj];

console.log(array); // []

// spreading an array of objects into another array does work
const objInArray = [ { key2: &quot;value2&quot;}];
array = [...objInArray];

console.log(array); // [ { key2: &quot;value2&quot; } ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s about the long and short of the spread syntax details that you need to know to use it effectively.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;At first glance, some of the newest JS syntax can seem totally foreign — even to people who’ve been writing JavaScript code for years. And while yes, it is different, it’s also incredibly powerful and makes doing our jobs so much easier than they were even just a few years ago.&lt;/p&gt;
&lt;p&gt;My aim with this blog series is to explain some of the JavaScript and ES6 syntax you use everyday, and show you how to fully harness the newest parts of the JavaScript language to full effect.&lt;/p&gt;
&lt;p&gt;Rest syntax looks exactly like spread syntax (&lt;code&gt;...&lt;/code&gt;) but is used for destructuring arrays and objects. In a way, rest syntax is the opposite of spread syntax: spread &lt;em&gt;expands&lt;/em&gt; an array into its elements, while rest collects multiple elements and &lt;em&gt;condenses&lt;/em&gt; them into a single element. It’s so useful in so many common programming situations, as I’m sure you can already imagine.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll start seeing the possibilities of using rest parameters and the spread syntax in your code in the future — they make a myriad of things a cinch. Please share this with your friends if you found it helpful!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters&quot;&gt;Rest Parameters&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax&quot;&gt;Spread Syntax&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript#Use_in_Web_pages&quot;&gt;JavaScript&lt;/a&gt;, Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;Destructuring&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Default Function Parameter Values: JavaScript ES6 Feature Series (Pt 3)</title><link>https://www.paigeniedringhaus.com/blog/default-function-parameter-values-javascript-es6-feature-series-pt-3/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/default-function-parameter-values-javascript-es6-feature-series-pt-3/</guid><description>Less parameter undefined checks make developers&apos; lives easier</description><pubDate>Fri, 23 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt3-func-params/books-hero.webp&quot; alt=&quot;Never ending shelves of books&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind these posts is simple: there are still plenty of developers for whom JavaScript makes no sense — or at the very least, is bewildering at times.&lt;/p&gt;
&lt;p&gt;Since JS does power so much of the web, I wanted to provide a slew of articles about JavaScript ES6 features that I use regularly, for other developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these articles to be short, in-depth explanations about various improvements to the language, that I hope will inspire you to write some really cool stuff using JS. Who knows, you might even learn something new along the way. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For my third post, I wanted to talk about default function parameter values: the things that will save us all from tons of undefined checks in our code.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Traditional function parameters&lt;/h2&gt;
&lt;p&gt;As one of my &lt;a href=&quot;./arrow-functions-java-script-es-6-feature-series-pt-2&quot;&gt;previous posts&lt;/a&gt; detailed, functions are one of the fundamental building blocks of JavaScript. One of the things functions allow us to do is define a set of statements that performs a task or calculates a value the same way, every time, AND supply a list of parameters that can be passed in to be operated on.&lt;/p&gt;
&lt;p&gt;Regardless of what values are passed in as parameters, the function will attempt to run the same tasks &lt;em&gt;every time&lt;/em&gt; it is called.&lt;/p&gt;
&lt;h3&gt;Anatomy of a function declaration and parameters&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function simpleAdd(a, b){
  return a + b;
}

simpleAdd(2, 3); 
// prints: 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re looking at the function declaration above, here’s what composes it. &lt;code&gt;simpleAdd&lt;/code&gt; is the name of the function, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are the two parameters the function takes in, and the body of the function &lt;code&gt;return a + b;&lt;/code&gt; is the statement.&lt;/p&gt;
&lt;p&gt;Ok, so that’s simple, straightforward and makes perfect sense, right? Right. But what happens if a traditional function declaration isn’t passed the correct amount of parameters?&lt;/p&gt;
&lt;p&gt;An overabundance of parameters is OK, the JavaScript engine just knows to ignore additional arguments that it doesn’t use in the function, but not supplying enough parameters is a different problem entirely... Check out what happens there.&lt;/p&gt;
&lt;h3&gt;Function declaration with too many &amp;amp; too few parameters&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function add(a, b){
  return a + b;
}

console.log(add(1, 2, 3, 4)); 
// prints: 3

console.log(add(1)); 
// prints: NaN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uh-oh, the lack of a &lt;code&gt;b&lt;/code&gt; parameter didn’t turn out so well for the &lt;code&gt;add(1)&lt;/code&gt; function. &lt;code&gt;NaN&lt;/code&gt; (&quot;not a number&quot;) is something a developer never wants to see when attempting to do math with JavaScript.&lt;/p&gt;
&lt;p&gt;Why did this happen? Because traditionally, function parameters default to &lt;code&gt;undefined&lt;/code&gt; when the function is declared, and it waits for &lt;code&gt;arguments&lt;/code&gt; to be passed in when the function is called in the code. So, how do we avoid dreaded things like &lt;code&gt;NaN&lt;/code&gt;? Up until ES6, we had to do things like &lt;code&gt;undefined&lt;/code&gt; checks everywhere in functions.&lt;/p&gt;
&lt;h3&gt;Checking a function for undefined parameters&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function addImproved(a, b) {
  if(a === undefined){
    a = 3;
  }
  if(b === undefined){
    b = 7;
  }
  return a + b;
}

console.log(addImproved(6,9)); 
// prints: 15 

console.log(addImproved()); 
// prints: 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above &lt;code&gt;addImproved()&lt;/code&gt;, in order to avoid &lt;code&gt;undefined&lt;/code&gt; parameter errors, we have to physically check each parameter as it’s passed in and make sure that it is not undefined before finally letting the function get to its main goal: adding the two numbers together.&lt;/p&gt;
&lt;p&gt;What a pain — imagine having to write this same type of logic over and over again for hundreds of functions throughout a large code base. 😩 No thanks, there’s got to be a better way...&lt;/p&gt;
&lt;h2&gt;Default function parameters&lt;/h2&gt;
&lt;p&gt;Enter the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters&quot;&gt;default function parameters&lt;/a&gt;; they allow named parameters in a function to be initialized with default values if no value or &lt;code&gt;undefined&lt;/code&gt; is passed in.&lt;/p&gt;
&lt;p&gt;As I briefly explained above, up until now, in JavaScript, function parameters automatically default to &lt;code&gt;undefined&lt;/code&gt;; which meant we had to test parameter values in a function body, check for potentially undefined parameters and assign values if they were undefined.&lt;/p&gt;
&lt;p&gt;Here’s an example of two ways to set values if they aren’t assigned. The first is a simple &lt;code&gt;if / else&lt;/code&gt; statement, the second is a ternary statement checking if the parameter’s &lt;code&gt;type&lt;/code&gt; is undefined or not, and setting the value if need be.&lt;/p&gt;
&lt;h3&gt;Two traditional ways of preventing undefined parameters&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function oldSum (x, y, z) {
  if (y === undefined) {
    y = 7;
  }
  z = (typeof z !== &quot;undefined&quot;) ? z : 42;
  return `oldSum(${x}) === ${x + y + z}`;
};

console.log(oldSum(1));  
// prints: oldSum(1) === 50

console.log(oldSum(2, 5, 8)); 
// prints: oldSum(2) === 15

console.log(oldSum()); 
// prints: oldSum(undefined) === NaN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Seems like a lot of extra code just to prevent errors before the function even runs. With default parameters in ES2015, checks in the function body are no longer necessary.&lt;/p&gt;
&lt;h3&gt;ES6 ways to prevent undefined errors with default parameters&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function newSum (x, y = 7, z = 42) {
  return `newSum(${x}) === ${x + y + z}`;
};

console.log(newSum(1)); 
// prints: newSum(1) === 50

console.log(newSum(3, 6, 9)); 
// prints: newSum(3) === 18

console.log(newSum(16, undefined)); 
// prints: newSum(16) === 65
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much nicer! Right where the parameters are named, they are also given default values in case not enough arguments are supplied. It’s so much cleaner and easier to read this way, and removes the boilerplate of undefined checks.&lt;/p&gt;
&lt;p&gt;I should also mention, the same rules that apply to default parameters in function declarations, work in arrow functions, as well. Check this out.&lt;/p&gt;
&lt;h3&gt;ES6 default parameters in arrow functions&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const thisWayWorksToo = (x = 7, y = 8) =&amp;gt; {
  return x + y;
}

console.log(thisWayWorksToo(3, 4)); 
// prints: 7

console.log(thisWayWorksToo()); 
// prints: 15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These types of examples are far and away the most common use cases for default parameters, however, there’s more to know about them, if you’re curious. 🤔&lt;/p&gt;
&lt;h2&gt;Gotchas and other use cases for default parameters&lt;/h2&gt;
&lt;p&gt;Default params have some other interesting functionalities it will be helpful to know — they also have some really handy use cases. Let’s go over them so you don’t get tripped up, or when you do, you can more quickly debug the source of the problem.&lt;/p&gt;
&lt;h3&gt;Passing undefined vs other falsy values&lt;/h3&gt;
&lt;p&gt;One thing that could trip you up: passing other falsy values like &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;&apos;’&lt;/code&gt; to a function with default parameters will &lt;em&gt;not&lt;/em&gt; result in the default value being substituted instead.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function luckyNumber(num = 11) { 
  console.log(typeof num);
};

luckyNumber(); 
// prints: &apos;number&apos; (num is set to 11)

luckyNumber(undefined); 
// prints: &apos;number&apos; (num is set to 11 too)

// test with other falsy values:
luckyNumber(&apos;&apos;); 
// prints: &apos;string&apos; (num is set to &apos;&apos;)

luckyNumber(null); 
// prints: &apos;object&apos; (num is set to null)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see above when &lt;code&gt;luckyNumber()&lt;/code&gt; is called with no value or a value of &lt;code&gt;undefined&lt;/code&gt; it falls back to its default param of 11. When it’s called, however, with an empty string or a &lt;code&gt;null&lt;/code&gt; value, it takes that value instead.&lt;/p&gt;
&lt;h3&gt;Evaluation at call time&lt;/h3&gt;
&lt;p&gt;The second thing to know is: default values are evaluated at call time, so a &lt;em&gt;new object&lt;/em&gt; is created each time the function is called — not, contrary to what you might think, adding to an already existing object or array.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function append(value, array = []) {
  array.push(value);
  return array;
}

console.log(append(1)); 
// prints: [1]

console.log(append(2)); 
// prints: [2], not [1, 2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each time the &lt;code&gt;append()&lt;/code&gt; function runs, it creates a brand new array with the value supplied as its contents. The first time the function is called and executed it runs, makes an array and is done, and its execution context is destroyed once it’s done running.&lt;/p&gt;
&lt;p&gt;What this means is that the function is now completely done with (and unaware of) the original array it created. Which is why, when &lt;code&gt;append()&lt;/code&gt; is invoked a second time, with a second value, it creates a second, entirely new array, instead of adding to the first one it created.&lt;/p&gt;
&lt;h3&gt;Earlier params are available to later default params&lt;/h3&gt;
&lt;p&gt;Ok, here’s a cool trick: parameters declared earlier (to the left) in a parameter string are then available to be used by later default parameters.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function welcome(name, greeting, message = greeting + &apos; &apos; + name) {
  return [name, greeting, message];
}

console.log(welcome(&apos;Sean&apos;, &apos;Hi&apos;));  
// [&quot;Sean&quot;, &quot;Hi&quot;, &quot;Hi Sean&quot;]

console.log(welcome(&apos;Sean&apos;, &apos;Hi&apos;, &apos;Happy Birthday!&apos;)); 
// [&quot;Sean&quot;, &quot;Hi&quot;, &quot;Happy Birthday!&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By passing in values for the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;greeting&lt;/code&gt; parameters, the third param of &lt;code&gt;message&lt;/code&gt; is able to take those two to make another string value. Pretty sweet.&lt;/p&gt;
&lt;p&gt;Imagine how much more cleanly you could handle functions with lots of potential variables. This example, which I borrowed from the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters#Default_parameters_are_available_to_later_default_parameters&quot;&gt;MDN docs&lt;/a&gt; on default parameters really drives the point home.&lt;/p&gt;
&lt;h3&gt;Cleaner edge case handling with and without default parameters&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function go() {
  return &quot;:P&quot;;
}

function withDefaults(a, b = 5, c = b, d = go(), e = this, f = arguments, g = this.value) {
  return [a, b, c, d, e, f, g];
}

function withoutDefaults(a, b, c, d, e, f, g) {
  switch (arguments.length) {
    case 0:
      a;
    case 1:
      b = 5;
    case 2:
      c = b;
    case 3:
      d = go();
    case 4:
      e = this;
    case 5:
      f = arguments;
    case 6:
      g = this.value;
    default:
  }
  return [a, b, c, d, e, f, g];
}

withDefaults.call({value: &quot;=^_^=&quot;});
// [undefined, 5, 5, &quot;:P&quot;, {value:&quot;=^_^=&quot;}, arguments, &quot;=^_^=&quot;]

withoutDefaults.call({value: &quot;=^_^=&quot;});
// [undefined, 5, 5, &quot;:P&quot;, {value:&quot;=^_^=&quot;}, arguments, &quot;=^_^=&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yeah, is there anyone who would choose to write out the &lt;code&gt;withoutDefaults()&lt;/code&gt; function instead of the &lt;code&gt;withDefaults()&lt;/code&gt; function? I think not.&lt;/p&gt;
&lt;h3&gt;Parameters without defaults after default parameters&lt;/h3&gt;
&lt;p&gt;While earlier params are available to later default params, you cannot, pass in defined parameters to fill the place of later undefined parameters in a function. Makes perfect sense, right? 😉 To put it another way: parameters are always set left-to-right, and they overwrite default parameters even if there are later parameters without defaults. This example below probably illustrates it better.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function f(x = 1, y) {
  return [x, y];
}

console.log(f()); 
// prints: [1, undefined]

console.log(f(4)); 
// prints: [4, undefined]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And those are some of the main things to know when it comes to default parameters in functions.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Even though JS has been around for more than 20 years and ES6 has been out since 2015, there’s still plenty of misinformation and knowledge gaps surrounding it.&lt;/p&gt;
&lt;p&gt;I’m trying to demystify it and give you a better understanding of JavaScript, ES6 — things you may use everyday but not fully grasp the nuances of.&lt;/p&gt;
&lt;p&gt;Functions are one of the key building blocks of JavaScript, and before now, checking for undefined parameters was just a fact of life. With the introduction of default parameters, though, at least some of the boilerplate can be peeled away, making functions easier to write, read and maintain, and I, for one, am incredibly grateful, and excited for future improvements as well.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about more JavaScript and ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll have a chance to take advantage of default parameters in the functions you write going forward, be they declarations, expressions or arrow functions. Please share this with your friends if you found it helpful!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions&quot;&gt;Functions, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters&quot;&gt;Default Function Parameters, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Arrow Functions: JavaScript ES6 Feature Series (Pt 2)</title><link>https://www.paigeniedringhaus.com/blog/arrow-functions-javascript-es6-feature-series-pt-2/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/arrow-functions-javascript-es6-feature-series-pt-2/</guid><description>When is a function not a function? When it&apos;s an arrow.</description><pubDate>Tue, 06 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt2-arrow-funcs/chalkboard-hero.webp&quot; alt=&quot;Old, beat up chalkboard with scribbled math on it&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind this series of posts is simple: there are still plenty of developers for whom JavaScript makes no sense sometimes — or at the very least, has seemingly odd behavior compared to other programming languages.&lt;/p&gt;
&lt;p&gt;Since it is such a popular and widely used language though, I wanted to provide a bunch of posts about JavaScript ES6 features that I use regularly, for developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these articles to be short but still in-depth explanations about various improvements to the language, that I hope will inspire you to write some really cool stuff using JS. Who knows, you might even learn something new along the way. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For the second post in this series, I wanted to dive into arrow functions, and how they differ from traditional function declarations and function expressions.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Function declarations&lt;/h2&gt;
&lt;p&gt;You may have heard this before, but it bears repeating: &lt;strong&gt;in JavaScript, functions are first-class objects&lt;/strong&gt;, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function&quot;&gt;&lt;strong&gt;&lt;code&gt;Function&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; objects.&lt;/p&gt;
&lt;p&gt;From here on, I will assume you’re familiar with the general idea of functions in JavaScript, But before I talk about arrow functions, it’s worth talking a little about both function declarations (also known as function statements) and function expressions.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function&quot;&gt;&lt;strong&gt;Function declarations&lt;/strong&gt;&lt;/a&gt; are the most basic function statement we see all the time in JavaScript. It defines a function along with the specified parameters it needs to run.&lt;/p&gt;
&lt;p&gt;Here’s an example:&lt;/p&gt;
&lt;h3&gt;Anatomy of a function declaration&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function multiply(number1, number2){
  return number1 * number2;
}

console.log(multiply(4, 9));  
// prints 36 to the console
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re looking at the function declaration example above, here’s what composes the function. &lt;code&gt;multiply&lt;/code&gt; is the &lt;strong&gt;name&lt;/strong&gt; of the function, &lt;code&gt;number1&lt;/code&gt; and &lt;code&gt;number2&lt;/code&gt; are the two &lt;strong&gt;parameters&lt;/strong&gt; the function takes in, and the body of the function: &lt;code&gt;return number1 * number2;&lt;/code&gt; is the &lt;strong&gt;statement&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Function declaration traits&lt;/h3&gt;
&lt;p&gt;Function declarations have certain traits which developers need to keep in mind as they write code, because they will trip you up at one time or another — they manage to trip us all up (myself included). 🙋&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Functions return undefined, unless otherwise specified&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By default functions return &lt;code&gt;undefined&lt;/code&gt;. By including the &lt;code&gt;return&lt;/code&gt; keyword in the body, you can specify the value it returns instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function declarations undefined vs. returned values&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function returnsNothing(item1, item2) {
  item1 + item2;
}

console.log(returnsNothing(1, 9)); 
// prints: undefined

function returnsSomething(item1, item2) {
  return item1 + item2;
}

console.log(returnsSomething(1, 9)); 
// prints: 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For my example above, the sum of &lt;code&gt;item1&lt;/code&gt; and &lt;code&gt;item2&lt;/code&gt; is what is returned from the &lt;code&gt;returnsSomething()&lt;/code&gt; function, while the &lt;code&gt;returnsNothing()&lt;/code&gt; function, although it does exactly the same addition, merely returns &lt;code&gt;undefined&lt;/code&gt; when the value is called with &lt;code&gt;console.log()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Function declarations are hoisted&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Similar to variable hoisting, which I discussed in my &lt;a href=&quot;./var-let-const-java-script-es-6-feature-series-pt-1&quot;&gt;previous blog post&lt;/a&gt;, function declarations in JavaScript are &lt;strong&gt;hoisted&lt;/strong&gt; to the top of the enclosing function or global scope. This means, you can use a function before it’s actually been declared in the code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function declaration hoisting vs. function expression not hoisting&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(hoistedFunction()); 
// prints: &quot;Hello, I work even though I am called before being declared&quot;

function hoistedFunction() {
  return &quot;Hello, I work even though I am called before being declared&quot;;
}

console.log(notHoisted());
 // prints: TypeError: notHoisted is not a function

var notHoisted = function() {
  return &quot;I am not hoisted, so I will not be found if called before my declaration&quot;;
}

console.log(notHoisted()); 
// prints: &quot;I am not hoisted, so I will not be found if called before my declaration&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, the function &lt;code&gt;hoistedFunction()&lt;/code&gt; returns its value, regardless of when it’s called in the code, because it’s a function declaration.&lt;/p&gt;
&lt;p&gt;On the other hand, the second function assigned to the variable &lt;code&gt;notHoisted()&lt;/code&gt;, which is a function expression, is not hoisted to the top of the scope so if it is invoked before the function is parsed, it throws a &lt;code&gt;TypeError&lt;/code&gt; in the code that it is not a function (mainly because the compiler’s not aware of it yet).&lt;/p&gt;
&lt;p&gt;Those are main things you need to be aware of when thinking about function declarations.&lt;/p&gt;
&lt;p&gt;Let’s move on to function expressions.&lt;/p&gt;
&lt;h2&gt;Function expressions&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/web/JavaScript/Reference/Operators/function&quot;&gt;&lt;strong&gt;Function expressions&lt;/strong&gt;&lt;/a&gt; are similar to function declarations. They still have names (which are optional this time), parameters, and body-based statements.&lt;/p&gt;
&lt;h3&gt;Anatomy of a function expression&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const divide = function(number1, number2){
  return number1 / number2;
}

console.log(divide(15, 5)); 
// prints: 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this example, the variable &lt;code&gt;divide()&lt;/code&gt; is assigned to the anonymous function which takes the parameters &lt;code&gt;number1&lt;/code&gt; and &lt;code&gt;number2&lt;/code&gt;, and returns the quotient as per the body’s statement &lt;code&gt;return number1 / number2;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Function expression traits&lt;/h3&gt;
&lt;p&gt;Just like function declarations, function expressions have some defining quirks of their own. Here’s what you need to know about them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Function expressions can be anonymous (or not)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As I mentioned briefly above, function expressions, since they’re assigned to variables, can omit a name, and be what’s known as an &quot;anonymous function&quot;. This is possible because the variable name will be &lt;em&gt;implicitly&lt;/em&gt; assigned to the function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anonymous function expression (implicit naming at work)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const anonymous = function() {
  return &quot;I do not need my own name, as I am assigned to the variable anonymous&quot;;
}

console.log(anonymous()); 
// prints: &quot;I do not need my own name, as I am assigned to the variable anonymous&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the variable name implies, since the function it’s referencing has no name, it implicitly assigns &lt;code&gt;anonymous()&lt;/code&gt; to the function.&lt;/p&gt;
&lt;p&gt;If, however, you want to refer to the current function inside the function body, you need to create an &lt;em&gt;explicitly&lt;/em&gt; named function (whose name is local only to the function body).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Named function expression (explicit naming at work)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var math = {
  &quot;factit&quot;: function factorial(n) {
    console.log(n)
    if (n &amp;lt;= 1) {
      return 1;
    }
    return n * factorial(n - 1);
  }
};

console.log(math.factit(3)); 
//prints: 3; 2; 1;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this variable &lt;code&gt;math&lt;/code&gt;, you can call the &lt;code&gt;factorial()&lt;/code&gt; function by invoking &lt;code&gt;math.factit();&lt;/code&gt; outside of the object, and passing the required parameter in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t find as much need for this type of named function expression in my day to day development, but it’s nice to know it’s available if the need arises.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; If the function expression’s name is omitted, it will be given the variable name (implicit name). If the function expression’s name is present, it will be the assigned function name (explicit name).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Function expressions can be IIFEs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A function expression can be used as an IIFE: an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IIFE&quot;&gt;Immediately Invoked Functional Expression&lt;/a&gt;, which runs as soon as it’s defined.&lt;/p&gt;
&lt;p&gt;This immediate execution by the JavaScript engine is triggered by the parentheses &lt;code&gt;()&lt;/code&gt; at the end of the anonymous function.&lt;/p&gt;
&lt;p&gt;I won’t go into too much detail here, but for any variables created within the IIFE to be accessible to the outside or global scope, the anonymous function must be assigned a variable a la a function expression.&lt;/p&gt;
&lt;p&gt;If it’s not and the anonymous function’s just invoked at run time, any variables created inside the function’s scope will be invisible to the outside world.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IIFE variables that are accessible vs. IIFEs that are not&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const cogitoErgoSum = (function () {
  const quote = &quot;I think therefore I am&quot;;
  return quote;
})();

// immediately creates the output
cogitoErgoSum; 
// prints: &quot;I think therefore I am&quot;

(function (){
  const quote2 = &quot;I am not outside this IIFE&quot;;
})();

quote2; 
// prints: ReferenceError: quote2 is not defined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. Function expressions don&apos;t hoist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Function expressions (and arrow functions) take after the new &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; variable keywords, in that they don’t get hoisted at run time.&lt;/p&gt;
&lt;p&gt;As I demonstrated above in the function declaration section around hoisting, function expressions &lt;strong&gt;do not hoist&lt;/strong&gt;, a function expression is created when the execution reaches it and it is usable from then on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function declaration hoisting vs. function expression not hoisting&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(hoistedFunction()); 
// prints: &quot;I am a function declaration so I am hoisted to the top of the scope at run time&quot;

function hoistedFunction() {
  return &quot;I am a function declaration so I am hoisted to the top of the scope at run time&quot;;
}

console.log(stillNotHoisted()); 
// prints: TypeError: stillNotHoisted is not a function

const stillNotHoisted = function() {
  return &quot;I am a function expression and therefore, hoisting does not apply to me&quot;;
}

console.log(stillNotHoisted());
 // prints: &quot;I am a function expression and therefore, hoisting does not apply to me&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The outcome is the same as when I described it in function declarations, function expressions throw &lt;code&gt;TypeErrors&lt;/code&gt; if invoked before they are parsed at run time. Just don’t do it.&lt;/p&gt;
&lt;p&gt;Ok, now time to move on to arrow functions: the latest and greatest function improvements courtesy of ES6.&lt;/p&gt;
&lt;h2&gt;Arrow function expressions ➡️&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt2-arrow-funcs/arrow-func.webp&quot; alt=&quot;Arrow function syntax&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The most basic arrow function syntax.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;&lt;strong&gt;Arrow function expressions&lt;/strong&gt;&lt;/a&gt; are syntactically compact alternatives to regular function expressions.&lt;/p&gt;
&lt;h3&gt;Anatomy of two basic arrow function expressions&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const basicArrow = () =&amp;gt; {
  return &quot;The most basic of basic arrow functions&quot;;
}

basicArrow(); 
// prints: &quot;The most basic of basic arrow functions&quot;

const basicArrow2 = oneParam =&amp;gt; `Single line with ${oneParam} is also valid`;

basicArrow2(&quot;only one param&quot;); 
// prints: &quot;Single line with only on param is also valid&quot; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both of the examples above &lt;code&gt;basicArrow()&lt;/code&gt; and &lt;code&gt;basicArrow2()&lt;/code&gt; are valid examples of an arrow function. As with all function expressions, both anonymous functions are implicitly named by the variables assigned to them.&lt;/p&gt;
&lt;p&gt;What’s different though is that the &lt;code&gt;function&lt;/code&gt; keyword is unnecessary. Instead it’s replaced by a set of parentheses &lt;code&gt;()&lt;/code&gt; if there are no required parameters, the name of the single parameter required by &lt;code&gt;basicArrow2()&lt;/code&gt;, which is &lt;code&gt;oneParam&lt;/code&gt; (no parentheses necessary in this case), or, for any other number of parameters, you could do &lt;code&gt;(paramOne, paramTwo, paramThree, ...)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, the first function has a normal &lt;code&gt;return&lt;/code&gt; statement inside the body of the function surrounded by curly braces &lt;code&gt;{}&lt;/code&gt; but, if the statement is super simple, and you can fit the return on a single line, the actual &lt;code&gt;return&lt;/code&gt; and curly braces can also be omitted, like in &lt;code&gt;basicArrow2()&lt;/code&gt;. This is concise body syntax with an implied return statement.&lt;/p&gt;
&lt;h3&gt;Arrow function traits&lt;/h3&gt;
&lt;p&gt;While arrow functions are easy to identify at first glance, they actually have some traits which are odd and specific to them, and which developers need to keep in mind.&lt;/p&gt;
&lt;p&gt;In addition to their concise syntax, arrow functions lack the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this&quot;&gt;this&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments&quot;&gt;arguments&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super&quot;&gt;super&lt;/a&gt;, or &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target&quot;&gt;new.target&lt;/a&gt; keywords.&lt;/p&gt;
&lt;p&gt;These facts also lend themselves to one of the arrow function’s biggest drawbacks: they are ill suited as methods and cannot be used as constructors. I’ll get to that in more detail soon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Shorter function syntax&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first, and biggest improvement, in my opinion, to regular function expressions is the shorter, more concise syntax that arrow functions offer.&lt;/p&gt;
&lt;p&gt;Here’s the exact same function written as a traditional function expression, then written again as an arrow function expression.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional function expression&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var elements = [&quot;Hydrogen&quot;, &quot;Helium&quot;, &quot;Lithium&quot;, &quot;Beryllium&quot;];

elements.map(function(element) {
  return element.length;
});
// this statement returns the array: [8, 6, 7, 9]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;New arrow function expression&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var elements = [&quot;Hydrogen&quot;, &quot;Helium&quot;, &quot;Lithium&quot;, &quot;Beryllium&quot;];

elements.map((element) =&amp;gt; element.length);
// this statement still returns the same array: [8, 6, 7, 9]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look at those and tell me the second function isn’t easier to read and follow what the code is doing.&lt;/p&gt;
&lt;p&gt;That by itself, is my biggest reason to want to use arrow functions whenever possible. It’s just so much cleaner and clearer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Hoisting still doesn&apos;t apply&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just like with traditional function expressions, hoisting still does not apply to arrow functions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No hoisting, only &lt;code&gt;TypeErrors&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(fish()); 
// prints: TypeError: fish is not a function

const fish = () =&amp;gt; [&quot;perch&quot;, &quot;salmon&quot;, &quot;trout&quot;, &quot;bass&quot;];

console.log(fish());
// prints: [&quot;perch&quot;, &quot;salmon&quot;, &quot;trout&quot;, &quot;bass&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you try to call the &lt;code&gt;fish()&lt;/code&gt; function before it’s declared in the code, a &lt;code&gt;TypeError&lt;/code&gt; will be thrown.&lt;/p&gt;
&lt;p&gt;The solution, as before, is to either declare the function as a function declaration so it gets hoisted to the top of the scope, or wait until after the function expression to call the code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. No separate &quot;this&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before arrow functions, every new function defined its own &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this&quot;&gt;&lt;code&gt;this&lt;/code&gt;&lt;/a&gt; value based on how the function was called:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A new object in the case of a constructor,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;undefined&lt;/code&gt; in strict mode function calls,&lt;/li&gt;
&lt;li&gt;The base object if the function was called as an &quot;object method&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An arrow function, on the other hand, does not have its own &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;this&lt;/code&gt; value of the enclosing lexical scope is used. Arrow functions follow the normal variable lookup rules of starting at the current scope level and searching all the way to the highest level looking for the variable. So while searching for &lt;code&gt;this&lt;/code&gt; which is not present in the current scope, an arrow function ends up finding the this object from its enclosing scope.&lt;/p&gt;
&lt;p&gt;See the example below to see the difference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;this&lt;/code&gt; scope, according to function declarations&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Person() {
  // The Person() constructor defines `this` as an instance of itself.
  this.age = 0;

  setInterval(function growUp() {
    // In non-strict mode, the growUp() function defines `this`
    // as the global object (because it&apos;s where growUp() is executed.), 
    // which is different from the `this`
    // defined by the Person() constructor.
    this.age++;
  }, 1000);
}

var p = new Person();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;this&lt;/code&gt; scope, according to arrow functions&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Person(){
  this.age = 0;

  setInterval(() =&amp;gt; {
    // `this` properly refers to the Person object
    this.age++; 
  }, 1000);
}

var p = new Person();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4. No binding of arguments&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In addition to not having access to &lt;code&gt;this&lt;/code&gt;, arrow functions do not have their own &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments&quot;&gt;&lt;code&gt;arguments&lt;/code&gt; object&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since you may not have heard of them, &lt;code&gt;arguments&lt;/code&gt; is an &lt;code&gt;Array&lt;/code&gt;-like object inside a function that contains the values passed to that function. I say &lt;code&gt;Array&lt;/code&gt;-like because this &lt;code&gt;arguments&lt;/code&gt; has a length property and indexing but it lacks Array’s built-in methods like &lt;code&gt;.forEach()&lt;/code&gt; and &lt;code&gt;.map()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thus, in this example, &lt;code&gt;arguments&lt;/code&gt; is simply a reference to the arguments of the enclosing scope.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;arguments&lt;/code&gt; with arrow functions&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var arguments = [1, 2, 3];
var arr = () =&amp;gt; arguments[0];

arr(); 
// prints: 1

function foo(n) {
  var f = () =&amp;gt; arguments[0] + n; 
  // foo&apos;s implicit arguments binding. arguments[0] is n
  return f();
}

foo(3); 
// prints: 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In most cases, using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters&quot;&gt;rest parameters&lt;/a&gt; is a good alternative to using an &lt;code&gt;arguments&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rest parameters instead of &lt;code&gt;arguments&lt;/code&gt; with arrow functions&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function foo(n) { 
  var f = (...args) =&amp;gt; args[0] + n;
  return f(10); 
}

foo(1); 
// prints: 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rest parameters, which I’ll discuss in another blog post later in this series, is the ES6-recommended way of accessing and manipulating &lt;code&gt;arguments&lt;/code&gt; inside of arrow functions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. No use of &quot;new&quot; as a constructor&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, last arrow function trait to know about: arrow functions cannot be used as constructors and will throw a &lt;code&gt;TypeError&lt;/code&gt; when used with the &lt;code&gt;new&lt;/code&gt; keyword.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var Foo = () =&amp;gt; {};

var foo = new Foo(); 
// prints: TypeError: Foo is not a constructor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it. That’s generally what you need to know about arrow functions. Simple! 😅&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;JavaScript is an incredibly powerful programming language, and its popularity only continues to increase (if the yearly developer surveys are to be believed). With so many developers using it though, there’s bound to be some misconceptions and knowledge gaps, especially with the growing widespread adoption of ES6 into everyday use.&lt;/p&gt;
&lt;p&gt;My aim is to shed light on some of the JavaScript and ES6 syntax you use everyday, but may never have fully grasped the nuances of why it works the way it works.&lt;/p&gt;
&lt;p&gt;Functions of all kinds are a staple of JavaScript, be they traditional function declarations or function expressions, or the newer, more concise ES6 arrow functions. Knowing when (and how to) effectively take advantage of the benefits of each type of function will definitely make writing JS easier.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you feel better equipped to incorporate arrow functions into your JavaScript applications. Please share this with your friends if you found it helpful!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function&quot;&gt;Function declaration, MDN docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/web/JavaScript/Reference/Operators/function&quot;&gt;Function expression, MDN docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;Arrow functions, MDN docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>Var, Let &amp; Const: JavaScript ES6 Feature Series (Pt 1)</title><link>https://www.paigeniedringhaus.com/blog/var-let-const-javascript-es6-feature-series-pt-1/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/var-let-const-javascript-es6-feature-series-pt-1/</guid><description>Let&apos;s begin at the beginning...</description><pubDate>Sun, 28 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt1-var-let-const/blocks-hero.webp&quot; alt=&quot;Close up of children&apos;s blocks&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The inspiration behind these posts is simple: there are still plenty of developers for whom JavaScript is a mystery — or at the very least, a little less understood.&lt;/p&gt;
&lt;p&gt;Add to that ES6, and the updates that the ECMAScript committee is now planning to release yearly, and it’s a lot of info to keep abreast of.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/pt1-var-let-const/barney-gif.gif&quot; alt=&quot;Barney head exploding&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Sorry, couldn’t help myself — I love Barney from How I Met Your Mother.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I wanted to provide a bunch of posts about JavaScript ES6 features that I use regularly, for developers to reference.&lt;/p&gt;
&lt;p&gt;The aim is for these articles to be short, in-depth explanations about various improvements to the language (and how to use them), that I hope will inspire you to write some really cool stuff using JS. Who knows, you might even learn something new along the way. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For my first post, it makes sense to begin at the beginning with var, let, and const: the building blocks of JavaScript.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Var&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript_syntax#Variables&quot;&gt;&lt;strong&gt;&lt;code&gt;var&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; is the original JavaScript syntax: the OG way to declare a variable, and optionally, initialize it as a value. It’s been around since the beginning of the language, long before ES6 was even a thought in anyone’s head.&lt;/p&gt;
&lt;p&gt;Variables have no pre-defined or attached type in JavaScript, meaning any value can be stored in any variable. Some examples:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Assigning values to variables&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var one = 1; // the integer 1 has just been assigned to the variable one

var two = &apos;two&apos;; // the string &apos;two&apos; has been assigned to the variable two

var paige = {
  gender: female,
  hairColor: red,
  eyeColor: blue
};
// the object containing a person&apos;s traits has been assigned to the variable paige
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of the &lt;code&gt;var&lt;/code&gt;s above are valid examples of how JavaScript allows any value to be assigned to any variable, unlike strongly typed languages like Java, which (until recently), required all variables be declared and typed before compile time.&lt;/p&gt;
&lt;p&gt;Another thing to know about &lt;code&gt;var&lt;/code&gt; is that it is regardless of if it is globally or locally scoped, these variables can be re-declared and updated at will. Check out this perfectly valid example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reusing the same variable with different value types&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var greet = &quot;Hello there&quot;;
console.log(greet); // prints: &quot;Hello there&quot;

greet = true
console.log(greet); // prints: true

greet = 11;
console.log(greet); // prints: 11

greet = welcome = (name) =&amp;gt; { 
  return `Hi ${name}. Welcome!`
};
console.log(greet(&quot;Paige&quot;)); // prints &quot;Hi Paige. Welcome!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although I reused the existing variable &lt;code&gt;greet&lt;/code&gt;, JavaScript throws no error, regardless of whether the variable is a string, a boolean, an integer — heck, even a function.&lt;/p&gt;
&lt;h3&gt;Variable declarations, lexical scoping, and hoisting&lt;/h3&gt;
&lt;p&gt;There are a few things to be aware of (which have tripped up many a developer, myself included), when using &lt;code&gt;var&lt;/code&gt;. These types of variables are &lt;strong&gt;&quot;lexically scoped&quot;&lt;/strong&gt; and subject to what’s known as &lt;strong&gt;&quot;hoisting.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What this means in execution is that a &lt;code&gt;var&lt;/code&gt;-type variable, no matter where it is defined inside of a block of code, will be pulled to the top of its scope before code execution. For example, if you wrote a few lines of JavaScript, then declared &lt;code&gt;var tree = &quot;elm&quot;;&lt;/code&gt;, at run time, behind the scenes, var tree would be &quot;hoisted&quot; to the top of the scope where it was defined.&lt;/p&gt;
&lt;p&gt;It may not be assigned to the value of &lt;code&gt;&quot;elm&quot;&lt;/code&gt; until several lines later, but the variable would exist according to the JavaScript engine. Here’s an example to show how this works, and what it could mean.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Variable declaration versus variable assignment in JavaScript&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var greeter; {/* the JS engine knows greeter is a variable, 
but it doesn&apos;t know what value greeter has */}
console.log(greeter); // currently, greeter prints: undefined

greeter = &quot;say hello&quot;; // now, greeter&apos;s been assigned to the value &quot;say hello&quot;
console.log(greeter); // prints: &quot;say hello&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lexical scoping also comes into play here. Without going too much into the details of lexical scoping in JavaScript (because that’s a whole other blog post), the word “lexical” refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available.&lt;/p&gt;
&lt;p&gt;This boils down to if a variable is created in the global scope, it’s hoisted to the top of the global scope, if the variable is created within a function, it’s hoisted to the top of the function, and so on and so forth.&lt;/p&gt;
&lt;p&gt;Here are examples of variable hoisting and lexical scoping in action as the JavaScript engine runs.&lt;/p&gt;
&lt;h3&gt;Variable hoisting based on lexical scoping&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var something; // declaration is hoisted to the top of the global scope
console.log(something); // prints: undefined

function doAnotherThing() {
  var anotherThing; {/*} declaration is hoisted to the top of the function&apos;s 
  lexical scope but not immediately assigned a value */}
  var thisOneThing = &quot;a defined value&quot;; // this variable is hoisted and then immediately defined

  function useAnotherThing(anotherThing) {
    console.log(`The value of another thing: ${anotherThing}`);
  }

  function useThisOneThing(thisOneThing) {
    console.log(`The value of this one thing: ${thisOneThing}`)
  }

  useAnotherThing(anotherThing); 
  {/* prints: &quot;The value of another thing: undefined&quot; because the variable 
  wasn&apos;t assigned a value until AFTER the function useAnotherThing() ran */}

  anotherThing = &quot;an undefined value&quot;; 
  // finally the variable, initialized earlier, is assigned a value

  useThisOneThing(thisOneThing); 
  {/*} prints: &quot;The value of this one thing: a defined value&quot; because 
  the variable was assigned a value before the function useThisOneThing() ran */}
}

something = &quot;that thing&quot;;

console.log(something); // prints: &quot;that thing&quot;
console.log(doAnotherThing()); // see printouts above next to inner functions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above I show how the variables &lt;code&gt;something&lt;/code&gt; and &lt;code&gt;anotherThing&lt;/code&gt;, by not being immediately assigned values after being declared are &lt;code&gt;undefined&lt;/code&gt; when &lt;code&gt;console.log()&lt;/code&gt; is called on them. Once their values are set further down the script and &lt;code&gt;console.log()&lt;/code&gt; is called again, they print their values to the console.&lt;/p&gt;
&lt;p&gt;The variable &lt;code&gt;thisOneThing&lt;/code&gt;, however, is initialized and assigned a value immediately after initialization, meaning that when the function using it: &lt;code&gt;useThisOneThing()&lt;/code&gt; is run (which is also an example of a JavaScript &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures&quot;&gt;&lt;strong&gt;&quot;closures&quot;&lt;/strong&gt;&lt;/a&gt; at work), it prints out the string &lt;code&gt;&quot;The value of this one thing: a defined value.&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I think this is enough about &lt;code&gt;var&lt;/code&gt; and how it works. There’s a million other tutorials talking about it, too. Now, let’s get on to the exciting, new ES6 variable syntax, and how these types of variables are different.&lt;/p&gt;
&lt;h2&gt;Let&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let&quot;&gt;&lt;strong&gt;&lt;code&gt;let&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; was finalized and officially introduced for widespread use with the release of ES6 in 2015. Of the two new variable types introduced, it is the much more flexible and ephemeral of the pair.&lt;/p&gt;
&lt;h3&gt;Let&apos;s similarities to var&lt;/h3&gt;
&lt;p&gt;While let is a totally new variable type, it does have share a couple of commonalities with &lt;code&gt;var&lt;/code&gt;. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;let&lt;/code&gt; is initialized, it can optionally be assigned a value at initialization time,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;let&lt;/code&gt; is also a variable type that can be mutated and / or reassigned to different data types at run-time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that’s pretty much where the similarities end.&lt;/p&gt;
&lt;h3&gt;Let&apos;s differences to var&lt;/h3&gt;
&lt;p&gt;Ok, here’s where it gets interesting and &lt;code&gt;let&lt;/code&gt; begins to differ from &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Block scoping and variable declaration and assignment&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;let&lt;/code&gt; is block scoped to the statement, or expression within which it is used, unlike &lt;code&gt;var&lt;/code&gt;, which defines a variable globally, or locally to an entire function regardless of block scope.&lt;/p&gt;
&lt;p&gt;Bottom line: &lt;code&gt;let&lt;/code&gt; lives inside a chunk of code (usually) defined by curly braces like so &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, &lt;code&gt;let&lt;/code&gt;’s value can be updated but not redeclared as a new variable inside of the same scope, which &lt;code&gt;var&lt;/code&gt;-type variables can. There’s an example below showing the differences between &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Valid assignments of let based on block scoping&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here is a valid example of assigning the variable greeting using the let keyword in the same file, but in different block scopes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let greeting = &quot;say Hi&quot;; // one variable declared in the global scope

if (true) {
  let greeting = &quot;say Hello instead&quot;; 
  {/*  another variable of the same name declared within this inner, block scope */}
  console.log(greeting); // prints &quot;say Hello instead&quot;
}
console.log(greeting); // prints: &quot;say Hi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Invalid assignments of let due to block scoping&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since this &lt;code&gt;let greeting&lt;/code&gt; variable is assigned a value in the global scope, it cannot be redeclared and reassigned to a new value within the same scope. If this scenario occurs, it throws a &lt;code&gt;SyntaxError&lt;/code&gt; in the console.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let greeting = &quot;say Hi&quot;;
let greeting = &quot;say Hello instead&quot;; //SyntaxError: Identifier &quot;greeting&quot; has already been declared
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doing the same type of thing with var produces no such error.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var fruit = &quot;banana&quot;;
console.log(fruit);  // prints: &quot;banana&quot;

var fruit = &quot;pear&quot;;
console.log(fruit); // prints: &quot;pear&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Variable hoisting (or lack thereof) and global objects&lt;/h3&gt;
&lt;p&gt;Hoisting does not apply to &lt;code&gt;let&lt;/code&gt;. Unlike &lt;code&gt;var&lt;/code&gt; a &lt;code&gt;let&lt;/code&gt;-type variable won’t be initialized to &lt;code&gt;undefined&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; its definition gets evaluated by the parser.&lt;/p&gt;
&lt;p&gt;If you try to use a &lt;code&gt;let&lt;/code&gt; variable before the part of the code where it’s initialized, you’ll get a &lt;code&gt;ReferenceError&lt;/code&gt; thrown.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ReferenceError of let because it was called before parsed&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&quot;test 0&quot;, test)

let test; // prints: ReferenceError: test is not defined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And at the top level of programs and functions, &lt;code&gt;let&lt;/code&gt;, unlike &lt;code&gt;var&lt;/code&gt;, does not create a property on the global &lt;code&gt;window&lt;/code&gt; object when declared in the top-most scope either. It’s not necessarily a bad thing, it means less pollution of the global namespace, which we can all benefit from, but it also means you can’t use the oft misunderstood &lt;code&gt;this&lt;/code&gt; property to access said global variables either.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No global object properties with let&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var x = &quot;global&quot;;
let y = &quot;global&quot;;

console.log(this.x); // prints: &quot;global&quot;
console.log(this.y); // prints: undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, I think that’s enough about &lt;code&gt;let&lt;/code&gt;, it’s time to move to the stricter, more immutable variable type &lt;code&gt;const&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Const&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const&quot;&gt;&lt;strong&gt;const&lt;/strong&gt;&lt;/a&gt; came about in the same ES6 release as &lt;code&gt;let&lt;/code&gt; back in 2015. But where &lt;code&gt;let&lt;/code&gt; provides increased flexibility and less permanent variables, &lt;code&gt;const&lt;/code&gt; provides more rigidity and permanence.&lt;/p&gt;
&lt;p&gt;It is also, by far, the most different of the three variable types.&lt;/p&gt;
&lt;h3&gt;Const&apos;s defining traits&lt;/h3&gt;
&lt;p&gt;This variable declaration shares some things with let.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;const&lt;/code&gt;, too, is limited to block scoping,&lt;/li&gt;
&lt;li&gt;It does not create properties on the &lt;code&gt;window&lt;/code&gt; object when it’s created in the global scope,&lt;/li&gt;
&lt;li&gt;When it is declared it must also have a value assigned to it,&lt;/li&gt;
&lt;li&gt;And it is not hoisted at run time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Block Scoping&lt;/h3&gt;
&lt;p&gt;Const has the same type of block scoping that &lt;code&gt;let&lt;/code&gt; does, but once &lt;code&gt;const&lt;/code&gt; is used to declare a variable, that value can’t be changed through reassignment or redeclared within that scope.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;const reassignment TypeErrors and redeclaration SyntaxErrors within the same scope&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pet = &quot;dog&quot;;
console.log(pet);  // prints: &quot;dog&quot;

pet = &quot;cat&quot;; // TypeError: Assignment to constant variable
console.log(pet);

const person = &quot;Sean&quot;;
const person = &quot;George&quot;; // SyntaxError: Identifier &quot;person&quot; has already been declared
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both pointing the existing &lt;code&gt;pet&lt;/code&gt; variable towards a different value or trying to redeclare &lt;code&gt;person&lt;/code&gt; within the same scope results in errors in the console.&lt;/p&gt;
&lt;p&gt;But with block scoping in mind, the following examples work with no issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Valid block scoping of variables using const&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pet = &quot;dog&quot;;
console.log(pet);  // prints: &quot;dog&quot;

if (true) {
  const pet = &quot;cat&quot;; // TypeError: Assignment to constant variable
  console.log(pet);  // prints: &quot;cat&quot;
}

const person = &quot;Sean&quot;;
console.log(person); // prints: &quot;Sean&quot;

function meet() { 
  const person = &quot;George&quot;; 
  console.log(`Meet ${person}`);
}
console.log(meet()); // prints: &quot;Meet George&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Immutability (sort of)&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;const&lt;/code&gt; creates a &lt;em&gt;read-only&lt;/em&gt; reference to a value. The caveat to that statement though is the value itself is mutable, but &lt;code&gt;const&lt;/code&gt;, once assigned, cannot be reassigned.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;const&lt;/code&gt; is assigned to an object, the properties within that object can still be updated and changed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;const’s reference to an updatable object&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greeting = {
  message: &quot;Hello there&quot;,
  person: &quot;Paige&quot;
};
console.log(greeting); // prints: { message: &quot;Hello there&quot;, person: &quot;Paige&quot; }

greeting.message = &quot;Hi there&quot;;
console.log(greeting); // prints: { message: &quot;Hi there&quot;, person: &quot;Paige&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Simultaneous declaration, initialization and no global object&lt;/h3&gt;
&lt;p&gt;Global constants like &lt;code&gt;const&lt;/code&gt; do not become properties of the &lt;code&gt;window&lt;/code&gt; object, unlike &lt;code&gt;var&lt;/code&gt; variables. An initializer for a constant is also required; that is, you must specify its value in the same statement in which it&apos;s declared (which makes sense, given that it can&apos;t be changed later).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;const not polluting the global scope with object properties&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var x = &quot;global&quot;;

const y = &quot;global&quot;;

console.log(this.x); // prints: &quot;global&quot;

console.log(this.y); // prints: undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;const&lt;/code&gt; is not assigned a value when it is initialized it will throw a &lt;code&gt;SyntaxError&lt;/code&gt;. Likewise, if a script tries to invoke it before the parser has reached the variable, it will throw a ReferenceError just like &lt;code&gt;let&lt;/code&gt; because &lt;code&gt;const&lt;/code&gt; is not subject to hoisting and it cannot be set to &lt;code&gt;undefined&lt;/code&gt; before being assigned a value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Errors From calling variables before declaration or initializing with value assignment&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(fruitTree); // ReferenceError: fruitTree is not defined

const fruitTree = &quot;fig tree&quot;;

const tree; // SyntaxError: Missing initializer in const declaration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that is about all there is to know about &lt;code&gt;const&lt;/code&gt;, as well.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The JavaScript language has been around for more than 20 years and even ES6 has been out since 2015, but even so, there’s still plenty of misconceptions and knowledge gaps about it.&lt;/p&gt;
&lt;p&gt;My aim of this series is to dispel those myths and give you a better understanding of JavaScript, and introduce some of the ES6 syntax you may use everyday but not fully grasp the nuances of.&lt;/p&gt;
&lt;p&gt;Since everything in JavaScript is built around variables, it seemed like an appropriate place to start with &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;let&lt;/code&gt;, and &lt;code&gt;const&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you learned something new about the most basic building blocks of JS: the humble variables. Please share this with your friends if you found it helpful!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var&quot;&gt;Var, MDN docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let&quot;&gt;Let, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const&quot;&gt;Const, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript_syntax&quot;&gt;JavaScript syntax, Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category></item><item><title>JavaScript International Methods</title><link>https://www.paigeniedringhaus.com/blog/javascript-international-methods/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/javascript-international-methods/</guid><description>Because date formatting is pain &amp; international formatting is impossible</description><pubDate>Sun, 07 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/js-intl-methods/stumped-hero.webp&quot; alt=&quot;Completely stumped developer&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Why is this so hard??&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I&apos;m lucky in that the company I work for is based mainly in the US, with a few additional locations in Mexico and Canada. This makes my job so much easier because I don&apos;t have to worry much about internationalization: not about converting to different date formats, not about the idiosyncrasies resulting from language translations, and certainly not about the oddities regarding lists and currencies in other countries (really — who puts commas after periods when it comes to money??).&lt;/p&gt;
&lt;p&gt;Just because these aren&apos;t my problems though, doesn&apos;t mean they aren&apos;t incredibly painful for other engineers. As an example, a lack of international standardizations (and the inability to convert numbers) resulted in a mismatch of metric units versus English units, causing NASA&apos;s Mars Orbiter to completely miss entering orbit around Mars in 1999, to the tune of $125 million.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/js-intl-methods/picard-facepalm.gif&quot; alt=&quot;Capt Picard face palm&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Oof...&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;While the sums of money my software development team works with aren&apos;t quite so large, and our errors result in bugs in the code we can usually fix in a matter of hours or days, I can definitely empathize with the NASA engineers, and I cringe thinking about how one simple mistake like not double checking everyone was using the same measurements in Orbiter&apos;s code caused such a loss.&lt;/p&gt;
&lt;p&gt;Which is why, when I heard the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl&quot;&gt;ECMAScript Internationalization API&lt;/a&gt; had recently been released, I was excited to see what kinds of improvements were about to make JavaScript around the world better and more standardized for everyone using it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, let&apos;s check out some of the best parts of Intl: the ECMAScript Internationalization API, which provides language sensitive string comparison, number formatting, and date and time formatting.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;International date time highlights&lt;/h2&gt;
&lt;p&gt;As per usual, Mozilla&apos;s MDN Web Docs, give the best summation of the new international API, and the properties that come with it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The INTL object provides access to several constructors as well as functionality common to the internationalization constructors and other language sensitive functions. — &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl&quot;&gt;MDN Web Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&apos;s six properties that come along with the new &lt;code&gt;Intl&lt;/code&gt; object, but in my opinion, only five of them deserve their own place in this blog post.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Intl.DateTimeFormat&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Intl.ListFormat&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Intl.NumberFormat&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Intl.PluralRules&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So without further preamble, I&apos;ll dive into the first property: the international date time format.&lt;/p&gt;
&lt;h3&gt;International date time format&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/js-intl-methods/date-time-nonsense.webp&quot; alt=&quot;Wrong date, wrong date, finally correctly formatted date&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Yes, we&apos;ve all been there. Yes, it&apos;s really this much of a nightmare with dates and times.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat&quot;&gt;&lt;strong&gt;&lt;code&gt;Intl.DateTimeFormat&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; object is a constructor for objects enabling language-sensitive date and time formatting.&lt;/p&gt;
&lt;p&gt;At its most basic, the date time format takes in &lt;code&gt;locales&lt;/code&gt; and &lt;code&gt;options&lt;/code&gt; objects and outputs formatted time stamps based on those options.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example using &lt;code&gt;locales&lt;/code&gt; from around the globe to format this date variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intl.DateTimeFormat &lt;code&gt;locales&lt;/code&gt; example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));

// using US date time formatting
console.log(new Intl.DateTimeFormat(&apos;en-US&apos;).format(date));
// expected output: &quot;12/19/2012&quot; // using Great Britain date time formatting

console.log(new Intl.DateTimeFormat(&apos;en-GB&apos;).format(date));
// expected output: &quot;19/12/2012&quot;

// Include a fallback language, in this case US English with the Buddhist calendar
console.log(new Intl.DateTimeFormat([&apos;en-US-u-ca-buddhist&apos;]).format(date));
// expected output: &quot;12/19/2555&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition to being able to pass in locations, users can provide additional parameters strung together with the location, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nu&lt;/code&gt; — the number systems used in different countries,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ca&lt;/code&gt; — the calendar to use,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hc&lt;/code&gt; — hour cycle ( &lt;code&gt;h11&lt;/code&gt;, &lt;code&gt;h24&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After the additions to &lt;code&gt;locales&lt;/code&gt;, comes the optional &lt;code&gt;options&lt;/code&gt; object which can include properties like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;timezone&lt;/code&gt; — this can be either &lt;code&gt;&quot;UTC&quot;&lt;/code&gt; or something like &lt;code&gt;&quot;America/New_York&quot;&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hourCycle&lt;/code&gt; — once again, specs like &lt;code&gt;&quot;h12&quot;&lt;/code&gt; or &lt;code&gt;&quot;h23&quot;&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;and my favorite one: &lt;code&gt;formatMatcher&lt;/code&gt; — this algorithm can take in properties used to describe date-times and format the outputs to match.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Subsets for &lt;code&gt;formatMatcher&lt;/code&gt; include things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;weekday&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt;, &lt;code&gt;month&lt;/code&gt;, &lt;code&gt;day&lt;/code&gt;, &lt;code&gt;hour&lt;/code&gt;, &lt;code&gt;minute&lt;/code&gt;, &lt;code&gt;second&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hour&lt;/code&gt;, &lt;code&gt;minute&lt;/code&gt;, &lt;code&gt;second&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And even then, the subset properties have different options. Here are the options for &lt;code&gt;weekday&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;long&quot;&lt;/code&gt; (e.g., &lt;code&gt;Thursday&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;short&quot;&lt;/code&gt; (e.g., &lt;code&gt;Thu&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;narrow&quot;&lt;/code&gt; (e.g., &lt;code&gt;T&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check out this example using &lt;code&gt;DateTimeFormat&lt;/code&gt;&apos;s &lt;code&gt;options&lt;/code&gt; arguments to format the outputs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intl.DateTimeFormat &lt;code&gt;options&lt;/code&gt; arguments example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));

// request a weekday along with a long date in Japanese
var options = { weekday: &apos;long&apos;, year: &apos;numeric&apos;, month: &apos;long&apos;, day: &apos;numeric&apos; };
console.log(new Intl.DateTimeFormat(&apos;ja-JP&apos;, options).format(date));
// expected output: &quot;2012年12月19日水曜日&quot;

// an application may want to use UTC and make that visible in German
options.timeZone = &apos;UTC&apos;;
options.timeZoneName = &apos;short&apos;;
console.log(new Intl.DateTimeFormat(&apos;de-DE&apos;, options).format(date));
// expected output: &quot;Donnerstag, 20. Dezember 2012, UTC&quot;

// sometimes you want to be more precise in Australian English
options = {
  hour: &apos;numeric&apos;, minute: &apos;numeric&apos;, second: &apos;numeric&apos;, 
  timeZone: &apos;Australia/Sydney&apos;,
  timeZoneName: &apos;short&apos;
};
console.log(new Intl.DateTimeFormat(&apos;en-AU&apos;, options).format(date));
// expected output: &quot;2:00:00 pm AEDT&quot;

// even the US needs 24-hour time for some occasions
options = {
  year: &apos;numeric&apos;, month: &apos;numeric&apos;, day: &apos;numeric&apos;,
  hour: &apos;numeric&apos;, minute: &apos;numeric&apos;, second: &apos;numeric&apos;,
  hour12: false,
  timeZone: &apos;America/Los_Angeles&apos; 
};
console.log(new Intl.DateTimeFormat(&apos;en-US&apos;, options).format(date));
// expected output: &quot;12/19/2012, 19:00:00&quot;

// to specify options but use the browser&apos;s default locale, use &apos;default&apos;
console.log(new Intl.DateTimeFormat(&apos;default&apos;, options).format(date));
// expected output: &quot;12/19/2012, 19:00:00&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is such a cool feature. It&apos;s going to make it so much easier to translate dates and times properly and format them in so many specific ways that packages like &lt;a href=&quot;https://momentjs.com/&quot;&gt;moment.js&lt;/a&gt;, made specifically for parsing, validating and manipulating JavaScript dates and times, will become unnecessary.&lt;/p&gt;
&lt;p&gt;The next property I want to segue into, since I&apos;m already on the subject of dates, is international relative time format.&lt;/p&gt;
&lt;h3&gt;International relative time format&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat&quot;&gt;&lt;strong&gt;&lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; object is a constructor for objects that enables language-sensitive relative time formatting.&lt;/p&gt;
&lt;p&gt;Similar to the &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt;, this object takes in a &lt;code&gt;locales&lt;/code&gt; parameter and an &lt;code&gt;options&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;locales&lt;/code&gt; parameter functions exactly the same in this relative time format object as it does in the date time format, so I&apos;ll skip any further explanation here.&lt;/p&gt;
&lt;p&gt;As for &lt;code&gt;options&lt;/code&gt;, the &lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt; has a variety of additional properties it accepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localeMatcher&lt;/code&gt; — a locale matching algorithm, with the options &lt;code&gt;&quot;best fit&quot;&lt;/code&gt; or &lt;code&gt;&quot;lookup&quot;&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;numeric&lt;/code&gt; — the format of the output message,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style&lt;/code&gt; — the length of the internationalized message.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;style&lt;/code&gt; follows the same lines as &lt;code&gt;weekday&lt;/code&gt;, in that it has three different values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;long&quot;&lt;/code&gt; (default, e.g., &lt;code&gt;in 2 months&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;short&quot;&lt;/code&gt; (e.g., in &lt;code&gt;2 mo.&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;or &lt;code&gt;&quot;narrow&quot;&lt;/code&gt; (e.g., in &lt;code&gt;2 mo.&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;narrow&lt;/code&gt; and &lt;code&gt;short&lt;/code&gt; could be the same depending on the country.&lt;/p&gt;
&lt;p&gt;Below are some samples using &lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt; in various &lt;code&gt;locales&lt;/code&gt; and with various &lt;code&gt;options&lt;/code&gt; passed to them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intl.RelativeTimeFormat examples&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var rtf1 = new Intl.RelativeTimeFormat(&apos;en&apos;, { style: &apos;narrow&apos; });
// relative time formats in English

console.log(rtf1.format(3, &apos;quarter&apos;));
//expected output: &quot;in 3 qtrs.&quot;

console.log(rtf1.format(-4, &apos;hour&apos;));
//expected output: &quot;4 hr. ago&quot;

var rtf2 = new Intl.RelativeTimeFormat(&apos;de&apos;, { numeric: &apos;auto&apos; });
// relative time formats in German

console.log(rtf2.format(2, &apos;day&apos;));
//expected output: &quot;übermorgen&quot;

// Create a relative time formatter in your locale
// with default values explicitly passed in.
const rtf = new Intl.RelativeTimeFormat(&quot;en&quot;, {
    localeMatcher: &quot;best fit&quot;, // other values: &quot;lookup&quot;
    numeric: &quot;always&quot;, // other values: &quot;auto&quot;
    style: &quot;long&quot;, // other values: &quot;short&quot; or &quot;narrow&quot;
});

// Format relative time in English using negative value (-1).
console.log(rtf.format(-1, &quot;day&quot;));
// &amp;gt; &quot;1 day ago&quot;

// Format relative time in English using positive value (1).
console.log(rtf.format(2, &quot;day&quot;));
// &amp;gt; &quot;in 2 days&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once again, super handy that we, as developers, don&apos;t have to deal with the logic of formatting days or hours or even some words, in &lt;em&gt;multiple languages&lt;/em&gt; no less, according to the number passed in. No complicated &lt;code&gt;if/else&lt;/code&gt; logic blocks or even ternary expressions.&lt;/p&gt;
&lt;p&gt;With the help of &lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt; just specify the language to use, the &lt;code&gt;numeric&lt;/code&gt; output and the &lt;code&gt;style&lt;/code&gt; and it&apos;s good to go. Nice! 😄&lt;/p&gt;
&lt;p&gt;On that note of the Internationalization API, let&apos;s look next at another thing that varies quite a bit from language to language: how lists are formatted.&lt;/p&gt;
&lt;h3&gt;International list format&lt;/h3&gt;
&lt;p&gt;It&apos;s tough enough transforming an array in one language into something that resembles a human-readable list with &lt;code&gt;ands&lt;/code&gt; or &lt;code&gt;ors&lt;/code&gt; added in, try doing that in multiple languages.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ListFormat&quot;&gt;&lt;strong&gt;&lt;code&gt;Intl.ListFormat&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; object is a constructor for objects to enable language-sensitive list formatting.&lt;/p&gt;
&lt;p&gt;As is becoming the recurring theme of this article, the first optional parameter &lt;code&gt;ListFormat&lt;/code&gt; accepts is a &lt;code&gt;locales&lt;/code&gt; specification.&lt;/p&gt;
&lt;p&gt;The second object is &lt;code&gt;options&lt;/code&gt; with parameters like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localeMatcher&lt;/code&gt; — the locale matching algorithm, same options as with &lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt; — the format of the output message. Possible values are &lt;code&gt;&quot;conjunction&quot;&lt;/code&gt;, which stands for &quot;and&quot;-based lists (default, e.g., &lt;code&gt;1, 2, and 3&lt;/code&gt;), or &lt;code&gt;&quot;disjunction&quot;&lt;/code&gt; that stands for &quot;or&quot;-based lists (e.g., &lt;code&gt;1, 2, or 3&lt;/code&gt;). &lt;code&gt;&quot;unit&quot;&lt;/code&gt; stands for lists of values with units (e.g., &lt;code&gt;7 pounds, 11 ounces&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style&lt;/code&gt; — the length of the formatted message. Values include &lt;code&gt;&quot;long&quot;&lt;/code&gt;, &lt;code&gt;&quot;short&quot;&lt;/code&gt;, or &lt;code&gt;&quot;narrow&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&apos;s some examples of how you could use the &lt;code&gt;Intl.ListFormat&lt;/code&gt; object in practice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intl.ListFormat examples&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const vehicles = [&apos;Cat&apos;, &apos;Dog&apos;, &apos;Fish&apos;];

// list formats in English
const formatter = new Intl.ListFormat(&apos;en&apos;, { style: &apos;long&apos;, type: &apos;conjunction&apos; });

console.log(formatter.format(vehicles));
// expected output: &quot;Cat, Dog, and Fish&quot;

// list formats in French
const formatter2 = new Intl.ListFormat(&apos;fr&apos;, { style: &apos;short&apos;, type: &apos;disjunction&apos; });
console.log(formatter2.format(vehicles));
// expected output: &quot;Cat, Dog ou Fish&quot;

// list formats in Spanish
const formatter3 = new Intl.ListFormat(&apos;es&apos;, { style: &apos;narrow&apos;, type: &apos;unit&apos; });
console.log(formatter3.format(vehicles));
// expected output: &quot;Cat Dog Fish&quot;

const list = [&apos;BMW&apos;, &apos;Volvo&apos;, &apos;Audi&apos;];

// list formats in British English
console.log(new Intl.ListFormat(&apos;en-GB&apos;, { style: &apos;long&apos;, type: &apos;conjunction&apos; }).format(list));
// expected output: &quot;BMW, Volvo and Audi&quot;

console.log(new Intl.ListFormat(&apos;en-GB&apos;, { style: &apos;short&apos;, type: &apos;disjunction&apos; }).format(list));
// expected output: &quot;BMW, Volvo or Audi&quot;

console.log(new Intl.ListFormat(&apos;en-GB&apos;, { style: &apos;narrow&apos;, type: &apos;unit&apos; }).format(list));
// expected output: &quot;BMW Volvo Audi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How awesome is it that finally, &lt;em&gt;finally&lt;/em&gt; there&apos;s a built-in API that can make lists look good? Heck, I&apos;d take this even if it was only available for English-speaking countries or English language-only applications, this is so useful.&lt;/p&gt;
&lt;p&gt;But wait! I&apos;ve got another incredibly useful constructor to introduce: the number formatter! 🤑&lt;/p&gt;
&lt;h3&gt;International number format 💰&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/js-intl-methods/make-it-rain.gif&quot; alt=&quot;Make it rain&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Make it rain, everybody.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Although the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat&quot;&gt;&lt;strong&gt;&lt;code&gt;Intl.NumberFormat&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; definition doesn&apos;t sound exciting at first, the implications are big. This object is a constructor for objects that enables language sensitive number formatting. And you know what that means? The formatting for international currencies is a breeze.&lt;/p&gt;
&lt;p&gt;In addition to &lt;code&gt;locales&lt;/code&gt; and &lt;code&gt;nu&lt;/code&gt; — the numbering system to be used, the &lt;code&gt;Intl.NumberFormat&lt;/code&gt; object can accept the following &lt;code&gt;options&lt;/code&gt; parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localeMatcher&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style&lt;/code&gt; — the formatting style to use. Possible values are &lt;code&gt;&quot;decimal&quot;&lt;/code&gt; for plain number formatting, &lt;code&gt;&quot;currency&quot;&lt;/code&gt; for currency formatting, and &lt;code&gt;&quot;percent&quot;&lt;/code&gt; for percent formatting; &lt;code&gt;&quot;decimal&quot;&lt;/code&gt; is the default style.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currency&lt;/code&gt; — the currency to use in currency formatting,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currencyDisplay&lt;/code&gt; — how to display the currency formatted. The options are &lt;code&gt;&quot;symbol&quot;&lt;/code&gt; to use a localized currency symbol such as €, &lt;code&gt;&quot;code&quot;&lt;/code&gt; to use the ISO currency code, or &lt;code&gt; &lt;/code&gt;to use a localized currency name such as &lt;code&gt;&quot;dollar&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useGrouping&lt;/code&gt; — Whether to use grouping separators, such as thousands separators or thousand/lakh/crore separators. Possible values are &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&apos;s a few more options around digits: &lt;code&gt;minimumIntegerDigits&lt;/code&gt;, &lt;code&gt;maximumSignificantDigits&lt;/code&gt;, but I think their usefulness is limited, so I&apos;ll skip defining them all here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intl.NumberFormat examples&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var number = 123456.789;

// currency formatting with euros in German
console.log(new Intl.NumberFormat(&apos;de-DE&apos;, { style: &apos;currency&apos;, currency: &apos;EUR&apos; }).format(number));
// expected output: &quot;123.456,79 €&quot;

// currency formatting in Japanese where the Japanese yen doesn&apos;t use a minor unit
console.log(new Intl.NumberFormat(&apos;ja-JP&apos;, { style: &apos;currency&apos;, currency: &apos;JPY&apos; }).format(number));
// expected output: &quot;￥123,457&quot;

// limiting an Indian currency format to three significant digits
console.log(new Intl.NumberFormat(&apos;en-IN&apos;, { maximumSignificantDigits: 3 }).format(number));
// expected output: &quot;1,23,000&quot;

// Arabic in most Arabic speaking countries uses real Arabic digits
console.log(new Intl.NumberFormat(&apos;ar-EG&apos;).format(number));
// expected output: ١٢٣٤٥٦٫٧٨٩

// India uses thousands/lakh/crore separators
console.log(new Intl.NumberFormat(&apos;en-IN&apos;).format(number));
// expected output: 1,23,456.789

// the nu extension key requests a numbering system, e.g. Chinese decimal
console.log(new Intl.NumberFormat(&apos;zh-Hans-CN-u-nu-hanidec&apos;).format(number));
// expected output: 一二三,四五六.七八九

// when requesting a language that may not be supported, such as
// Balinese, include a fallback language, in this case Indonesian
console.log(new Intl.NumberFormat([&apos;ban&apos;, &apos;id&apos;]).format(number));
// expected output: 123.456,789
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my mind, for an international company or website, this has got to be a huge, &lt;em&gt;huge&lt;/em&gt; selling point for the Internationalization API. Instead of hand-coding for all the varieties of currency differences that exist, we can rely on a single API to handle it for us — what a logic and time-saver!&lt;/p&gt;
&lt;p&gt;Ok, time for the last property I&apos;ll cover today: &lt;code&gt;Intl.PluralRules&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;International plural rules&lt;/h3&gt;
&lt;p&gt;When you think about rules for plurals in English, the rules are hard: &quot;one dog&quot; becomes &quot;two dogs&quot; but &quot;one goose&quot; becomes &quot;two geese&quot;, &quot;one&quot; becomes &quot;two&quot; but beyond &quot;two&quot; becomes &quot;a few&quot; or &quot;many&quot; or &quot;other&quot; when describing some vague, larger numbers of items, and so on and so forth— are you starting to see where I&apos;m going with this?&lt;/p&gt;
&lt;p&gt;Now imagine needing to know unwritten rules like this in more than one language...ugh. 😑&lt;/p&gt;
&lt;p&gt;Well, this is where the International Plural Rules becomes a life saver. The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules&quot;&gt;&lt;strong&gt;&lt;code&gt;Intl.PluralRules&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; object is a constructor for objects enabling plural sensitive formatting and plural language rules.&lt;/p&gt;
&lt;p&gt;This constructor accepts &lt;code&gt;locales&lt;/code&gt; (of course), and its &lt;code&gt;options&lt;/code&gt; object takes in the following parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;localeMatcher&lt;/code&gt; — The locale matching algorithm to use. Possible values are &lt;code&gt;&quot;lookup&quot;&lt;/code&gt; and &lt;code&gt;&quot;best fit&quot;&lt;/code&gt;; the default is &lt;code&gt;&quot;best fit&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt; — the type to use. Possible values are: &lt;code&gt;&quot;cardinal&quot;&lt;/code&gt; for cardinal numbers (referring to the quantity of things). This is the default value. Or &lt;code&gt;&quot;ordinal&quot;&lt;/code&gt; for ordinal number (referring to the ordering or ranking of things, e.g. &quot;1st&quot;, &quot;2nd&quot;, &quot;3rd&quot; in English).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Uses for Intl.PluralRules&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&apos;s a few different ways to use &lt;code&gt;Intl.PluralRules&lt;/code&gt; in your code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Basic usage&lt;/strong&gt; — In basic use without specifying a locale, a formatted string in the default locale and with default options is returned. This is useful to distinguish between singular and plural forms such as &quot;cat&quot; and &quot;cats&quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Locales usage&lt;/strong&gt; — When using &lt;code&gt;locales&lt;/code&gt;, the example code below shows some of the variations in localized plural rules. In order to get the format of the language used in the user interface of your application, make sure to specify that language (and possibly some fallback languages) using the locales argument.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Options usage&lt;/strong&gt; — The plural results can be customized using the &lt;code&gt;options&lt;/code&gt; argument, which has one property called type which you can set to &lt;code&gt;ordinal&lt;/code&gt;. This is useful to figure out the ordinal indicator, e.g. &quot;1st&quot;, &quot;2nd&quot;, &quot;3rd&quot;, &quot;4th&quot;, &quot;42nd&quot; and so forth.&lt;/p&gt;
&lt;p&gt;The code snippets below outline all the usages I just described.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intl.PluralRules examples&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// basic usage examples
var pr = new Intl.PluralRules();
// examples of plural rules if in US English locale

console.log(pr.select(0));
// expected output: &apos;other&apos;

console.log(pr.select(1)); 
// expected output: &apos;one&apos;

console.log(pr.select(2));
// expected output: &apos;other&apos;

// examples using `locale`
// for example: Arabic has different plural rules
console.log(new Intl.PluralRules(&apos;ar-EG&apos;).select(0));
// expected output: &apos;zero&apos;

console.log(new Intl.PluralRules(&apos;ar-EG&apos;).select(1)); 
// expected output: &apos;one&apos;

console.log(new Intl.PluralRules(&apos;ar-EG&apos;).select(2));
// expected output: &apos;two&apos;

console.log(new Intl.PluralRules(&apos;ar-EG&apos;).select(6));
// expected output: &apos;few&apos;

console.log(new Intl.PluralRules(&apos;ar-EG&apos;).select(18));
// expected output: &apos;many&apos;

// examples using `options`
var pr = new Intl.PluralRules(&apos;en-US&apos;, { type: &apos;ordinal&apos; });
// examples using US English and `options type` specification

console.log(pr.select(0));
// expected output: &apos;other&apos;

console.log(pr.select(1));
// expected output: &apos;one&apos;

console.log(pr.select(2));
// expected output: &apos;two&apos;

console.log(pr.select(3));
// expected output: &apos;few&apos;

console.log(pr.select(4));
// expected output: &apos;other&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty nice, huh? I&apos;ll admit, of all the &lt;code&gt;Intl&lt;/code&gt; methods, this is less widely applicable than some of the other methods included, but I&apos;m sure it will still have its moments where it&apos;s just the ticket.&lt;/p&gt;
&lt;p&gt;It is also worth noting that this method is still in &quot;Draft&quot; status, with the comment &quot;initial definition&quot; in MDN&apos;s docs, so I would hold off for a while longer before attempting to rely on it completely in production.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Translating websites and applications for use in different countries and languages is tough enough, but being able to correctly handle things like date time formats, currencies and lists of items with their many language-specific rules is a real challenge.&lt;/p&gt;
&lt;p&gt;The newest version of the ECMAScript Internationalization API aims to make some of these arduous tasks easier by letting its methods do the formatting for you, based on &lt;code&gt;locales&lt;/code&gt; and whatever other &lt;code&gt;options&lt;/code&gt; you might want to specify.&lt;/p&gt;
&lt;p&gt;For JavaScript developers working with international requirements, this stands to be a huge boon, and I for one, am looking forward to incorporating these new features into my own applications just for the total convenience these properties provide.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you see the value the ECMAScript Internationalization API can provide to your applications, and are able to incorporate some of the properties into your web apps in the future. Please share this with your friends if you found it helpful!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl&quot;&gt;ECMAScript Internationalization API, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat&quot;&gt;International Date Time Format, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat&quot;&gt;International Relative Time Format, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ListFormat&quot;&gt;International List Format, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat&quot;&gt;International Number Format, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules&quot;&gt;International Plural Rules, MDN Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>programming</category><category>internationalization</category></item><item><title>Viewport Units, the CSS You Didn&apos;t Know About But Should</title><link>https://www.paigeniedringhaus.com/blog/viewport-units-the-css-you-didnt-know-about-but-should/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/viewport-units-the-css-you-didnt-know-about-but-should/</guid><description>Because CSS done right is awesome</description><pubDate>Sun, 23 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import CodePen from &apos;../../src/components/CodePen.astro&apos;;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/css-viewport-units/css-is-awesome-hero.webp&quot; alt=&quot;CSS is awesome meme where it spills out of its container box&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Source: The whole Internet and every front end web developer at one time or other, let’s be real here.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;CSS can be both the greatest thing in the world and the most frustrating thing in the world for a web developer at exactly the same time.&lt;/p&gt;
&lt;p&gt;It is a joy when it works the way we envision it — it’s beautiful, it makes the site intuitive, accessible, possibly animated — just good in all the ways. But the effort, time and the pain of getting everything pixel perfect can be totally maddening to the point where we want to tear our hair out and the meme above is very, very real to us.&lt;/p&gt;
&lt;p&gt;To be honest, I fall more towards the side of “I like CSS, and all that it does for me, even when it takes &lt;em&gt;forever&lt;/em&gt; to get it there,” whereas some of my coworkers have less positive feelings about it. I don’t normally get to dive deep into things like animations, multi-browser support or some of the really bleeding-edge CSS stuff because the software I work on day-in and day-out is an internal application to help other employees at my company do their jobs better.&lt;/p&gt;
&lt;p&gt;But I still really enjoy (usually) when I pick up a front end feature that gives me the opportunity to dust off my CSS skills and implement some transitions or hover states, or learn some new cool CSS tricks I’ve not used before.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I want to share something I’ve been learning more about lately: CSS viewport units. They’re awesome for so many reasons.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;CSS Viewport units&lt;/h2&gt;
&lt;p&gt;Viewport units have been around in CSS for a few years now, but I don’t see them used all that often, and I think part of it is because people just aren’t that aware that they exist. And there’s so much to learn and do in CSS, I’m not terribly surprised that’s the case. I’m sure there’s a ton of CSS tricks I’m not aware of either.&lt;/p&gt;
&lt;p&gt;In case you haven’t heard of viewport units, let me give you a quick overview of what they are.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;They are truly responsive length units in the sense that their value changes every time the browser resizes. — &lt;a href=&quot;https://www.sitepoint.com/css-viewport-units-quick-start/&quot;&gt;CSS Viewport Units: A Quick Start&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If that doesn’t immediately make sense or sound incredibly useful to you right off the bat, bear with me, there’s some cool examples coming up.&lt;/p&gt;
&lt;p&gt;But first, let’s define viewport units in terms of their CSS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Viewport Height (vh)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This unit is based on the height of the viewport. A value of &lt;code&gt;20vh&lt;/code&gt; is equal to &lt;code&gt;20%&lt;/code&gt; of the viewport height.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Viewport Width (vw)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This unit is based on the width of the viewport. A value of &lt;code&gt;10vw&lt;/code&gt; is equal to &lt;code&gt;10%&lt;/code&gt; of the viewport width. If a browser window is 1200px wide, the viewport width will be 120px. Likewise, if a mobile view browser is 480px wide, the viewport width would be 48px.&lt;/p&gt;
&lt;p&gt;These next two are a bit more interesting than the standard &lt;code&gt;vh&lt;/code&gt; and &lt;code&gt;vw&lt;/code&gt;, but also not as commonly used either.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Viewport Minimum (vmin)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The viewport minimum is calculated as a percentage of the viewport width or height, &lt;em&gt;whichever is smaller at the time&lt;/em&gt;. &lt;code&gt;20vmin&lt;/code&gt; will resolve to &lt;code&gt;20%&lt;/code&gt; of the current viewport width in portrait orientations, and 20%of the viewport height on landscape orientations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Viewport Maximum (vmax)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For viewport maximum (like viewport minimum), it is based on a percentage of the viewport width or height, &lt;em&gt;whichever is larger at the time&lt;/em&gt;. &lt;code&gt;15vmax&lt;/code&gt; will resolve to &lt;code&gt;15%&lt;/code&gt; of the current viewport height in portrait orientations, and &lt;code&gt;15%&lt;/code&gt; of the viewport width on landscape orientations.&lt;/p&gt;
&lt;p&gt;Personally, I don’t find the last two as useful as the first, but that’s just me.&lt;/p&gt;
&lt;p&gt;Now, after making sure we’re all on the same page, let’s get to the interesting parts — the examples.&lt;/p&gt;
&lt;h3&gt;Benefits of using viewport units&lt;/h3&gt;
&lt;p&gt;At this point, you might be thinking to yourself, ok, that’s cool, but how does this differ or improve upon the percentages and media queries I use in my CSS today?&lt;/p&gt;
&lt;p&gt;I’m so glad you asked...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1: Child components can be larger than their parent components&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;CodePen url=&quot;https://codepen.io/paigen11/pen/OemmKV&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;If you look at the CodePen example above, you’ll see that traditionally, if a child div is using percentages to calculate its size, it bases those percentages off of its parent component.&lt;/p&gt;
&lt;p&gt;Using viewport units, however, makes it possible to make child components larger than the parent component — they base their size off of the size of the viewport instead of their parent component.&lt;/p&gt;
&lt;p&gt;Helpful? In certain situations, you betcha.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2: Background images can be responsive without media queries&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;CodePen url=&quot;https://codepen.io/paigen11/pen/pXPpoO&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;The example here shows the power of both viewport height and viewport width. If you look at the images and colors set as backgrounds, you’ll notice that when the browser resizes, the images (and text centered in them), resize right along with them because it’s using &lt;code&gt;vh&lt;/code&gt; and &lt;code&gt;vw&lt;/code&gt; to set the height, width and padding.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.fullscreen {
  width: 100vw; /* this will stretch the width of the viewport */
  height: 100vh; /* this will stretch the height of the viewport */
  color: white;
  padding: 40vmin 1rem;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No muss, no fuss, just perfectly centered, resizing backgrounds. Tell me that’s not awesome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3: Font Sizes can Scale with the Help of &lt;code&gt;calc()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;CodePen url=&quot;https://codepen.io/paigen11/pen/WqjMNB&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;Another really cool thing that can be done with &lt;code&gt;vw&lt;/code&gt; and &lt;code&gt;vh&lt;/code&gt; is with &lt;code&gt;calc()&lt;/code&gt;. By using &lt;code&gt;calc()&lt;/code&gt;, font-sizes and headers can responsively resize based purely on the viewport.&lt;/p&gt;
&lt;p&gt;In the example above, you’ll notice the &lt;code&gt;h1&lt;/code&gt; and the &lt;code&gt;p&lt;/code&gt; text &lt;code&gt;font-sizes&lt;/code&gt; automatically resize and grow accordingly with the help of &lt;code&gt;calc()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;h1 {
  padding: 10vmin 1rem;
  font-size: calc(32px + 1.5vw);
  background-color: #BF6FE5;
}
p {
  font-size: calc(16px + 0.5vw);
  margin: 0 0 10vmin 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the padding for the &lt;code&gt;h1&lt;/code&gt; tag also uses the &lt;code&gt;vmin&lt;/code&gt; tag in addition to the &lt;code&gt;1rem&lt;/code&gt; static padding, so regardless of whether the height or width of the browser is greater, it will always have some padding keeping it from running up against the edges of the viewport.&lt;/p&gt;
&lt;p&gt;I know these may seem like little things, but just imagine the CSS developers are saved from writing based on improvements like this.&lt;/p&gt;
&lt;p&gt;If you like these kinds of examples, I’d highly recommend the CSS articles at the bottom of this post to see more of the possibilities that can be achieved with CSS viewport units.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;CSS gives websites the ability to be unique, beautiful, useful and delightful, and it can sometimes make the engineers who use it want to quit their jobs.&lt;/p&gt;
&lt;p&gt;Ultimately though, it feels so rewarding to me when I get it right and users tell me how much better an application makes their jobs. CSS viewport units, though often overlooked in favor of flashier frameworks like flexbox and grid, have some super useful applications that can reduce the amount of code needed to make a site responsive and child elements independent of their parents in some ways&lt;/p&gt;
&lt;p&gt;It definitely has a place in my CSS arsenal, now that I have a better understanding of its usefulness.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you can find some ways to incorporate CSS viewport units into your own sites, and (hopefully) reduce the amount of CSS needed along the way.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sitepoint.com/css-viewport-units-quick-start/&quot;&gt;CSS Viewport Units: A Quick Start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/fun-viewport-units/&quot;&gt;Fun with Viewport Units&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/simple-little-use-case-vmin/&quot;&gt;Simple Little Use Case for &lt;code&gt;vmin&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>css</category><category>programming</category></item><item><title>Github Templates: The Smarter Way to Formalize PRs Among Dev Teams</title><link>https://www.paigeniedringhaus.com/blog/github-templates-the-smarter-way-to-formalize-prs-among-dev-teams/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/github-templates-the-smarter-way-to-formalize-prs-among-dev-teams/</guid><description>No more confusing pull requests.</description><pubDate>Tue, 11 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-pr-templates/all-for-one-hero.webp&quot; alt=&quot;Fist bump of a team between all their laptops&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Today I’m going to give you a better, easier, more efficient way to keep pull requests not only uniform but also completely customized to your dev team.&lt;/p&gt;
&lt;h3&gt;Some common issues of a dev team&lt;/h3&gt;
&lt;p&gt;If you’ve ever worked with GitHub as a software developer, either solo or as part of a team, you should be familiar with the issues I’m about to show you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Leaving less than stellar commit messages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First, the nonsensical commit messages. These are usually sent multiple times because we, as developers, are lazy and will keep pushing changes to GitHub with the same note even though the code update has nothing whatsoever to do with that message.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-pr-templates/commit-messages.webp&quot; alt=&quot;Nonsense commit messages that are all the same&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is a typical bunch of commit messages, I found in one shared repo my team owns.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt;: If you want to see some laugh out loud commit messages, I highly recommend the website &lt;a href=&quot;http://whatthecommit.com/&quot;&gt;&lt;em&gt;What the Commit&lt;/em&gt;&lt;/a&gt;. Just keep refreshing the page for a constant stream of hilarious (and accurate) commit messages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Completely puzzling pull requests&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You’ve seen (and/or submitted) a pull request like this one to a repo — don’t try to deny it. Names and discerning details have been omitted to protect the privacy of the guilty.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-pr-templates/bad-pr.webp&quot; alt=&quot;Nonsense PR full of commit messages that tell no story&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Excellent. This definitely tells me just what I need to know.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Yes, this is an actual pull request on GitHub, titled only as “catching up” with a ton of commit messages that give very little context and no other details to anyone reviewing this any idea as to what was going on here.&lt;/p&gt;
&lt;p&gt;At this point, you may be thinking to yourself that this does, in fact, resemble things you’ve seen (or submitted) before and you might not see a huge problem with it.&lt;/p&gt;
&lt;p&gt;If you’re a solo developer working on your own projects, always aware of everything in the code base, I might be inclined to agree with you. However, if you’re on a team with 10 or 20 other developers and building an application used by hundreds or thousands of people, where other developers have to look at the changes you made, determine if the code and logic is sound and it won’t break anything in your &lt;code&gt;main&lt;/code&gt; code branch, this is a big, big problem.&lt;/p&gt;
&lt;h3&gt;Temporary solutions - don&apos;t both using these options ⚠️&lt;/h3&gt;
&lt;p&gt;To solve these problems there are a few different solutions that my development team tried in the past:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 1: A completely manual process&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A loose collection of requirements we had to manually add to every new pull request. Things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Links to the feature story we were working on in our backlog,&lt;/li&gt;
&lt;li&gt;Links to the automated Jenkins branch where our feature branch was built and deployed into QA,&lt;/li&gt;
&lt;li&gt;Links to the feature branch for testing,&lt;/li&gt;
&lt;li&gt;A code coverage report,&lt;/li&gt;
&lt;li&gt;Links to related PRs in other repos, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This worked OK, except people commonly forgot (or just didn’t care to add) one or more of these links, and we didn’t have a formalized system for new devs joining the team to know how to format their PRs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2: A template that needed to be copy/pasted into every PR, every time&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our second attempt was slightly less manual: A pull request template that my team kept in a Slack &lt;code&gt;.txt&lt;/code&gt; file pinned in one of our development channels. Here’s what that looked like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## Story
Jira, Pivotal Tracker, (link to where the story you worked on lives)

## PR Branch
URL to the automated branch build for feature testing

## Code Coverage
URL to the automated code coverage report run during the automated build process

## e2e
URL to the automated end to end tests run against the feature branch

## UX Approved
yes / no

## Newman
yes / no

## Related PR&apos;s
TBD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But once again, devs had to go find the template, copy the markdown formatting, and paste it into each and every pull request opened up and fill out the contents of it.&lt;/p&gt;
&lt;p&gt;This worked better because the template, at least, ensured there was less chance of forgetting something, but it still wasn’t foolproof. Oftentimes (because devs are people and people are lazy, myself included), we’d just go find an old closed PR, copy its contents and paste it into the new PR we were working on. That was OK until someone forgot to update the story link or the end to end test link... you see the issue.&lt;/p&gt;
&lt;p&gt;But that was the best solution anyone had until our team had some fresh developers brought on board.&lt;/p&gt;
&lt;p&gt;As I was showing one of our new devs the PR template we used (by copying it from out of another closed pull request), he asked why we didn’t just use &lt;a href=&quot;https://help.github.com/en/articles/creating-a-pull-request-template-for-your-repository&quot;&gt;&lt;strong&gt;GitHub Templates&lt;/strong&gt;&lt;/a&gt;, and I said, “because none of us had ever heard of them.” Then, he showed me something really cool and very easy to do.&lt;/p&gt;
&lt;h3&gt;A better solution - what we&apos;re using now (and you should too) ⭐️&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Option 3: GitHub Templates - the automated way to do PRs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GitHub templates are an awesome invention from GitHub for both pull requests and issues. Since PRs are what concerned my team, I found the GitHub docs to learn more.&lt;/p&gt;
&lt;p&gt;Here&apos;s what I learned from the docs:&lt;/p&gt;
&lt;p&gt;&quot;When you add a pull request template to your repository, project contributors will automatically see the template’s contents in the pull request body.&quot; — &lt;a href=&quot;https://help.github.com/en/articles/creating-a-pull-request-template-for-your-repository&quot;&gt;GitHub Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was just the sort of thing my team needed. It was a way to ensure every pull request was uniform without our devs having to think about it. Perfect.&lt;/p&gt;
&lt;p&gt;Turns out, it was incredibly easy to set up as well.&lt;/p&gt;
&lt;h4&gt;Setting up GitHub Templates in a project&lt;/h4&gt;
&lt;p&gt;Although setting up a PR template is very straightforward, I’m happy to lay out the steps here for convenience sake.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Add a &lt;code&gt;.github/&lt;/code&gt; folder into the root of your project&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The docs say you can either add the PR template in the root directory itself or in a folder named &lt;code&gt;docs/&lt;/code&gt; or &lt;code&gt;.github/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since we wanted to ignore the PR folder the majority of the time we were doing development, I chose to create the template inside of the hidden &lt;code&gt;.github/&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-pr-templates/github-folder.webp&quot; alt=&quot;GitHub folder inside of project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s a shot of my repo with the hidden &lt;code&gt;.github/&lt;/code&gt; folder at the root of the project.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Add your &lt;code&gt;pull_request_template.md&lt;/code&gt; markdown file inside the folder&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In order for Github to automatically pick up the formatting from the markdown file for PR templates, you must name the file &lt;code&gt;pull_request_template.md&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Below is an example of the one my team uses:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# &amp;lt;Feature Title&amp;gt;

Tracker ID: **_#ADD LINK TO PIVOTAL STORY_**

Unit tests completed?: (Y/N)

PR Branch
**_#ADD LINK TO PR BRANCH_**

Code Coverage &amp;amp; Build Info
**_#ADD LINK TO JENKINS CONSOLE_**

E2E Approved
**_#ADD LINK TO PASSING E2E TESTS_**

Windows Testing
**_#HAS WINDOWS BEEN TESTED?_**

Related PR
**_#ADD ANY RELATED PULL REQUESTS_**

UX Approved
**_#ADD UX APPROVAL IF NEEDED_**
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Add these files to your &lt;code&gt;main&lt;/code&gt; branch and prepare for smooth sailing in all PRs going forward&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here’s a screenshot of a &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;repo&lt;/a&gt; I have with the pull request template added to it, and an example pull request I raised.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/github-pr-templates/pr-template.webp&quot; alt=&quot;Screenshot of what a new PR in GH looks like when there&apos;s a GitHub PR template in the project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s my automated PR automatically generated when I open a new PR in this project.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;It really is that simple to have a standardized PR template included in any repo with very little effort.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When you’re working with a team of developers on a mission-critical product, pull requests are a necessary evil, but they can be less painful with the help of GitHub’s &lt;code&gt;pull_request_templates&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The benefits of the formatted PR templates are many, but some of the highlights in my mind are how flexible they are; no matter what your team deems necessary to review and accept, a pull request can be easily included and implemented in any repo. That’s the kind of ease developers need for required formalities like PRs.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this helps you better manage your own team’s pull requests in an easy and more orderly fashion.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Example &lt;a href=&quot;https://gist.github.com/paigen11/0df23cdf168057dd5e8cf3c61d5beb0f&quot;&gt;original, manual Pull Request Template gist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;Pull Request Template in repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Example &lt;a href=&quot;https://gist.github.com/paigen11/9ef7fd2b08de2b8a9976615c633ada02&quot;&gt;new, automated Pull Request Template gist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://help.github.com/en/articles/creating-a-pull-request-template-for-your-repository&quot;&gt;Github Templates docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>github</category><category>git</category><category>devops</category></item><item><title>Use ES6 To Destructure Deeply Nested Objects in JavaScript</title><link>https://www.paigeniedringhaus.com/blog/use-es6-to-destructure-deeply-nested-objects-in-javascript/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/use-es6-to-destructure-deeply-nested-objects-in-javascript/</guid><description>Because Airbnb&apos;s ESLint is merciless in React.</description><pubDate>Mon, 27 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/destructure-deep-objs/sparta-hero.webp&quot; alt=&quot;Sparta meme: &amp;quot;This is madness? This is ES6 destructuring&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In case this is your first time reading one of my posts, thanks for taking the time, I am a full stack software developer with a fondness for JavaScript, and the React framework, in particular.&lt;/p&gt;
&lt;p&gt;For just over a year, in my free time after work, I’ve been teaching myself React with the help of online documentation, articles, tutorials and building (and breaking) side projects.&lt;/p&gt;
&lt;p&gt;With all these sources of knowledge and inspiration, I managed to build a &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;user registration application&lt;/a&gt; that I was pretty proud of. It had a React front end, an Express/Node.js server back end, a MySQL database, it used &lt;a href=&quot;./implementing-json-web-tokens-passport-js-in-a-react-app&quot;&gt;Passport.js and JSON Web Tokens&lt;/a&gt; to handle authentication, the &lt;a href=&quot;./sequelize-like-mongoose-but-for-sql&quot;&gt;Sequelize&lt;/a&gt; ORM to perform CRUD operations on the database, a &lt;a href=&quot;./password-reset-emails-in-your-react-app-made-easy-with-nodemailer&quot;&gt;password reset feature&lt;/a&gt; through Nodemailer, &lt;a href=&quot;./setting-up-swagger-to-api-test-in-a-java-script-application&quot;&gt;Swagger endpoint&lt;/a&gt; testing on the REST API endpoints, a &lt;a href=&quot;./setting-up-swagger-to-api-test-in-a-java-script-application&quot;&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/a&gt; file to spin up all three pieces of the application simultaneously in a virtualized container environment, etc., etc. Have you had enough technology buzzwords thrown at you, yet? 😫&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/destructure-deep-objs/anchor-man-big-deal.gif&quot; alt=&quot;Anchor Man: I&apos;m kind of a big deal&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Yes, I threw out all those buzzwords, no, I‘m really not that big of a deal. 😉&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Please understand, this project was by no means achieved in a day, it started as a very basic idea and mushroomed in scope as I made forward progress and got more ambitious to see how far I could push it. But by the time I’d gotten to that point, I was feeling pretty proud of myself. I’d made a cool, useful little side project — completely built in JavaScript.&lt;/p&gt;
&lt;p&gt;Then I &lt;a href=&quot;./how-eslint-makes-me-a-better-react-developer&quot;&gt;introduced Airbnb’s ESLint&lt;/a&gt; configuration into the mix, and was humbled as the &lt;a href=&quot;./keep-code-consistent-across-developers-the-easy-way-with-prettier-es-lint&quot;&gt;VS Code browser&lt;/a&gt; lit up left and right with red squiggles of disapproval. 😞 Instead of quitting though, I persevered in learning the best practices of modern JavaScript/ES6 development (according to ESLint and Airbnb), fixed the majority of my errors and became a better developer along the way.&lt;/p&gt;
&lt;p&gt;There was one error, however, which eluded me. The deeply nested, destructured object. How, pray tell, do you destructure a &lt;code&gt;prop&lt;/code&gt; object that’s several levels deep in JavaScript to ESLint’s satisfaction?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I will show you how to use ES6 to destructure nested objects, my friends, AND what’s more, prevent the dreaded undefined error if an object is missing that property entirely.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s get to it.&lt;/p&gt;
&lt;h2&gt;The issue: ES6 object destructuring &amp;amp; deeply nested objects&lt;/h2&gt;
&lt;p&gt;To give you some insight into what I’m describing, let me back up just a minute and go over what object destructuring in JavaScript is, and why it’s a little daunting once your objects get complex.&lt;/p&gt;
&lt;h3&gt;Object Destructuring in a Nutshell&lt;/h3&gt;
&lt;p&gt;As per usual, MDN’s documentation sums up JavaScript destructuring nicely:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;destructuring assignment&lt;/strong&gt; syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. — &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;MDN Docs, Destructuring Assignment&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a feature introduced in ES6, and what it means, in practice, is that your code can go from looking like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plain old JavaScript object&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = { 
  a : &quot;foo&quot;, 
  b : false, 
  c : 11 
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Traditional JS object property access example (dot notation and bracket notation)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the object’s properties being accessed through dot notation or bracket notation like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(myObject.a); // &quot;foo&quot;
console.log(myObject[b]); // false
console.log(myObject.c); // 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ES6 object property access example (destructured)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To being accessed like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { a, b, c } = myObject;
console.log(a); // &quot;foo&quot;
console.log(b); // false
console.log(c); // 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s pretty cool, right? It’s shorter, it’s much more concise to read, and it makes pretty good sense logically.&lt;/p&gt;
&lt;p&gt;There’s a lot more cool things that can be done with both arrays and object and destructuring, and I’d recommend you read the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;docs&lt;/a&gt; for more examples.&lt;/p&gt;
&lt;p&gt;Ok, so now that ES6’s destructuring has been defined, let’s look at my issue, which seemed a lot less straightforward with how to approach it (at least, at first pass, to me).&lt;/p&gt;
&lt;h2&gt;A deeply nested object&lt;/h2&gt;
&lt;p&gt;Below is an example of the object I was working with in my React application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;this.props.match.params.username; 
// what a mouthful! no one wants to write this anymore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was my nested object, written in traditional JavaScript dot notation syntax.&lt;/p&gt;
&lt;p&gt;To give a little more context around it, this object was being taken from the URL string and passed into the HTTP call from the browser’s client to the server side to identify (and validate) the username in the database. This syntax is courtesy of the &lt;a href=&quot;https://www.npmjs.com/package/react-router-dom&quot;&gt;&lt;code&gt;react-router-dom&lt;/code&gt; npm package&lt;/a&gt; and React’s &lt;code&gt;props&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Regardless of where the object’s syntax and structure originated from, it’s complicated. It’s technically nested 4+ layers deep in this object to get to the useful piece of information, the &lt;code&gt;username&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And unlike, &lt;code&gt;const {a} = myObject;&lt;/code&gt;, trying to figure out how to dive several levels deep into an object was a little befuddling.&lt;/p&gt;
&lt;h3&gt;The ESLint errors: merciless as always&lt;/h3&gt;
&lt;p&gt;But did ESLint care?&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/destructure-deep-objs/honey-badger.webp&quot; alt=&quot;Honey badger meme: ESLint don&apos;t care&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I never imagined I’d have reason to use a honey badger meme in a blog post, and yet, here it is.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In the immortal words of honey badger: “nope”.&lt;/p&gt;
&lt;p&gt;As soon as ESLint saw this type of syntax in my code, sirens went off and the ESLint error showed up: &lt;code&gt;Must use destructuring props assignment eslint(react/destructuring-assignment)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/destructure-deep-objs/eslint-destructuring-error.webp&quot; alt=&quot;ESLint destructuring props error message in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Thanks for being so helpful, ESLint, this is an extremely useful warning message. 🙄&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I visited the ESLint documentation, made a few half-hearted attempts to figure out how to pull this convoluted mess of objects apart, but eventually gave up and resorted to the old &lt;code&gt;* eslint-disable react/destructuring-assignment */&lt;/code&gt; import at the top of my files instead of fixing it properly. And I moved on with my life. 😬&lt;/p&gt;
&lt;p&gt;Then, a while later, another developer pointed me towards &lt;a href=&quot;https://medium.com/@pyrolistical/destructuring-nested-objects-9dabdd01a3b&quot;&gt;an article&lt;/a&gt; that showed me the light, while we were trying to decide how best to guard our code against throwing errors if environment variables weren’t specified during local development.&lt;/p&gt;
&lt;p&gt;After reading it, things made much more sense. Here is what I learned.&lt;/p&gt;
&lt;h3&gt;How to fix the ESLint &quot;Destructuring Props&quot; error&lt;/h3&gt;
&lt;p&gt;Apparently, I was trying to make the solve for object destructuring more complicated than it needed to be. Here’s a breakdown (or build up) to my object, with destructuring along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One JavaScript object&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = {
  props: &quot;Hello world&quot;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The destructured version becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { 
  props 
} = myObject; 

console.log(props); // prints: &quot;Hello world&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right, that seems logical, access the property’s value in the object just by wrapping that property in curly braces.&lt;/p&gt;
&lt;p&gt;Next, up...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One JS object within &lt;em&gt;another&lt;/em&gt; object&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For an object inside another object, like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = { 
  props: { 
    match : &quot;Some value&quot; 
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The destructured version becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { 
  props : { 
    match 
  },
} = myObject; 

console.log(match); // prints: &quot;Some value&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All right, so to access property values two levels deep, first wrap the original property inside the top level object (in this case &lt;code&gt;props&lt;/code&gt;) in curly braces, then, inside that object, wrap the inner object, &lt;code&gt;match&lt;/code&gt;, in another set of curly braces.&lt;/p&gt;
&lt;p&gt;Ok, following so far...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One JS object within &lt;em&gt;two more&lt;/em&gt; objects&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a slightly more complex object, like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = { 
  props: { 
    match: {
      params: &quot;A new value&quot;
    } 
  } 
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new destructured version becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { 
  props: { 
    match: { 
      params 
    }, 
  }, 
} = myObject; 

console.log(params); // prints: &quot;A new value&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once more, stepping through each tier: &lt;code&gt;props&lt;/code&gt; gets wrapped in the first set of curly braces, match, the object contained within &lt;code&gt;props&lt;/code&gt; is wrapped in the second set of curly braces, and finally, the third object &lt;code&gt;params&lt;/code&gt; (with the value I want to access) is wrapped in the third set of curly braces.&lt;/p&gt;
&lt;p&gt;The pattern is starting to make sense when deconstructed object by object.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One JS object within &lt;em&gt;three. More. Objects&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So, for an even &lt;em&gt;more&lt;/em&gt; complex object, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = { 
  props: { 
    match: { 
      params: { 
        username: &quot;Paige&quot; 
      } 
    } 
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new destructured version becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { 
  props: {
    match: {
      params: { 
        username 
      }, 
    }, 
  }, 
} = myObject; 

console.log(username); // prints: &quot;Paige&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same rules and pattern as above still apply, just keep going one level further with the curly braces to reach the object properties you want to read.&lt;/p&gt;
&lt;p&gt;To fix the ESLint error my React application was throwing: &lt;code&gt;Must use destructuring props assignment eslint(react/destructuring-assignment)&lt;/code&gt;, this is the solution I came up with.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const {
  match: {
    params: { username },
  },
} = this.props;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since ESLint only wanted object destructuring from the &lt;code&gt;props&lt;/code&gt; object level and onwards, I was able to make my object slightly smaller than a truly, entirely destructured object. Access the &lt;code&gt;match&lt;/code&gt; object inside &lt;code&gt;this.props&lt;/code&gt;, access the params object inside match, and finally, access the value attached to &lt;code&gt;username&lt;/code&gt; for the info I was seeking.&lt;/p&gt;
&lt;p&gt;Broken down into steps like that, everything started making a lot more sense.&lt;/p&gt;
&lt;p&gt;Nice! But then I thought of an edge case, what if, for some reason, one of these properties was missing? Ah, there’s a way to safeguard against &lt;code&gt;undefined&lt;/code&gt; errors too within destructured objects.&lt;/p&gt;
&lt;h3&gt;How to prevent undefined errors for missing properties: default values&lt;/h3&gt;
&lt;p&gt;I can’t tell you the number of times I’ve thrown errors in local development because a property on an object I was trying to access was &lt;code&gt;undefined&lt;/code&gt;, meaning the property (and its value) didn’t exist on that object. Not as an empty string, nor as an empty array or even a 0. It just flat out didn’t exist.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TypeError: Cannot read property ‘params’ of undefined.&lt;/code&gt; It’s so annoying — especially when it causes React to throw a giant error in the browser. 😠&lt;/p&gt;
&lt;p&gt;But there’s a way around this with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#default_value&quot;&gt;&lt;strong&gt;object default values&lt;/strong&gt;&lt;/a&gt;. Another nice feature of ES6, in the case that the value unpacked from the object is &lt;code&gt;undefined&lt;/code&gt;, is that that variable can be assigned a default value.&lt;/p&gt;
&lt;p&gt;That’s a whole other blog post, but what this means for me, in the case of a missing property on a destructured object, is that instead of throwing a &lt;code&gt;TypeError&lt;/code&gt;, I could provide a fallback value in the form of a string or other value, and I’d receive that value, which I could specifically look for and then move on from.&lt;/p&gt;
&lt;p&gt;Here’s an example with an object with just one property.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plain old JavaScript object&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = { 
  props: &quot;I only have props, nothing else&quot;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the destructured version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { props } = myObject; 

console.log(props); // prints: &quot;I only have props, nothing else&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I tried to access an undefined property within a destructured object, normally:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES6 destructured object with no default props&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { 
  props: {
    match 
  } 
} = myObject 

console.log(match); // throws error: TypeError: Cannot read property &quot;match&quot; of undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But, if I set a default value to fall back on if that property doesn’t exist, within that destructured object, like so:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES6 destructured object with default props&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { 
  props: { match } = { match: &quot;No match&quot;}
} = myObject
console.log(match); // prints: &quot;No match&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with an empty object, an empty array, a default string or integer, or a host of other things besides the dreaded &lt;code&gt;undefined&lt;/code&gt; error, I can set up error handling in the DOM to display some sort of message to the user so they know what’s going on and how to fix the situation —a much better experience than an obvious React error screen with a cryptic message that something’s gone wrong.&lt;/p&gt;
&lt;p&gt;So, here’s a rewritten version of the destructured object my app needed with a username from the URL string. If the username’s not present in the URL, this object structure will default to the string of &lt;code&gt;&quot;no match&quot;&lt;/code&gt;, which I can then check for, and display a nicer error message to help the user get back to a working place in the application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const {
  match: { params: { username } = { username: &quot;no match&quot; } },
} = this.props;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Default values are one, nifty way to guard against &lt;code&gt;undefined&lt;/code&gt; errors in your destructured objects.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;ES6 is a great improvement to the JavaScript syntax, and Airbnb’s ESLint configuration is an excellent linter to identify code where the latest and greatest in ES6 could be used but hasn’t been.&lt;/p&gt;
&lt;p&gt;My biggest complaint is that sometimes it isn’t helpful enough in explaining just how to fix the errors it finds. Luckily, I found a resource to better explain how to destructure more deeply nested objects, and even how to set default values to prevent &lt;code&gt;undefined&lt;/code&gt; errors from being thrown in my React applications.&lt;/p&gt;
&lt;p&gt;Readability, clean, concise code, and error prevention with default values to fall back to, what more could one ask for? I’m a fan of object destructuring, especially now that I know how to handle all kinds of different scenarios with it.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this helps you better understand the power of ES6 object destructuring and how to use it in your own JavaScript applications. Please share this with your friends if you found it helpful!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;MERN, User Registration Github repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN Documentation &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring&quot;&gt;object destructuring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-router-dom&quot;&gt;react-router-dom, npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN Documentation, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#default_value&quot;&gt;object default values&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category><category>eslint</category><category>react</category></item><item><title>JavaScript&apos;s Async / Await versus Promises: The Great Debate</title><link>https://www.paigeniedringhaus.com/blog/javascripts-async-await-versus-promise-the-great-debate/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/javascripts-async-await-versus-promise-the-great-debate/</guid><description>Prepare yourselves, you&apos;re stepping into a minefield</description><pubDate>Sun, 12 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/async-await/office-space-refactor-meme.webp&quot; alt=&quot;Office Space meme about refactoring all the JavaScript over the weekend&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;The spark that ignited the firestorm&lt;/h2&gt;
&lt;p&gt;One day, just a few weeks ago at work, I was minding my own business, writing some React code, submitting pull requests, and another developer on my team, in essence, lobbed a grenade at our codebase.&lt;/p&gt;
&lt;p&gt;He asked a seemingly benign question about why we were continuing to use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;strong&gt;promises&lt;/strong&gt;&lt;/a&gt; in JavaScript versus the newer ECMAScript 17 version, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;&lt;strong&gt;async / await&lt;/strong&gt;&lt;/a&gt;. 🚨 It seemed innocent enough, at first glance.&lt;/p&gt;
&lt;p&gt;And let me tell you, normally, I’m all for using the new hotness in JavaScript (especially when it’s built into the language and &lt;a href=&quot;https://caniuse.com/#search=async&quot;&gt;supported&lt;/a&gt; by most modern browsers — looking at you for continued non-compliance, Internet Explorer), but even though I’ve heard the about the greatness of async / await, I hadn’t really used it up to that point.&lt;/p&gt;
&lt;p&gt;I didn’t really see any benefits of async / await that outweighed using promises — they both ended up accomplishing the same thing: handling asynchronous data calls in a performant, consistent manner.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/async-await/promises.webp&quot; alt=&quot;Toy Story meme where Buzz describes Space to Woody, except promises&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;All promises, all the time.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I like promises, I’m comfortable with the syntax of &lt;code&gt;.then()&lt;/code&gt;, with the error handling of &lt;code&gt;.catch()&lt;/code&gt;, with all of it, and switching required rewriting a lot of asynchronous calls our application currently makes. Before I uprooted all the hard work the team had written in traditional promise form, I wanted to find some reasoning beyond “it’s ES7, and it’s newer” to make the jump to async / await.&lt;/p&gt;
&lt;p&gt;And so, I set off to do some learning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I’ll compare the benefits (and personal preferences) of choosing promises or async / await for your asynchronous data needs in your JavaScript application.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;A short history of JavaScript&apos;s asynchronous data handling (or lack thereof)&lt;/h2&gt;
&lt;p&gt;Now before I go into detail about promises and async / await, I want to backtrack to a darker time in JavaScript, when asynchronous data fetching was more of a problem and the lesser solution was known as &lt;a href=&quot;https://javascript.info/callbacks&quot;&gt;callbacks&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;AJAX &amp;amp; callbacks&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3schools.com/php/php_ajax_intro.asp&quot;&gt;AJAX&lt;/a&gt;, which stands for Asynchronous JavaScript And XML and callbacks were an OG way of handling asynchronous calls in JavaScript. What it boils down to, is when one function is meant to be executed &lt;em&gt;after&lt;/em&gt; another function has finished executing — hence the name &quot;call back&quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Callbacks in a nutshell&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first function normally returns data the second function needs to perform some sort of operation on, and unlike multi threaded languages like Java, the single threaded &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop&quot;&gt;JavaScript event loop&lt;/a&gt; will push that first function to the call stack and execute it, pop that function call off the call stack once it’s completed it’s request, and continue running, pushing other operations that were waiting in the queue to the call stack in the meantime (which keeps the UI from seeming as if it’s frozen to the user).&lt;/p&gt;
&lt;p&gt;Then, when the response from the other server comes back (the asynchronous data) it’s added to the queue, the event loop will eventually push it to the call stack when it sees the stack is empty, and the call stack will execute that response as the callback function.&lt;/p&gt;
&lt;p&gt;This article isn’t about callbacks though, so I won’t go into too much more detail, but here’s an example of a what a JavaScript event with a callback function looks like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional JavaScript callback example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// the original function to call
function orderFood(food, callback) {
  alert(`Ordering my ${food} at the counter.`);
  callback();
}
// the callback once the order&apos;s up
function alertFoodReady(){
  alert(`Order&apos;s ready for pickup`);
}
// calling the function and adding the callback as the second 
// parameter
orderFood(&apos;burger&apos;, alertFoodReady);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a pretty simple example, and to be fair, it’s only showing the &quot;happy path&quot; — the path when the callback works and the food’s prepared and ready to be picked up.&lt;/p&gt;
&lt;p&gt;What’s not covered here is the error handling, nor is it an example of what can happen when you have many, many asynchronous dependencies nested inside one another. This is fondly known among JavaScript developers as “Callback Hell” or “The Pyramid of Doom”.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Callback Hell&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Below is an example of what Callback Hell looks like. This is a nightmare, don’t try to deny it. This happens when multiple functions need data from other functions to do their jobs.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/async-await/callback-hell.webp&quot; alt=&quot;Callback Hell code example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A perfect example of callback hell: a callback, inside a callback, inside another callback for eternity.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If you’d like to error handle that or even try to add some new functionality in the middle of that mess, be my guest.&lt;/p&gt;
&lt;p&gt;I, however, won’t have anything to do with it, so let’s agree that AJAX and callbacks were once a way to handle asynchronous data, but they are no longer the de facto way. There’s much better solutions that have come about that I’ll show you next. Let’s move on to promises.&lt;/p&gt;
&lt;h2&gt;Promises, promises&lt;/h2&gt;
&lt;p&gt;Mozilla does an excellent job of defining promises, so I’ll use their definition as the first introduction to what a promise is.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt; is an object representing the eventual completion or failure of an asynchronous operation…Essentially, a promise is a returned object to which you attach callbacks, instead of passing callbacks into a function. — &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&quot;&gt;Mozilla Docs, Using promises&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here’s another example of an asynchronous callback function called &lt;code&gt;createAudioFileAsync()&lt;/code&gt;. It takes in three parameters: &lt;code&gt;audioSettings&lt;/code&gt;, a &lt;code&gt;successCallback&lt;/code&gt;, and a &lt;code&gt;failureCallback&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional JavaScript callback example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function successCallback(result) {
  console.log(&quot;Audio file ready at URL: &quot; + result);
}

function failureCallback(error) {
  console.log(&quot;Error generating audio file: &quot; + error);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a lot of functions and code for just one asynchronous data call.&lt;/p&gt;
&lt;p&gt;Here’s the shorthand for that same function when it’s transformed using promises.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JavaScript promise example with callbacks&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;createAudioFileAsync(audioSettings)
  .then(successCallback, failureCallback);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Does that look nicer to you? It looks nicer to me.&lt;/p&gt;
&lt;p&gt;But wait, there’s more. Instead of the success and failure callbacks both inside the &lt;code&gt;.then()&lt;/code&gt;, it can be changed to:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modern day JavaScript promise example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;createAudioFileAsync(audioSettings)
  .then(successCallback)
  .catch(failureCallback);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And even this can be modernized one more time, by swapping the original &lt;code&gt;successCallback()&lt;/code&gt; and &lt;code&gt;failureCallback()&lt;/code&gt; functions for ES6 arrow functions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES6 arrow function promise example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;createAudioFileAsync(audioSettings)
  .then(result =&amp;gt; console.log(`Audio file ready at URL: ${result}`))
  .catch(error =&amp;gt; console.log(`Error generating audio file: ${error}`));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This may seem like a minor improvement right now, but once you start chaining promises together or waiting for multiple promises to resolve before moving forward, having one single &lt;code&gt;.catch()&lt;/code&gt; block at the end to handle anything that goes wrong within, is pretty handy. Read on and I’ll show you.&lt;/p&gt;
&lt;h3&gt;Pros of promises over callbacks&lt;/h3&gt;
&lt;p&gt;In addition to a cleaner syntax, promises offer advantages over callbacks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Callbacks added with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then&quot;&gt;&lt;code&gt;.then()&lt;/code&gt;&lt;/a&gt; even &lt;em&gt;after&lt;/em&gt; the success or failure of the asynchronous operation, will be called, as above.&lt;/li&gt;
&lt;li&gt;Multiple callbacks may be added by calling &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then&quot;&gt;&lt;code&gt;.then()&lt;/code&gt;&lt;/a&gt; several times. Each callback is executed one after another, in the order in which they were inserted (this is the chaining I mentioned earlier).&lt;/li&gt;
&lt;li&gt;It’s possible to chain events together &lt;em&gt;after&lt;/em&gt; a failure, i.e. a &lt;code&gt;.catch()&lt;/code&gt;, which is useful to accomplish new actions even after an action failed in the chain.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all&quot;&gt;&lt;code&gt;Promise.all()&lt;/code&gt;&lt;/a&gt; returns a single &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt; that resolves when all of the promises passed as an iterable have resolved or when the iterable contains no promises. Callbacks can’t do that.&lt;/li&gt;
&lt;li&gt;Promises solve a fundamental flaw with the callback pyramid of doom, by catching all errors, even thrown exceptions and programming errors. This is essential for functional composition of asynchronous operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To back up a moment, a common need is to execute two or more asynchronous operations back to back, where each subsequent operation starts when the previous operation succeeds, with the result from the previous step. This can be accomplished with a &lt;a href=&quot;https://javascript.info/promise-chaining&quot;&gt;promise chain&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the olden days, we entered Callback Hell when callbacks depended on each other for information. See below (note also, the multiple &lt;code&gt;failureCallbacks&lt;/code&gt; that had to be added for each callback).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Traditional, nested callback chain example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log(&apos;Got the final result: &apos; + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the introduction of the promise chain, that &quot;pyramid of doom&quot;, became what you see below (see the improvement of just one &lt;code&gt;failureCallback&lt;/code&gt; instance now at the very end).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;New promise chain example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;doSomething()
.then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log(&apos;Got the final result: &apos; + finalResult);
})
.catch(failureCallback);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with the advent of ES6 arrow functions, that code becomes even more compact in the next example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES6 arrow function promise chain example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;doSomething()
.then(result =&amp;gt; doSomethingElse(result))
.then(newResult =&amp;gt; doThirdThing(newResult))
.then(finalResult =&amp;gt; {
  console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not bad, huh?&lt;/p&gt;
&lt;p&gt;Note that with arrow functions, the &lt;code&gt;return&lt;/code&gt; statement is unnecessary to pass on the result, instead the result is returned via &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;implicit returns&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;Likewise, sometimes you need two or more unconnected promises to all resolve before moving on, which is where &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all&quot;&gt;&lt;code&gt;Promise.all()&lt;/code&gt;&lt;/a&gt; becomes a godsend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Promise.all() example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, &apos;foo&apos;);
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// expected output: Array [3, 42, &quot;foo&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simply by passing the three promises as an array to &lt;code&gt;Promise.all()&lt;/code&gt;, the promise waited until all three had resolved before moving on to the &lt;code&gt;.then()&lt;/code&gt; part of the statement.&lt;/p&gt;
&lt;p&gt;I’d like to see callbacks do that gracefully.&lt;/p&gt;
&lt;h3&gt;Promise FTW?&lt;/h3&gt;
&lt;p&gt;This is the kind of code my team had been writing in our React application. It was clean, compact, easy to read (in my opinion), I saw nothing wrong with it. Then I investigated async await.&lt;/p&gt;
&lt;h2&gt;ECMAScript 17&apos;s new hotness: async / await&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/async-await/matrix-meme.webp&quot; alt=&quot;Matrix meme where Morpheus promises even cleaner code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The promise of async / await. See what I did there? 😏&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Once more, I turn to Mozilla for the most succinct definitions of async and await.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;async function&lt;/code&gt;&lt;/strong&gt; declaration defines an &lt;strong&gt;asynchronous function&lt;/strong&gt;, which returns an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction&quot;&gt;&lt;code&gt;AsyncFunction&lt;/code&gt;&lt;/a&gt; object. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt; to return its result. But the syntax and structure of your code using async functions is much more like using standard synchronous functions...&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;async&lt;/code&gt; function can contain an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await&quot;&gt;&lt;code&gt;await&lt;/code&gt;&lt;/a&gt; expression that pauses the execution of the async function and waits for the passed &lt;code&gt;Promise&apos;s&lt;/code&gt; resolution, and then resumes the &lt;code&gt;async&lt;/code&gt; function&apos;s execution and returns the resolved value. — &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;Mozilla Docs, Async Function&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While that may make sense to you, I usually benefit from seeing code to really get the gist of it. Here’s a couple of code examples so you can see the differences for yourself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Promise-based example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here’s an example of a promise-based &lt;code&gt;fetch()&lt;/code&gt; HTTP call.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function logFetch(url) {
  return fetch(url)
    .then(response =&amp;gt; response.text())
    .then(text =&amp;gt; {
      console.log(text);
    }).catch(err =&amp;gt; {
      console.error(&apos;fetch failed&apos;, err);
    });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, this seems pretty straightforward so far.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Async / await example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here’s the async / await version of that same call.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function logFetch(url) {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log(&apos;fetch failed&apos;, err);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this too, seems pretty easy to understand - but in a more concise manner.&lt;/p&gt;
&lt;h3&gt;Pros of async / await over promises&lt;/h3&gt;
&lt;p&gt;So what’s the big deal?&lt;/p&gt;
&lt;p&gt;What this seems to boil down to in practice, is that async / await is really &lt;strong&gt;syntactic sugar&lt;/strong&gt; for promises, because it &lt;em&gt;still&lt;/em&gt; uses promises under the hood.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/async-await/got-meme.webp&quot; alt=&quot;Game of Thrones meme about one not using async / await without knowing promises&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;It’s all promises in the end!&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The change to the syntax, though, is where its appeal to many starts to become apparent.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The syntax and structure of your code using async functions is much more like using standard synchronous functions.&lt;/li&gt;
&lt;li&gt;In the examples above, the &lt;code&gt;logFetch()&lt;/code&gt; functions are the same number of lines, but all the callbacks are gone. This makes it easier to read, especially for those less familiar with promises.&lt;/li&gt;
&lt;li&gt;Another interesting tidbit, is that anything you &lt;code&gt;await&lt;/code&gt; is passed through &lt;code&gt;Promise.resolve()&lt;/code&gt; (for us, typically the &lt;code&gt;.then(result)&lt;/code&gt; resolution of the promise), so you can safely &lt;code&gt;await&lt;/code&gt; non-native promises. That’s pretty cool.&lt;/li&gt;
&lt;li&gt;And you can safely combine async / await with &lt;code&gt;Promise.all()&lt;/code&gt; to wait for multiple asynchronous calls to return before moving ahead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To show another example of async / await which is more complex (and better demonstrates the readability of the new syntax), here’s a streaming bit of code that returns a final result size.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second promise-based example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function getResponseSize(url) {
  return fetch(url).then(response =&amp;gt; {
    const reader = response.body.getReader();
    let total = 0;

    return reader.read().then(function processResult(result) {
      if (result.done) return total;

      const value = result.value;
      total += value.length;
      console.log(&quot;Promise-Based Example &quot;, value);

      return reader.read().then(processResult);
    })
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/async-await/matrix-neo-meme.webp&quot; alt=&quot;Matrix meme with Neo wondering how the world really works&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Me, at the first glance of the code above.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;It looks fairly elegant, but you have to stare at the code for a good bit, before you finally understand what it’s doing. Here’s that same code again but with async / await.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second async / await example&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function getResponseSize(url) {
  const response = await fetch(url);
  const reader = response.body.getReader();
  let result = await reader.read();
  let total = 0;

  while (!result.done) {
    const value = result.value;
    total += value.length;
    console.log(&quot;Data received &quot;, value);
    // get the next result
    result = await reader.read();
  }

  return total;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All right, now I’m getting a better idea of async / await syntax being more readable. That code &lt;em&gt;is&lt;/em&gt; much easier read, I can agree with that. And the fact that I can combine it with &lt;code&gt;Promise.all()&lt;/code&gt; is pretty nifty as well.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But to change all the promise-based calls in the entire codebase, I needed more convincing beyond readability for developers...I needed cold, hard, performance-driven benefits.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/async-await/office-space-2-meme.webp&quot; alt=&quot;Office Space meme asking for benefits of refactoring all the promises&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Convince me to refactor everything.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;The silver bullet moment: when async / await won the day&lt;/h3&gt;
&lt;p&gt;And here’s the &lt;a href=&quot;https://v8.dev/blog/fast-async&quot;&gt;&lt;strong&gt;article&lt;/strong&gt;&lt;/a&gt; that really changed my mind, from the team that actually builds and maintains the JavaScript V8 engine running all my Chrome browsers right now.&lt;/p&gt;
&lt;p&gt;The article sums up how some minor changes to the ECMAScript specifications and the removal of two microticks of time, actually lets “async / await outperform hand-written promise code now,” across all JavaScript engines.&lt;/p&gt;
&lt;p&gt;Yes, you read that right. &lt;strong&gt;The V8 team made improvements that make async / await functions run faster than traditional promises in the JavaScript engine.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That was all the proof I needed. It actually runs faster in the browser? Well sign me up.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Promises and async / await accomplish the same thing. They make retrieving and handling asynchronous data easier. They eliminate the need for callbacks, they simplify error handling, they cut down on extraneous code, they make waiting for multiple concurrent calls to return easy, and they make adding additional code in between calls a snap.&lt;/p&gt;
&lt;p&gt;I was on the fence about whether rewriting all our traditional promises to use async / await was worth it, &lt;em&gt;until&lt;/em&gt; I read (from the maintainers of the JavaScript V8 runtime engine) that &lt;strong&gt;they’d actually updated the engine to better handle async / await calls than promises&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If there’s performance improvements for our application that can be gained from something as simple as a syntax change to our code, I’ll take a win like that any day. My ultimate goal is always a better end user experience.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, ES6 or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this helps you make a better informed decision about which syntax style you prefer more: promises or async / await so you can go forward with a consistent asynchronous data handling strategy in your code base.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;JavaScript Promises&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&quot;&gt;Using Promises&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all&quot;&gt;Promise.all()&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;Async Await&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3schools.com/php/php_ajax_intro.asp&quot;&gt;AJAX&lt;/a&gt;, W3Schools Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop&quot;&gt;JavaScript Event Loop&lt;/a&gt;, MDN Docs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://javascript.info/callbacks&quot;&gt;Callbacks&lt;/a&gt;, JavaScript Info&lt;/li&gt;
&lt;li&gt;V8 Developers Blog, &lt;a href=&quot;https://v8.dev/blog/fast-async&quot;&gt;Faster Async Functions and Promises&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>es6</category><category>promises</category><category>async</category></item><item><title>4 Solutions to Run Multiple Node.js or npm Commands Simultaneously</title><link>https://www.paigeniedringhaus.com/blog/4-solutions-to-run-multiple-nodejs-or-npm-commands-simultaneously/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/4-solutions-to-run-multiple-nodejs-or-npm-commands-simultaneously/</guid><description>At some point, everyone has this problem...</description><pubDate>Thu, 02 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/multiple-npm-commands/node-npm-logo.webp&quot; alt=&quot;npm and Node.js logos&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Node and npm: they just go together like peanut butter and jelly.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Funny story: npm doesn&apos;t provide an immediately obvious way to run multiple scripts at once&lt;/h2&gt;
&lt;p&gt;We’ve all been there — you open up an app for local development and you need to run your Express/Node.js backend server and your React UI server simultaneously, but in order to do so you have to open up two terminal windows (or more), &lt;code&gt;cd&lt;/code&gt; into two different &lt;code&gt;package.json&lt;/code&gt; files via the command line and run two different start commands.&lt;/p&gt;
&lt;p&gt;Sound familiar? If only there were a better way...&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/multiple-npm-commands/thinking-hard.gif&quot; alt=&quot;Patrick and Spongebob thinking hard&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Quite simply, there is a better way. And like all good things in web development today, there’s a thousand different ways to achieve the same end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I will share four ways to run multiple Node.js commands or npm scripts at once.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ready? Ok, let’s run through them.&lt;/p&gt;
&lt;h2&gt;The solution(s)&lt;/h2&gt;
&lt;h3&gt;Option 1: Bash &amp;amp;&amp;amp; chained commands&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/multiple-npm-commands/bash.webp&quot; alt=&quot;Bash logos&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Good old Bash - can&apos;t beat the command line.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This solution is the most straightforward and requires no extra npm packages or other software — it is literally just the command line shell.&lt;/p&gt;
&lt;p&gt;Fun fact: the &lt;code&gt;&quot;scripts”&lt;/code&gt; in a package.json file are actually just terminal commands that would be run in an OS’s shell (like Bash). So by using standard shell syntax, you can chain together commands that NPM runs by calling the key associated with those combined values — see my example below.&lt;/p&gt;
&lt;p&gt;Inside your npm script, in the &lt;code&gt;&quot;start&quot;&lt;/code&gt; command, or whatever you want to use to run your servers (provided they’re in the same repo, of course), just chain together your two start scripts like so.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;scripts&quot;: {
  &quot;start&quot;: &quot;react-scripts start&quot;,
  &quot;dev&quot;: &quot;(cd server &amp;amp;&amp;amp; npm run start) &amp;amp; npm run start&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The way this works, is that at the root level of the project is my React project (the &lt;code&gt;&quot;react-scripts start&quot;&lt;/code&gt; command executes in the shell when you type in &lt;code&gt;npm run start&lt;/code&gt; in the terminal), and one level inside of that is a folder called &lt;code&gt;/server&lt;/code&gt; which holds the Node.js server used to proxy calls to all the backend microservices, and starts up with the same command at its root level thanks to its own &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s a very dumbed down diagram of the project structure, for reference:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root/ 
├── package.json 
├── server/ 
| ├── package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, both levels of the project have separate &lt;code&gt;package.json&lt;/code&gt; files with their own dependencies and individual npm start scripts, but by simply chaining the two together with the &lt;code&gt;&amp;amp;&lt;/code&gt; in between them, both Node commands can be run.&lt;/p&gt;
&lt;p&gt;Additionally, using the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; means that the script will wait until the server has successfully started before spinning up the client-side React application (because &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; in bash means the things on both sides of the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; must evaluate to true). If the server can’t start for some reason, the whole npm command will fail and the UI won’t start without its backend server ready to go too.&lt;/p&gt;
&lt;p&gt;That’s the quickest, easiest, most built-in way to run multiple Node.js commands in different file locations, at once.&lt;/p&gt;
&lt;p&gt;Now, I’ll move on to a few npm packages that make the process even simpler, and require no knowledge of Bash.&lt;/p&gt;
&lt;h3&gt;Option 2: Concurrently&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/multiple-npm-commands/npm-logo.webp&quot; alt=&quot;npm logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;npm package #1: Concurrently&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The first npm package I’ll introduce you to is called &lt;a href=&quot;https://www.npmjs.com/package/concurrently&quot;&gt;&lt;strong&gt;Concurrently&lt;/strong&gt;&lt;/a&gt;. Its name is pretty self-explanatory: it runs multiple commands concurrently. 😝&lt;/p&gt;
&lt;p&gt;It’s not as robust, in terms of customization, as my next npm package recommendation, npm-run-all, but I think the majority of the time (hopefully) all the extra configuration is unnecessary.&lt;/p&gt;
&lt;p&gt;After running &lt;code&gt;npm i concurrently&lt;/code&gt; to install it, you can then set up your NPM start script to run multiple commands just by separating each individual command with quotes.&lt;/p&gt;
&lt;p&gt;In a &lt;code&gt;package.json&lt;/code&gt; file, your &lt;code&gt;&quot;scripts”&lt;/code&gt; command might look something like this, (note the need for escape quotes here):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;scripts&quot;: {
  &quot;start&quot;: &quot;react-scripts start&quot;,
  &quot;dev&quot;: &quot;concurrently \&quot;cd server &amp;amp;&amp;amp; npm run start\&quot; \&quot;npm run start\&quot;&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And once again, you should be off to the races. Also worth noting is you can run these same types of commands with quotes surrounding each argument from the command line as well, after Concurrently’s been installed globally.&lt;/p&gt;
&lt;p&gt;I also recommend checking out the &lt;a href=&quot;https://github.com/kimmobrunfeldt/concurrently#readme&quot;&gt;documentation&lt;/a&gt; for more cool tricks you can do with it, like shortening commands, supporting wildcards, etc.&lt;/p&gt;
&lt;h3&gt;Option 3: npm-run-all&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/multiple-npm-commands/npm-logo.webp&quot; alt=&quot;npm logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;npm package #2: npm-run-all&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Moving on, this package is another popular option from NPM, called &lt;a href=&quot;https://www.npmjs.com/package/npm-run-all&quot;&gt;&lt;strong&gt;npm-run-all&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The npm page proclaims npm-run-all to be &quot;A CLI tool to run multiple npm-scripts in parallel or sequential.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is a similar concept to how Concurrently works, but the syntax is slightly different and npm-run-all touts how it can shorten a very long, single start command like: &lt;code&gt;npm run clean &amp;amp;&amp;amp; npm run build:css &amp;amp;&amp;amp; npm run build:js &amp;amp;&amp;amp; npm run build:html&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Into: &lt;code&gt;npm-run-all clean build:*&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The npm-run-all CLI is installed can be installed via npm or Yarn: &lt;code&gt;npm install npm-run-all —-save-dev&lt;/code&gt;, and once installed, it boasts three different commands, based on your needs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mysticatea/npm-run-all/blob/HEAD/docs/npm-run-all.md&quot;&gt;&lt;strong&gt;&lt;code&gt;npm-run-all&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; - the main command, which has documentation on all of the flags and additions you can pass in via the command line.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;run-s&lt;/code&gt;&lt;/strong&gt; - run sequential — for when you need one command to finish before the next one starts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;run-p&lt;/code&gt;&lt;/strong&gt; - run parallel — like when both the UI and server pieces of the application need to run side by side.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If, for example, the &lt;code&gt;package.json&lt;/code&gt; scripts looked like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;scripts&quot;: {
    &quot;clean&quot;: &quot;rimraf dist&quot;,
    &quot;lint&quot;:  &quot;eslint src&quot;,
    &quot;build&quot;: &quot;babel src -o lib&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That could become with npm-run-all: &lt;code&gt;npm-run-all clean lint build&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The combinations can also get much fancier with combinations of parallel and sequential runs together, depending on what your needs are. See the &lt;a href=&quot;https://github.com/mysticatea/npm-run-all/blob/HEAD/docs/npm-run-all.md&quot;&gt;documentation&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;Pretty easy, right?&lt;/p&gt;
&lt;p&gt;And now, on to the last option for running multiple npm commands at once, Docker.&lt;/p&gt;
&lt;h3&gt;Option 4: docker-compose&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/multiple-npm-commands/docker.webp&quot; alt=&quot;Docker mascot: Moby Dock&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The final solution — and a little out in left field: Docker.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Docker and Docker-Compose are whole other articles, which I’ve covered in detail, &lt;a href=&quot;./docker-101-fundamentals-the-dockerfile&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;./docker-102-docker-compose&quot;&gt;here&lt;/a&gt; on Medium. I’d recommend checking both of those out if you’re unfamiliar with the virtual containerization platform that is Docker. It’s an extremely powerful and effective tool, when used properly.&lt;/p&gt;
&lt;p&gt;For this article, I’ll keep the Docker conversation focused specifically on the &lt;code&gt;Dockerfile&lt;/code&gt; and NOT the &lt;code&gt;docker-compose.yml&lt;/code&gt;, which is another piece of the Docker puzzle.&lt;/p&gt;
&lt;p&gt;The Dockerfile provides all the instructions and commands a user could call on the command line to assemble a Docker image. Essentially, it defines an app’s environment so it can be reproduced anywhere.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;docker-compose.yml&lt;/code&gt; defines the services that make up the app, so they can be run together in an isolated environment. That’s a separate piece unrelated to the focus of this article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you’d like a more in-depth explanation of using docker-compose to improve your application development in lower life cycles and even production, please see &lt;a href=&quot;./using-docker-docker-compose-to-improve-your-full-stack-app-development&quot;&gt;this article&lt;/a&gt; I wrote on the subject.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can also see my &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;MERN project repo&lt;/a&gt;, which uses docker-compose to spin itself up, complete with a MySQL database instance running locally.&lt;/p&gt;
&lt;p&gt;In terms of the Dockerfile, though, after you’ve &lt;a href=&quot;https://runnable.com/docker/&quot;&gt;installed Docker&lt;/a&gt; on your machine, it’s very simple to write for a completely JavaScript project.&lt;/p&gt;
&lt;p&gt;Here’s my file structure for the React UI (&lt;code&gt;client/&lt;/code&gt; folder) and Node.js backend (&lt;code&gt;api/&lt;/code&gt; folder) for reference of the file structure.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root/
├── server/ 
├── client/ 
├── docker/ 
├── docker-compose.yml 
├── Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here’s the contents of the whole Dockerfile.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:9
WORKDIR /app
CMD ls -ltr &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s what happening in the lines above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;FROM node:9&lt;/code&gt;&lt;/strong&gt; - Download a version of Node.js from Docker hub.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt;&lt;/strong&gt; - Define the working directory for each app (both go at the root of their respective containers as &lt;code&gt;/app&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;CMD ls -ltr &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm start&lt;/code&gt;&lt;/strong&gt; - npm installs all the dependencies in each using their own &lt;code&gt;package.json&lt;/code&gt; files, and once the dependencies are downloaded, start the apps (both have an &lt;code&gt;npm start&lt;/code&gt; command in their &lt;code&gt;&quot;scripts&quot;&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it. That’s all that’s needed because the &lt;code&gt;docker-compose&lt;/code&gt; tells the multiple applications (&lt;code&gt;server/&lt;/code&gt; and &lt;code&gt;client/&lt;/code&gt;) how to structure themselves, where to mount needed volumes, open ports to the outside environment, get the needed Docker images for things like databases, etc.&lt;/p&gt;
&lt;p&gt;I’d recommend checking out my Docker-powered &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;project&lt;/a&gt; to see more examples of what I’ve described above.&lt;/p&gt;
&lt;p&gt;It’s a little bit of a different tack to run multiple npm scripts at once from the other solutions, with what is arguable a bit more initial overhead, but it works, and if you’re familiar with Docker’s many benefits, it’s a pretty sweet way to run your projects.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Whatever you choose as a resolution, this is a problem that every JavaScript developer runs into at some point or other.&lt;/p&gt;
&lt;p&gt;You need a config file to run before your server starts, you need two servers to run side-by-side to handle UI views and API calls, you need watcher files to keep running while you make file changes — there’s a million reasons. Regardless of the exact scenario, eventually there will come a time when it will be beneficial to run multiple Node.js commands or npm scripts at the same time.&lt;/p&gt;
&lt;p&gt;You could do this manually with multiple, open terminal instances, or you could use one of the solutions I suggest above. One is pure shell scripting, two are popular, stable npm packages, and one is the pretty far removed, but extremely powerful solution of using Docker to containerize and run multiple apps.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you some new ideas on how to approach running your own simultaneous npm scripts when the need arises.&lt;/p&gt;
&lt;h2&gt;References &amp;amp;  Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/concurrently&quot;&gt;Concurrently&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/npm-run-all&quot;&gt;npm-run-all&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;Docker-Compose example repo, Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>npm</category></item><item><title>Take Your VS Code Config Anywhere Easily with Settings Sync</title><link>https://www.paigeniedringhaus.com/blog/take-your-vs-code-config-anywhere-easily-with-settings-sync/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/take-your-vs-code-config-anywhere-easily-with-settings-sync/</guid><description>Just when you thought Visual Studio Code couldn&apos;t get any better, it did.</description><pubDate>Sat, 13 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/vs-code-logo-hero.webp&quot; alt=&quot;VS Code logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;VS Code — the best JavaScript IDE available today&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;My optimum work setup, and how I play with fire&lt;/h2&gt;
&lt;p&gt;I’ve had my current, work-issued MacBook Pro for just under two years, and as you might imagine as a software developer, I’ve installed a lot of stuff on it. Some things, like tools I use regularly, I remember, but most things I’ve installed on it, I probably don’t. It’s the install-once-globally-and-then-never-have-to-think-about-it-again mentality.&lt;/p&gt;
&lt;p&gt;And I know this is a dangerous game to play, because while I’m usually careful with my personal effects, things happen. Coffees get spilled, laptops slip to the floor, OSs get corrupted, and other people can be less conscientious with themselves and their stuff.&lt;/p&gt;
&lt;p&gt;At that point, I have a problem, I have a new or freshly reset laptop devoid of all my personal settings, plugins, random installs and preconfigured tooling that makes development easier and more fun. Especially when it comes to my IDE (Visual Studio Code) — I have it tweaked and set up just how I like it, and in a blink, it could all be gone.&lt;/p&gt;
&lt;p&gt;In that moment, I am reminded of just how painful set up and configuration is. Apparently, I must block this out of my memory every time I have to go through it, because let’s be honest, it’s just a big pain.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/starting-over.gif&quot; alt=&quot;Starting over pain&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This article won’t walk through perfectly restoring your entire machine to the state it was before the incident, that’s beyond the scope of this post.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This article will, however, show you how to perfectly recreate your Visual Studio Code IDE settings without starting over from scratch and spending hours on it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s get going.&lt;/p&gt;
&lt;h2&gt;Settings Sync to the rescue&lt;/h2&gt;
&lt;p&gt;If you haven’t read any of my previous posts &lt;a href=&quot;./the-absolute-easiest-way-to-debug-node-js-with-vs-code&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;./keep-code-consistent-across-developers-the-easy-way-with-prettier-es-lint&quot;&gt;here&lt;/a&gt; about VS Code, I would highly encourage you to do so. It’s an incredible IDE that’s free AND it trumps WebStorm in almost every way, which is not free, I might add (and which I used before).&lt;/p&gt;
&lt;p&gt;One of my favorite things about VS Code is the &lt;a href=&quot;https://marketplace.visualstudio.com/vscode&quot;&gt;extension marketplace&lt;/a&gt; that’s absolutely chock-full of useful plugins people have rolled themselves and felt the need to share with the rest of us developers, mostly for free as well. Bless these people.&lt;/p&gt;
&lt;p&gt;These extensions are some of the things that make VS Code such a delight to develop with — they help make it my own editor too. My color theme (&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=sdras.night-owl&quot;&gt;Night Owl&lt;/a&gt;), my list of must-have plugins (&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&quot;&gt;Prettier&lt;/a&gt; with auto format on save enabled, among others), my sidebar of useful doohickeys (&lt;a href=&quot;https://code.visualstudio.com/docs/containers/overview&quot;&gt;Docker&lt;/a&gt;, &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens&quot;&gt;GitLens&lt;/a&gt;), not to mention &lt;a href=&quot;https://code.visualstudio.com/learn/collaboration/live-share&quot;&gt;Live Share&lt;/a&gt; and the ever-growing list of features the VS Code team keeps releasing each month. I could go on…&lt;/p&gt;
&lt;p&gt;When faced with the possibility of losing (or even trying to transfer) my carefully developed VS Code setup to another machine, I knew there had to be a way to do it gracefully. Some enterprising developer somewhere had faced the challenge I was now facing and had figured out a way to sync their settings across machines.&lt;/p&gt;
&lt;p&gt;I just knew the solution had to be out there, and so, I asked the internets, and it brought back &lt;a href=&quot;https://marketplace.visualstudio.com/itemdetails?itemName=Shan.code-settings-sync&quot;&gt;&lt;strong&gt;Settings Sync&lt;/strong&gt;&lt;/a&gt; (formerly known as Visual Studio Code Settings Sync).&lt;/p&gt;
&lt;h3&gt;Settings Sync&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/settings-sync-logo.webp&quot; alt=&quot;Settings Sync logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I wish this cute little cloud came in a larger image size for this post, but alas.
&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🌴💪 Synchronize your Visual Studio Code Settings Across Multiple Machines using Github GIST 💪🌴 — &lt;a href=&quot;https://github.com/shanalikhan/code-settings-sync&quot;&gt;Settings Sync, GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This plugin, free in the VS Code marketplace is exactly what its Github description says it is: a tool that can sync your VS Code settings across as many machines as you please (complete with palm tree emojis and all), and Github’s gists make it possible.&lt;/p&gt;
&lt;p&gt;And it syncs everything:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Settings file&lt;/li&gt;
&lt;li&gt;Keybinding file&lt;/li&gt;
&lt;li&gt;Launch file&lt;/li&gt;
&lt;li&gt;Snippets folder&lt;/li&gt;
&lt;li&gt;VS Code extensions &amp;amp; extensions configurations&lt;/li&gt;
&lt;li&gt;Workspaces folder&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sounds good in theory, but is it really as easy as its made out to be? Actually, yes. because the &lt;a href=&quot;http://shanalikhan.github.io/2015/12/15/Visual-Studio-Code-Sync-Settings.html&quot;&gt;documentation&lt;/a&gt; that accompanies the Settings Sync plugin is nothing short of great.&lt;/p&gt;
&lt;p&gt;Ok, let’s get set up with Settings Sync.&lt;/p&gt;
&lt;h3&gt;Settings Sync in action&lt;/h3&gt;
&lt;p&gt;Like I said, the actual &lt;a href=&quot;http://shanalikhan.github.io/2015/12/15/Visual-Studio-Code-Sync-Settings.html&quot;&gt;&lt;strong&gt;directions&lt;/strong&gt;&lt;/a&gt; supplied by Settings Sync’s creator are pretty good, but since you’re here, I’ll go through them step-by-step and clarify a few points that I would have appreciated knowing the first time around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Install Settings Sync in VS Code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/settings-sync-extension.webp&quot; alt=&quot;Settings Sync extension in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is the official plugin you’ll see in your own VS Code marketplace.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The obvious first step is to install Settings Sync into your VS Code terminal from the marketplace. This is the icon you’ll see when you search for it.&lt;/p&gt;
&lt;p&gt;Next up, you’ll need to head to your Github account.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Generate a Personal Access Token (PAT) from GitHub&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The way that Settings Sync works is through Github, it makes a private gist with all the VS Code info saved there, which is then accessible to anyone else who has the keys to access the gist.&lt;/p&gt;
&lt;p&gt;So in Github, you’ll go to: &lt;a href=&quot;https://github.com/settings&quot;&gt;&lt;strong&gt;Settings&lt;/strong&gt;&lt;/a&gt; &amp;gt; &lt;a href=&quot;https://github.com/settings/tokens&quot;&gt;&lt;strong&gt;Developer settings&lt;/strong&gt;&lt;/a&gt; &amp;gt; &lt;a href=&quot;https://github.com/settings/tokens&quot;&gt;&lt;strong&gt;Personal access tokens&lt;/strong&gt;&lt;/a&gt; &amp;gt; &lt;strong&gt;Generate New Token&lt;/strong&gt; (see screenshot below).&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/generate-pat.webp&quot; alt=&quot;Create new GitHub PAT&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s a picture of my own VS Code settings sync gist.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As you can see, I already have a “vscode-settings-sync” token, but for the purposes of this article, I clicked the “Generate new token” button to walk through the steps.&lt;/p&gt;
&lt;p&gt;Once you’re in the generation of the token, name the token something easy to remember and click the checkbox next to “Create gists”. That’s all you have to do before you create the token.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/name-pat.webp&quot; alt=&quot;Name GitHub PAT&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;All you have to click is the &quot;gist&quot; box when creating the token.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;After your new token is generated, copy the token hash to your computer clipboard (or Sublime or notes or somewhere), you’ll never be able to access this string again in the future.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/new-pat.webp&quot; alt=&quot;New GitHub PAT&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Copy the access token hash for future use.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;With that done, we’re ready to head back to VS Code now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Upload your VS Code settings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/initiate-settings-sync.webp&quot; alt=&quot;Access Setting Sync from VS Code command palette&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Sync your settings with update / upload settings&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Once back in VS Code, open up the command palette with &lt;code&gt;command + shift + p&lt;/code&gt; (for Macs), and start typing in &lt;code&gt;sync:&lt;/code&gt; and you should see the following list of options. Click the first one: &lt;code&gt;**Sync: Update/Upload Settings**&lt;/code&gt; and you’ll be prompted to add the GitHub token you just copied from your newly created gist.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/apply-pat.webp&quot; alt=&quot;Apply PAT in VS Code settings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is when you enter the hash token from GitHub.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Now you’ve entered the token, all your current VS Code settings should be uploaded, and the &lt;code&gt;OUTPUT&lt;/code&gt; terminal in VS Code will show a message similar to the screenshot below.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/verify-settings-synced.webp&quot; alt=&quot;Verify settings for VS Code are synced&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Verify it worked from the output in the VS Code terminal.
&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;You can see my &lt;code&gt;settings&lt;/code&gt; and &lt;code&gt;extensions&lt;/code&gt; files were uploaded along with all of the extensions I’m currently using in my own VS Code setup.&lt;/p&gt;
&lt;p&gt;You should also be able to go to your gists in Github and verify the settings are there. It will be stored in Gists under a file name like &lt;code&gt;cloudSettings&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But before you close this output terminal: copy the GitHub token and Gist ID generated by the upload — you’ll need these to download your settings on other machines. Put it somewhere you’ll be able to access it from the new machine you’ll be downloading the settings to (Slack, Google Docs, etc.).&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/pat-token-vs-code.webp&quot; alt=&quot;GitHub token and gist&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;You need to keep this gist and token somewhere where you’ll be able to access it again on another machine, like Slack, Sublime, etc.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Now, we’re ready to move on to the new VS Code IDE that needs these settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Download your settings on a new machine&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Start up your new VS Code machine, and you’ll follow the same first step as uploading the settings: open up the command palette with &lt;code&gt;command + shift + p&lt;/code&gt;, then start typing in &lt;code&gt;sync:&lt;/code&gt;, but this time, you’ll select the &lt;code&gt;**Sync: Download Settings**&lt;/code&gt; option from the list.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/download-settings.webp&quot; alt=&quot;Settings Sync download settings option in VS Code command palette&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Download the settings to your new VS Code set up this way.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;After you’ve selected that, Sync Settings will prompt you to enter first your Github personal access token — this is the token you copied from the terminal output created when you uploaded your VS Code settings to Settings Sync.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/reenter-pat-in-vs-code.webp&quot; alt=&quot;Enter the GitHub PAT in the VS Code command palette&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;First enter the GitHub token.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Then, you’ll be asked to enter the Gist ID, also provided from the output terminal (this is the part that tripped me up the first time, I didn’t realize I needed both the token and ID, the first time around). It resulted in my having to reset my Settings Sync and do it again from the original computer to generate a new token and ID, not a big deal, but a bit of a pain.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/vs-code-settings-sync/enter-gist-id.webp&quot; alt=&quot;Enter the GitHub gist ID in the VS Code command palette&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Then enter the gist ID.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;After that, your original settings should download to VS Code without an issue.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Restart your editor and enjoy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You’re done! At this point, you may need to close the VS Code editor completely and reopen it for all the changes to take effect, but that should be it.&lt;/p&gt;
&lt;p&gt;With one big thing knocked off your to-do list, getting your IDE right how you want it to be, you can get on with everything else that comes with setting up a brand new machine. If only it were all so easy. 😬&lt;/p&gt;
&lt;p&gt;And here’s a final fun fact, if you want to share these VS Code settings across a team of developers and machines, you can even make a public Gist that they can all access, more info on that is available here, under the “Create Public Gist to Share Settings” section.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There’s nothing that feels as good when developing software (especially JavaScript) as a fully configured IDE like VS Code. And nothing more painful than trying to remember all the little nuances, plugins and tweaks you did to get it to that state of perfection.&lt;/p&gt;
&lt;p&gt;Now, with the help of the Settings Sync plugin, you don’t have to remember all those things, or spend hours recreating them on a new machine, you can simply save them to Github cloud (and let’s face it, if Github goes down, we’ve all got bigger problems than what our VS Code configurations were) and access them from any other machine as long as you have the personal access token and Gist ID.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about React or something else related to web development, so please follow me so you don’t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this helps you safeguard yourself and your VS Code settings from future accidents, it only takes a few minutes to do, but it can save you hours of reconfiguration.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://shanalikhan.github.io/2015/12/15/Visual-Studio-Code-Sync-Settings.html&quot;&gt;Settings Sync documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/itemdetails?itemName=Shan.code-settings-sync&quot;&gt;Settings Sync extension&lt;/a&gt; in VS Code marketplace&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/shanalikhan/code-settings-sync&quot;&gt;Settings Sync, GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/vscode&quot;&gt;VS Code Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>vscode</category><category>programming</category></item><item><title>Node Engines: Helping Developers Everywhere Avoid Phantom Bugs</title><link>https://www.paigeniedringhaus.com/blog/node-engines-helping-developers-everywhere-avoid-phantom-bugs/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/node-engines-helping-developers-everywhere-avoid-phantom-bugs/</guid><description>Specific Node.js engines should be required for every package.json.</description><pubDate>Sun, 31 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/node-engines/npm-hero.webp&quot; alt=&quot;npm and package.json logos&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;The classic opening line: “It works on my machine.”&lt;/h2&gt;
&lt;p&gt;Let me set the stage for you: you’re writing code, minding your own business, knocking out a shiny new feature for your web application when suddenly a red-light starts flashing (or the #support Slack channel lights up, either one) and it’s all hands on deck: there’s an issue in production. 🚨&lt;/p&gt;
&lt;p&gt;As the development team drops everything to figure out what’s going wrong and attempts to pinpoint and recreate the issue, after twenty minutes of pointless debugging, one bold soul shrugs and says, &quot;Works on my machine.&quot; 😒&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/node-engines/broken-in-prod.webp&quot; alt=&quot;Broken in production? Works on my machine.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Every developer has heard (and said) this at least eleventy billion times.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This statement helps exactly no one, but accurately sums up the issues I’m about to discuss:&lt;/p&gt;
&lt;p&gt;Something as simple as an incompatible Node version in production can break your application, and be nearly impossible for developers to locally figure out that’s the problem. Locking down your Node engine can help you quickly debug and avoid this.&lt;/p&gt;
&lt;p&gt;You never give a second thought as to which version of Node or NPM your machine is using locally versus the version of Node.js your production environment is using… until it matters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real World Examples of Why This Matters&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I speak from personal experience when I say, an AngularJS 1.5 application my team supports ONLY works in Node version 9, however, when we deployed to our production cloud environment, the Node buildpack that deployed with it, pulled in v6. Version 6?!? Who even develops with a Node version that old any more??&lt;/p&gt;
&lt;p&gt;Regardless, our deployment failed because Node 6 couldn’t download the &lt;code&gt;node_modules&lt;/code&gt; dependencies correctly, the application failed to start up, and it took several hours of pouring over code, build logs, and environment variables to figure out what the actual problem was. That deployment became known as &quot;Dark Thursday&quot; within my dev team. To this day, if you ask someone who was there about that night, they’ll give you a haunted look in return. 😱&lt;/p&gt;
&lt;p&gt;Similarly, our React application needs Node version 10 or higher, to take advantage of all the ES6 and beyond node dependencies that it has. It needs to be at least v10 or above, no ifs, ands, or buts.&lt;/p&gt;
&lt;p&gt;So now you can see why not knowing what version of Node your cloud buildpack will default to is bad. It means you don’t know if your node modules will successfully be downloaded or fail. We can all agree that’s no way to develop.&lt;/p&gt;
&lt;p&gt;But how do we ensure that we get the buildpack we need? How do we guarantee when we’re deploying from our local development environment to our cloud production environment that the Node.js runtime is the same? That it can support the Node dependencies our project needs to run?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It’s actually easier than you might think: strictly defining the Node engines for a project. Read on to learn how.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;How do we prevent the wrong version of Node taking down our application?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Easy: engines&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/node-engines/confused-ryan-reynolds.gif&quot; alt=&quot;Ryan Reynolds confused &quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I don’t blame you if this is your initial response, it was mine too.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Engines? What does that even mean?&lt;/p&gt;
&lt;h3&gt;What are Node engines?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.npmjs.com/files/package.json#engines&quot;&gt;&lt;strong&gt;Node engines&lt;/strong&gt;&lt;/a&gt; are a little discussed (but in my opinion pretty critical) configuration that can be specified in your &lt;code&gt;package.json&lt;/code&gt; file that tells anyone (or any machine) running the JavaScript application which version of Node is required for the code to work.&lt;/p&gt;
&lt;p&gt;npm’s &lt;a href=&quot;https://docs.npmjs.com/files/package.json#engines&quot;&gt;own docs&lt;/a&gt; say when defining engines:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You can specify the version of node that your stuff works on” — npm&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pretty self-explanatory.&lt;/p&gt;
&lt;p&gt;What this means in practice is: if &lt;code&gt;engines&lt;/code&gt; is included, when a JavaScript build deploys (depending on how the engine field is specified) it will look for a version of Node at or above the version configured in the &lt;code&gt;package.json&lt;/code&gt;, then download it and install all the &lt;code&gt;node_modules&lt;/code&gt; dependencies using that engine.&lt;/p&gt;
&lt;p&gt;If an engine is not specified, the project is at the mercy of the buildpack gods, and will assume any old version of Node will do and download the dependencies with some random version of Node and npm. Which is how we end up with fire drills like the scenario described above.&lt;/p&gt;
&lt;p&gt;In fact, you can actually specify the version of Node.js, the version of npm and the version of Yarn a project uses in its &lt;code&gt;engines&lt;/code&gt; config, which is pretty sweet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Just to be crystal clear: the &lt;code&gt;engines&lt;/code&gt; field will be verified when you install the package, not when you run the application.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that you’re better acquainted with Node engines, why they’re useful and how they work, let’s go about setting up a project to prevent an easily avoidable deployment failure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1. Figure out your local development runtime&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first step is to figure out which version of Node you’re with developing locally. Simple enough.&lt;/p&gt;
&lt;p&gt;Just open up a terminal window and type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you should see the version of Node you’re working with printed out to the terminal. See the screenshot below.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/node-engines/node-version.webp&quot; alt=&quot;Node version displayed in a terminal&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;How to see the local version of Node running on your machine. For me, it’s currently v11.10.0.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If you ever need to switch Node versions for local development, I’d highly recommend &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;NVM (Node Version Manager)&lt;/a&gt;, which I also wrote a blog post about &lt;a href=&quot;./nvm-the-easiest-way-to-switch-node-environments-on-your-machine-in-a-flash&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But that’s a tangent. All you need for now, is to know what Node version you’re currently developing in. Let’s move on to Step 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Specify your Node engine in the &lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that you know the version of Node, you can specify it in your &lt;code&gt;package.json&lt;/code&gt; file in your project. Below are a couple of examples what the engines config looks like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node and npm version example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This example includes both a Node version that’s greater than or equal to v11.10.2 and less than v12.0.0, and an npm version of exactly 5.8.0.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;... // code above here like dependencies and other specs
  &quot;engines&quot;: {    
    &quot;node&quot;: &quot;&amp;gt;=11.10.2 &amp;lt;12.0.0&quot;,    
    &quot;npm&quot;: &quot;5.8.0&quot;  
  },
... // more code below here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Node version example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Or this example, which includes a Node version around 10.15.0.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;... // more code 
  &quot;engines&quot;: {    
    &quot;node&quot;: &quot;~10.15.0&quot;  
  },
... // more code
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Specifying Node, npm and Yarn versions is similar to specifying them for dependencies in your &lt;code&gt;package.json&lt;/code&gt;, you can be as specific as you want down to the exact version, provide a lower limit, provide a range or an approximate. It’s up to you.&lt;/p&gt;
&lt;p&gt;After you’ve set the Node engine in the &lt;code&gt;package.json&lt;/code&gt;, it’s time to deploy the application and verify the correct engine is being downloaded and used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Run your deployment build scripts &amp;amp; verify the buildpack matches&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once your build pipeline is deploying the JavaScript application, you should be able to verify in the logs that the specified Node version is being downloaded and the correct node module dependencies along with it.&lt;/p&gt;
&lt;p&gt;Below are some logs from our Jenkins server that runs all of our builds for our AngularJS application, which requires a version of Node 9. As you can see in the first screenshot, the build is checking for a specific Node version on the server and finds 9.11.2 specified in the &lt;code&gt;package.json&lt;/code&gt;, so it installs that version to the build server if it’s not already available.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/node-engines/build-logs-1.webp&quot; alt=&quot;Checking the Node version in the deployment logs&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s verification that the version of Node.js is running on the Jenkins build server.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And here’s another screenshot example, this time of our React application, which needs a Node version of 10 or above, downloading Node v10.15.0, also specified in the React’s &lt;code&gt;package.json&lt;/code&gt; &lt;code&gt;&quot;engines&quot;&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/node-engines/build-logs-2.webp&quot; alt=&quot;Checking the Node version in the deployment logs&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Another example of the specified Node engine being downloaded to then get the project’s needed node module dependencies.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;After this happens, the specified Node dependencies can be successfully downloaded and our applications should be able to start up without a problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Enjoy your less stressful production deployment&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Feel the relief wash over you as you suddenly have one less variable to worry about when you deploy to production. 😄&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/node-engines/sigh-of-relief.gif&quot; alt=&quot;Sigh of relief&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Node engines won’t solve all your problems, but they at least should take some of the guesswork (and unintended bugs) out of your production deployments. For the small amount of work it takes to specify this in your &lt;code&gt;package.json&lt;/code&gt; configuration, the investment now can save you hours down the line. Trust me, it’s worth it.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about JavaScript, React or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this convinces you to specify your Node versions and npm / Yarn engines in your &lt;code&gt;package.json&lt;/code&gt; configuration.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;npm, &lt;a href=&quot;https://docs.npmjs.com/files/package.json#engines&quot;&gt;Engines documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;NVM, GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>npm</category></item><item><title>Update Feature Toggles in a React App without Redeploying</title><link>https://www.paigeniedringhaus.com/blog/update-feature-toggles-in-a-react-app-without-redeploying/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/update-feature-toggles-in-a-react-app-without-redeploying/</guid><description>Spring Cloud makes feature toggles easy. A Node endpoint makes app redeployment unnecessary.</description><pubDate>Fri, 15 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/multiple-devs-hero.webp&quot; alt=&quot;Multiple developers looking at a computer together&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Feature toggles: the preferred way to test new UI features&lt;/h2&gt;
&lt;p&gt;Have you ever said to yourself: “Gee, I wish I could deploy this new feature to just a few of my users at a time. I want to test if they like it and it works well, before I open it up to the entire user base.”?&lt;/p&gt;
&lt;p&gt;Then you shrug, deploy to production, and the site crashes when 250 users find that one unhappy path you didn’t even contemplate it was so far outside the scope of how to logically use the site (because that’s what users excel at).&lt;/p&gt;
&lt;p&gt;This kind of scenario (and the ensuing mad scramble to code up a fast fix) could have been prevented with feature toggles.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So what are feature toggles?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Aside from the scenario I described above, according to Wikipedia:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;feature toggle&lt;/strong&gt; is a technique in &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_development&quot;&gt;software development&lt;/a&gt; that attempts to provide an alternative to maintaining multiple &lt;a href=&quot;https://en.wikipedia.org/wiki/Source_code&quot;&gt;source-code&lt;/a&gt; branches (known as feature branches), such that a feature can be tested even before it is completed and ready for release. Feature toggle is used to hide, enable or disable the feature during run time. For example, during the development process, a developer can enable the feature for testing and disable it for other users.&lt;/p&gt;
&lt;p&gt;— &lt;a href=&quot;https://en.wikipedia.org/wiki/Feature_toggle&quot;&gt;Wikipedia, feature toggle&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Feature toggles allow developers to introduce new features to a small group of users (beta testers), ensure that all the kinks and bugs are worked out, and the feature is solid and well liked by the users before letting everyone have access to it.&lt;/p&gt;
&lt;p&gt;It also allows for multiple versions of an application to exist at once. Although feature toggles are generally thought of as impermanent - used for testing features then releasing them to the general public once they’ve been vetted - they could also be used maintain multiple versions of an application, with different versions available to different users.&lt;/p&gt;
&lt;p&gt;If you’d like to read more about how to go about setting up a config server, you can read an &lt;a href=&quot;./why-a-spring-cloud-config-server-is-crucial-to-a-good-ci-cd-pipeline-pt-1&quot;&gt;article&lt;/a&gt; I wrote a while back about setting one up with the help of Spring Boot’s Cloud Configuration package.&lt;/p&gt;
&lt;p&gt;And if you’d like to see another way of setting up feature toggles in a slightly older JavaScript application, I wrote an &lt;a href=&quot;./leveraging-a-spring-cloud-config-server-in-a-node-js-apps-feature-toggles-pt-2&quot;&gt;article&lt;/a&gt; about that as well. That implementation though, required a redeployment of the total application every time a new user or group was added with a feature toggle, but with this new solution that’s unnecessary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this blog, I’ll show you how to add new information to existing feature toggles in a React UI without having to redeploy the whole application.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The best part? It’s not terribly complicated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; this article does not eliminate the need to modify and redeploy UI code to implement brand new feature toggles, but it does make it possible to modify existing feature toggles with new information (like new users or user groups).&lt;/p&gt;
&lt;h2&gt;Rebuilding and redeploying UIs is not always a must&lt;/h2&gt;
&lt;p&gt;Back in the olden days of JavaScript development, when Grunt and Gulp tasks rebuilt jQuery fueled applications, if you wanted to modify feature toggles in the UI with new information, the whole application had to be rebuilt from the Node.js server up. Recompiled, re-minified, re-uglified, rebuilt and redeployed to the server or the cloud.&lt;/p&gt;
&lt;p&gt;It didn’t really take too long in the grand scheme of things, but it was still a pain. And for my business partners who wanted the relative ease of clicking a button to enable or disable a feature toggle for certain user groups, it made that impossible.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/easy-button.jpeg&quot; alt=&quot;Staples easy button&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is how easy my business partners want feature toggling to be: just push the button.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Now, with newer tools at our disposal like Webpack and hot reloading in the browser with frameworks like React, it doesn’t have to be that way anymore.&lt;/p&gt;
&lt;p&gt;You can simply update the information being provided to the UI from the config server, refresh it via the Node.js server, and voilà — the modifications are picked up in the browser.&lt;/p&gt;
&lt;h2&gt;Feature toggle setup&lt;/h2&gt;
&lt;h3&gt;Enabling feature toggles with the Cloud Config Client npm package&lt;/h3&gt;
&lt;p&gt;In order to set up our JavaScript application to connect to the Spring Cloud Config server, I used a package called &lt;a href=&quot;https://www.npmjs.com/package/cloud-config-client&quot;&gt;&lt;strong&gt;&lt;code&gt;cloud-config-client&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; from npm.&lt;/p&gt;
&lt;p&gt;There’s a dozen packages like this made for connecting Node.js applications to Spring Boot cloud configuration servers, but this one is one of the more popular, well-documented packages on npm, so it’s the one I chose to go with this time.&lt;/p&gt;
&lt;p&gt;I broke these steps down into server side and client side so you can see where the Node.js files are in play versus the React files.&lt;/p&gt;
&lt;h3&gt;Server side: configure in &lt;code&gt;server.js&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;After initially installing the &lt;code&gt;cloud-config-client&lt;/code&gt; package with &lt;code&gt;npm i --save cloud-config-client&lt;/code&gt;, it’s time to configure the Node’s &lt;code&gt;server.js&lt;/code&gt; file. The place where every good Express-powered Node application begins.&lt;/p&gt;
&lt;p&gt;My &lt;code&gt;server.js&lt;/code&gt; file is relatively small, as a lot of the routes, loggers, and other Node server extras have been split off into their own folders to keep it more organized.&lt;/p&gt;
&lt;p&gt;The only adjustments needed to this file are requiring the route to the config server at the top of the file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const configServerRouter = require(&apos;./routes/configServer&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then making sure that when the React client’s request comes to the Node server and includes &lt;code&gt;/configserver/&lt;/code&gt; in the URL path, it routes to the &lt;code&gt;configServer.js&lt;/code&gt; file, where the logic to access the Spring Cloud Config server is stored. Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.use(&apos;/configserver&apos;, configServerRouter);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/server-js.webp&quot; alt=&quot;Node server.js file code to access config server route&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;There’s not much to update in the Node’s server.js file to make it able to access the cloud config server.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Next, I move on to the &lt;code&gt;configServer.js&lt;/code&gt; file, which resides inside my &lt;code&gt;routes/&lt;/code&gt; directory on the server side.&lt;/p&gt;
&lt;h3&gt;Server Side: Connect to the Spring Cloud and Create The Two Node Config Server Endpoints&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;configServer.js&lt;/code&gt; file contains the majority of the connection information to the Spring Cloud config server running in the cloud.&lt;/p&gt;
&lt;p&gt;Below, is a screenshot of the whole file — I’ll go over each section in detail, but at a high level, it contains a function call to initially connect to the config server and load any feature toggle info that may be present: &lt;code&gt;loadConfig()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There’s an endpoint to refresh the info supplied to the config server with the &lt;code&gt;/refresh&lt;/code&gt; endpoint. &lt;strong&gt;This is the key to enabling or disabling feature toggles &lt;em&gt;without&lt;/em&gt; having to rebuild and redeploy the whole JavaScript application every time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And finally, there’s the actual &lt;code&gt;/featureToggles/:feature&lt;/code&gt; endpoint, which is how the React UI calls to the Node.js server to figure out which feature toggles are available.&lt;/p&gt;
&lt;p&gt;Ok, now let’s get in to the details of each function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;configServer.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/config-server-js.webp&quot; alt=&quot;Node configServer.js file code to handle config server logic&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s my whole configServer.js file for checking and refreshing feature toggles.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Server side: feature toggle endpoint&lt;/h3&gt;
&lt;p&gt;Here’s a close up of the &lt;code&gt;loadConfig()&lt;/code&gt; and &lt;code&gt;/featureToggles/:feature&lt;/code&gt; functions that are used to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fetch any feature toggle info from the Spring Cloud config server, and&lt;/li&gt;
&lt;li&gt;Handle calls from the UI to check if certain feature toggles are available for user groups.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the actual &lt;code&gt;loadConfig()&lt;/code&gt; function, I just followed the documentation supplied by the &lt;a href=&quot;https://www.npmjs.com/package/cloud-config-client&quot;&gt;&lt;code&gt;cloud-config-client&lt;/code&gt;&lt;/a&gt; package.&lt;/p&gt;
&lt;p&gt;Once the initial connection is made from that function, there’s a good bit of &lt;a href=&quot;https://lodash.com/&quot;&gt;Lodash functions&lt;/a&gt; being used to massage the config server data into a map of keys and values for each individual feature toggle. If that’s a little hard to follow, it might make more sense when I show an example of the feature toggle in action. For now, keep reading.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;router.get(/featureToggles/:feature)&lt;/code&gt; function is the endpoint that will handle the call from the React client, check if that &lt;code&gt;:feature&lt;/code&gt; exists as a key in the previously created &lt;code&gt;configServerMap&lt;/code&gt; and if it does, return a positive 200 HTTP response to the client side.&lt;/p&gt;
&lt;p&gt;That’s all there is to it for this bit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;configServer.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/load-config-js.webp&quot; alt=&quot;Node configServer.js file code to handle config server logic&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A close up of both the initial loadConfig() call that gets the info from the Spring Cloud server, and the feature toggle call sent from the client side checking the configServerMap.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Server side: feature toggle refresh endpoint&lt;/h3&gt;
&lt;p&gt;The other function to be aware of here is the &lt;code&gt;router.post(/refresh)&lt;/code&gt; endpoint. This endpoint can be called from either the browser, or (more likely) an API REST client like &lt;a href=&quot;https://www.getpostman.com/&quot;&gt;Postman&lt;/a&gt; or &lt;a href=&quot;https://insomnia.rest/&quot;&gt;Insomnia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is how changes made to the config server files get updated and pulled into the UI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This ‘/refresh’ endpoint is the key to modifying the information provided to already existing feature toggles in the React UI.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the very same &lt;code&gt;loadConfig()&lt;/code&gt; function that’s called as soon as the Node.js server starts up the first time, is called again when the &lt;code&gt;/refresh&lt;/code&gt; endpoint is triggered. And to let users know the refresh worked, a simple JSON message is sent back when the POST is successful: &lt;code&gt;res.send(&quot;Refreshed Config Server.&quot;);&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;configServer.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/load-config-js.webp&quot; alt=&quot;Node configServer.js file code to handle config server logic&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The refresh endpoint triggered to bring in new information related to feature toggles already implemented in the UI application. This is the key.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Client side: feature toggle call&lt;/h3&gt;
&lt;p&gt;Now, we get to the client side in the React UI, and it’s dead simple. On the UI side of things, I have a folder inside of React called /services where all the shared business logic files live and there’s one file concerned with the config server, appropriately called &lt;code&gt;configServerService.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This serves as the connection point between the React UI client and the Node.js server.&lt;/p&gt;
&lt;p&gt;As you can probably tell from the screenshot below, this example feature toggle is called &lt;code&gt;&quot;status-pilot&quot;&lt;/code&gt; and it checks a user’s&lt;code&gt; ldap&lt;/code&gt; (username), which is provided by the Spring Cloud config server through the &lt;code&gt;/configServer/featureToggles/status-pilot&lt;/code&gt; endpoint. Then it checks the client supplied &lt;code&gt;ldap&lt;/code&gt; against the list of users from the config server and if one of them matches the names in the list, it returns a truth-y boolean.&lt;/p&gt;
&lt;p&gt;With this confirmation the user is allowed to see certain features currently being tested out in the app with a small, select group of users. And that’s it.&lt;/p&gt;
&lt;p&gt;Just call the &lt;code&gt;isStatusPilotUser()&lt;/code&gt; function wherever the React app is checking the user’s permissions in the UI and set the boolean of &lt;code&gt;isStatusPilotUser&lt;/code&gt; to true or false after the Node server gives its response based on the info from the config server.&lt;/p&gt;
&lt;p&gt;This same sort of function set up can be added to this service file for multiple feature toggles at once, as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;configServerService.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/load-config-js.webp&quot; alt=&quot;React configServerService.js file code to handle client side config server logic&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is the function on the client side: isStatusPilotUser() that communicates with the Node server that’s holding feature toggle information provided by the config server.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Feature toggles in action&lt;/h2&gt;
&lt;p&gt;Right, so now that I’ve walked through how to connect the Node server to the Spring Cloud config server, and connect the React client to the Node server, it’s time to show a feature toggle in action.&lt;/p&gt;
&lt;p&gt;The first thing needed is a simple: an updated configuration YAML file for the Spring Cloud config server to consume.&lt;/p&gt;
&lt;p&gt;Continuing with the &lt;code&gt;&quot;status-pilot&quot;&lt;/code&gt; example from above, here’s a YAML file, with a list of LDAPs (usernames). The highlighted username &lt;code&gt;&quot;AM00002&quot; &lt;/code&gt;is a new addition to the list that the Node.js server isn’t yet aware of.&lt;/p&gt;
&lt;p&gt;This change won’t immediately be registered by the config server itself, I’ll have to trigger it manually to update (or set up a cron job) and get the new information from the file, but I’ll come to that in a minute.&lt;/p&gt;
&lt;h3&gt;Update the config file for the Spring Cloud config server&lt;/h3&gt;
&lt;p&gt;Here’s the simple YAML file I mentioned above. The highlighted user &lt;code&gt;&quot;AM00002&quot;&lt;/code&gt; is a new addition to the file (and the status-pilot list).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;status-pilot-example.yml&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/status-pilot-ldap-yaml.webp&quot; alt=&quot;Status pilot LDAP list in YAML form&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s an example YAML file. &quot;AM00002&quot; is a new user who’s been added to the ‘status-pilot’ feature toggle.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Verify the config info being sent to the Node server&lt;/h3&gt;
&lt;p&gt;Currently, when I start up the Node server connected to the Spring Cloud server and the React UI client, it pulls in the previously existing list of info from the Spring Cloud config server. Because the Spring server’s not aware the info it is supplying has changed, it continues to supply the previously cached configuration info to the client.&lt;/p&gt;
&lt;p&gt;If you look carefully in the screenshot on the right hand side, you can see that user &quot;AM00002&quot; is not present in the &lt;code&gt;pilotUserList&lt;/code&gt;. That’s fine, this will be updated soon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;configServer.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/config-server-before-new-user.webp&quot; alt=&quot;Config server list of users before refreshing the endpoint&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Just confirming who is and is not currently considered as part of the pilotUserList by the UI’s Node server. Notice &quot;AM00002&quot; is not in that list yet...&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Hit the Node server’s &lt;code&gt;/refresh&lt;/code&gt; endpoint with Postman&lt;/h3&gt;
&lt;p&gt;Time to tell the Spring server to update the files it’s serving. Open up the Postman REST client and type in the URL of your app’s &lt;code&gt;/refresh&lt;/code&gt; endpoint and send a &lt;code&gt;POST&lt;/code&gt; request to it.&lt;/p&gt;
&lt;p&gt;If the refresh trigger is successful, the following success message will appear as the response from the server side in Postman.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/config-server-before-new-user.webp&quot; alt=&quot;Postman success message after hitting the config server refresh endpoint&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is what a successful call from Postman looks like to the config server endpoint.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Check that the React UI now sees &quot;AM00002&quot; as a Status Pilot User&lt;/h3&gt;
&lt;p&gt;Finally, I can verify the changes have taken effect after refreshing the Spring Cloud server’s info via Postman, by putting a breakpoint in the Chrome DevTools on the client’s &lt;code&gt;isStatusPilotUser()&lt;/code&gt; function in the &lt;code&gt;configServerService.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When the browser pauses on the breakpoint, I can see the usernames contained in the &lt;code&gt;ldapList &lt;/code&gt;supplied to the Node server from the Spring config server. And if you look closely, you can see &lt;code&gt;&quot;am00002&quot;&lt;/code&gt; is now there; clear as day.&lt;/p&gt;
&lt;p&gt;The refresh to the UI’s feature toggle info worked, and all without having to rebuild or redeploy the JavaScript application. And I’m done, now this user is also part of the &lt;code&gt;status-pilot&lt;/code&gt; program in this particular UI feature toggle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;configServerService.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-feature-toggles/config-server-after-new-user.webp&quot; alt=&quot;Config server list of users after refreshing the endpoint&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;By using these breakpoints, I can tell the modifications to the status-pilot feature toggle took effect, and now &quot;AM00002&quot; is part of the status-pilot as well.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The update to the existing feature toggle &quot;status-pilot&quot; worked, and all without having to rebuild or redeploy the JavaScript application.&lt;/p&gt;
&lt;p&gt;With just a few additions to the Node server using the &lt;code&gt;cloud-config-client&lt;/code&gt; and a call to a &lt;code&gt;/refresh&lt;/code&gt; REST endpoint, the React UI’s existing feature toggles can be modified and updated in short order.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you can use this implementation to update your own JavaScript application’s feature toggles, and be able to test new features more easily with a subset of your own users.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Feature_toggle&quot;&gt;Wikipedia, feature toggle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cloud config client, &lt;a href=&quot;https://www.npmjs.com/package/cloud-config-client&quot;&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cloud config client, &lt;a href=&quot;https://github.com/victorherraiz/cloud-config-client#readme&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lodash.com/&quot;&gt;Lodash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.getpostman.com/&quot;&gt;Postman&lt;/a&gt; REST client&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://insomnia.rest/&quot;&gt;Insomnia&lt;/a&gt; REST client&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>react</category><category>spring boot</category></item><item><title>nvm, the Easiest Way to Switch Node Environments on Your Machine in a Flash</title><link>https://www.paigeniedringhaus.com/blog/nvm-the-easiest-way-to-switch-node-environments-on-your-machine-in-a-flash/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/nvm-the-easiest-way-to-switch-node-environments-on-your-machine-in-a-flash/</guid><description>Nope, I didn’t misspell npm — Node Version Manager is its own handy dev tool.</description><pubDate>Sun, 03 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-hero.webp&quot; alt=&quot;nvm logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;nvm — a simple bash script to manage multiple active Node.js versions.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Multiple Node environments are a pain to develop locally&lt;/h2&gt;
&lt;p&gt;I&apos;m sure I’m not alone when I tell you that my current development team owns two different UI applications: one built in AngularJS (the old one) and one built in React (the new one). The two work together to serve up a single user experience, while we slowly migrate over the existing screens and functionality from the old, AngularJS application into the new, React application. The end goal is that the React application will one day host the entire application on its own.&lt;/p&gt;
&lt;p&gt;I’m sure I’m also not alone when I tell you that the AngularJS application will ONLY run on Node.js version 9 (it crashes and causes weird bugs if it’s not), and our React application needs Node version 10 or above to take advantage of all the ES6 and beyond features.&lt;/p&gt;
&lt;p&gt;And you know what? Switching between Node environments for local development is kind of a pain. It’s not easy, it’s something I forget to do frequently (until I have an unexplained issue during development), and frankly, it’s just not the easiest thing to do on a Mac.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Painfully changing Node versions was my lot in life, until a co-worker clued me in to an awesome tool called &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;Node Version Manager (nvm)&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;nvm is a local web development game changer. Let me tell you how.&lt;/p&gt;
&lt;h2&gt;Node Version Manager&lt;/h2&gt;
&lt;h3&gt;What is it?&lt;/h3&gt;
&lt;p&gt;Node Version Manager is exactly what its name says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[nvm is a] Simple bash script to manage multiple active node.js versions. —&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;nvm, GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While it doesn’t sound complicated, what nvm can do is awesome. It makes it possible to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access every long term support (LTS) version of Node.js from v0.1.14 to the latest version today, which happens to be v.11.10.1, as I write this.&lt;/li&gt;
&lt;li&gt;Download any one of those remote LTS versions of Node locally with a simple command.&lt;/li&gt;
&lt;li&gt;Set up aliases to switch between different downloaded versions of Node with ease.&lt;/li&gt;
&lt;li&gt;Default to automatically use whichever version of Node.js is specified if a &lt;code&gt;.nvmrc&lt;/code&gt; file is present in a repo.&lt;/li&gt;
&lt;li&gt;And it works with multiple types of shells: Sh, Bash, Zsh, Dash, Ksh, (not Fish though).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As long as you’re fairly comfortable with the terminal, you can use NVM.&lt;/p&gt;
&lt;h3&gt;Setting up nvm&lt;/h3&gt;
&lt;p&gt;nvm is relatively easy to set up too — after hearing about its benefits, I was able to use the &lt;a href=&quot;https://github.com/nvm-sh/nvm#installation-and-update&quot;&gt;GiHhub &lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt; to set it up on my computer in short order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Install nvm&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first step is simplest: just install nvm with the curl or wget command provided in the documentation.&lt;/p&gt;
&lt;p&gt;cURL command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wget command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 1.5: Verify nvm in the command line&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Close your current terminal for the install to take effect, open a new terminal window and type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;command -v nvm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If it’s installed you’ll get a message like the screenshot below.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-installed.webp&quot; alt=&quot;Confirmation nvm is installed on the command line&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is the nvm response you want to see. If you get a response like &lt;code&gt;nvm command not found&lt;/code&gt;, it’s not ready to be used yet.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If the version of nvm shows up in the terminal, you’re ready to go and can move on to the section &lt;a href=&quot;#using-nvm&quot;&gt;Using nvm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you get an error, you’re like me and need to do a bit more manual installation to set up your shell to point to nvm&apos;s home directories. Keep reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Add the nvm directory paths to your shell profile (when needed)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For me, even after installing nvm using the cURL command, I still got an error message in my terminal when I typed the command &lt;code&gt;-v nvm&lt;/code&gt; to verify the installation.&lt;/p&gt;
&lt;p&gt;At that point, I jumped down the documentation to the &lt;a href=&quot;https://github.com/nvm-sh/nvm#git-install&quot;&gt;&lt;strong&gt;Git Install&lt;/strong&gt;&lt;/a&gt; section which had additional notes on how to add the nvm directory paths to the various shell profiles like &lt;code&gt;~/.bashrc&lt;/code&gt; or &lt;code&gt;~/.zshrc&lt;/code&gt;, in my case, since I prefer to use Zsh.&lt;/p&gt;
&lt;p&gt;To edit my &lt;code&gt;.zshrc&lt;/code&gt;, I just run the following command in the terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nano .zshrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Scroll down to the bottom of the file and paste in the following lines.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export NVM_DIR=&quot;$HOME/.nvm&quot;
[ -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;amp;&amp;amp; \. &quot;$NVM_DIR/nvm.sh&quot;  # This loads nvm
[ -s &quot;$NVM_DIR/bash_completion&quot; ] &amp;amp;&amp;amp; \. &quot;$NVM_DIR/bash_completion&quot;  # This loads nvm bash_completion
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then type &lt;code&gt;CTRL + X&lt;/code&gt; from a Mac, &lt;code&gt;Y&lt;/code&gt; to save the changes, and &lt;code&gt;Enter&lt;/code&gt; and you should be back where you started in the terminal.&lt;/p&gt;
&lt;p&gt;If you want to double check your changes are there, you can run &lt;code&gt;cat .zshrc&lt;/code&gt; and scroll down with the down arrow key to check the new nvm scripts are at the bottom of the file.&lt;/p&gt;
&lt;p&gt;Once you’re sure it’s there, completely quit the terminal program and reopen it and type &lt;code&gt;command -v nvm&lt;/code&gt; again, and you should see this:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-installed.webp&quot; alt=&quot;Confirmation nvm is installed on the command line&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Now you’re in business. nvm is installed and ready to be used.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Now we’re ready to use nvm.&lt;/p&gt;
&lt;h2&gt;Using nvm&lt;/h2&gt;
&lt;p&gt;nvm is super simple to use. Here’s the commands you’ll need to know when you want to work with nvm in the command line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nvm ls-remote&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This shows you all available LTS versions of Node.js.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/ls-remote.webp&quot; alt=&quot;List of Node.js versions available via nvm&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is just a fraction of all the available Node.js versions nvm has to offer.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nvm ls&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Shows you all installed versions available locally on your machine.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-ls.webp&quot; alt=&quot;All the versions of Node.js installed on my local machine&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The versions of Node.js installed on my local machine.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nvm install node OR nvm install 8.15.1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Typing &lt;code&gt;nvm install node&lt;/code&gt; will install the latest version of Node.js to your machine, or &lt;code&gt;nvm install &amp;lt;SPECIFIC_NODE_VERSION&amp;gt;&lt;/code&gt; will install the specified version.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-install.webp&quot; alt=&quot;Install the latest Node version via nvm&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I just installed the latest version of Node.js to my local development machine.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nvm use node OR nvm use 11.10.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will set the version of Node.js running locally to the latest version downloaded if you just type &lt;code&gt;nvm use node&lt;/code&gt;, or the version specified if you append the command with the version number &lt;code&gt;nvm use --version&lt;/code&gt; e.g. &lt;code&gt;nvm use 8.15.1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-use.webp&quot; alt=&quot;Choose which version of Node.js to use with nvm&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Both of the use commands: the first defaults to the latest version (11.10.1), the second sets the version to 11.10.0.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The version you want to run locally must be installed on your machine first, or else Node will fall back to whatever version it was running before the command was issued.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;nvm run node OR nvm run 11.10.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This command is almost the same as the one above, the only difference is typing &lt;code&gt;nvm run node&lt;/code&gt; or &lt;code&gt;nvm run --version&lt;/code&gt; like &lt;code&gt;nvm run 11.10.0&lt;/code&gt; will switch to the specified version of Node.js and open up a Node command line for you to run commands manually from afterwards.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-run.webp&quot; alt=&quot;Choose which version of Node.js to run with nvm&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;From nvm run node, I can then run commands like &lt;code&gt;console.log(‘hello world’)&lt;/code&gt; or &lt;code&gt;server.js&lt;/code&gt; right after switching to a Node version.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In this way, you could, potentially, have multiple terminals open running multiple versions of Node at once. 🤔 Pretty handy…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nvm alias default node OR nvm alias default 11.10.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;These commands will set an NVM alias called ‘default’ to the latest downloaded version of node with nvm alias default node, or the specified version with nvm alias default --version like nvm alias default 11.10.0.&lt;/p&gt;
&lt;p&gt;Once this default alias is set, any new shell will default to running with that version of Node.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/nvm-node-envs/nvm-alias.webp&quot; alt=&quot;Give Node version an alias with nvm&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;These are the main commands you’ll probably use to download and switch between Node.js versions while doing local web development. At least, they’re the ones I use most of the time.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/nvm-sh/nvm#table-of-contents&quot;&gt;nvm documentation&lt;/a&gt; though, is pretty good and it goes into real depth if you want to get fancy with your nvm-ing.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Node versions are something we rarely think about until they become a problem during development. And if your situation is at all similar to mine, you may need to switch between multiple versions regularly, because your various web apps demand it.&lt;/p&gt;
&lt;p&gt;Node Version Manager makes it incredibly easy to do this right from the command line. From installation to actual use, nvm is simple, and it makes development in whatever version of Node.js that’s required, so much simpler as well. I hope you’ll take advantage of it.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about the useful things I learned while building this project in addition to other topics on JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope nvm can be useful to you and your development team when you’re writing your various JavaScript applications.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;nvm, GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>nvm</category></item><item><title>How ESLint Makes Me a Better React Developer</title><link>https://www.paigeniedringhaus.com/blog/how-eslint-makes-me-a-better-react-developer/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/how-eslint-makes-me-a-better-react-developer/</guid><description>JavaScript&apos;s loose standards are a blessing and a curse.</description><pubDate>Sun, 17 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/eslint-success-kid.webp&quot; alt=&quot;No ESLint errors success kid&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Clean-er code: the wake up call&lt;/h2&gt;
&lt;p&gt;I was a little late to the React party, I only started learning it in earnest, about 10 months ago. Yes, I’d heard about it long before then. Yes, I’d had co-workers, casual acquaintances, and the two developers putting out my web dev podcast of choice, &lt;a href=&quot;https://syntax.fm/&quot;&gt;Syntax&lt;/a&gt;, tell me how great it was. Yes, I’d heard Facebook, which at that time had yet to reveal of its less-than-savory-doings, had created it, and kept improving on it.&lt;/p&gt;
&lt;p&gt;But as anyone who’s been a web developer for longer than six months knows, there’s an absolute ton of JavaScript frameworks out there that had a brief moment in the sun, only to be obscured weeks or month later by the new hotness. So I sat on my hands, waited to see if React was worth investing my time in learning, and laughed every time this meme came across my Internet feeds.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/oreilly-meme.webp&quot; alt=&quot;Parody O&apos;Reilly cover&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This image still makes me smile whenever I see it. O’Reilly parody covers are the best.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;When it became apparent that React was the new JavaScript powerhouse of choice and wasn’t going away anytime soon, I finally got on board and started teaching it to myself. For the past 10 months or so, I’ve been learning React on the side while supporting an AngularJS 1.5 application at my current company.&lt;/p&gt;
&lt;p&gt;And having to work with that monolithic, two-way data binding, AngularJS application, chock full of business logic, while building smaller, cleaner, unidirectional data flow, React side projects reinforced what every one else had been telling me all along. React is way better.&lt;/p&gt;
&lt;p&gt;Recently, I was feeling pretty good about my own React / JavaScript knowledge and coding abilities. By no means am I an expert, nor have I used some of React’s most recent advancements like Hooks, but I can talk knowledgeably about state and props. I can discuss different lifecycle render methods and what they’re good for. Heck, I can even debate Redux versus the Context API for state management, and why things like defined prop types are beneficial.&lt;/p&gt;
&lt;p&gt;I’ve written a &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;full-stack, user registration&lt;/a&gt; app as a learning tool and I am proud of it. It’s React and ES6 on the front end, Node.js on the backend, and a MySQL database with the &lt;a href=&quot;./sequelize-like-mongoose-but-for-sql&quot;&gt;Sequelize ORM to handle database interactions&lt;/a&gt;. I implemented &lt;a href=&quot;./implementing-json-web-tokens-passport-js-in-a-react-app&quot;&gt;Passport.js middleware for JWT authentication&lt;/a&gt; and Docker Compose to &lt;a href=&quot;./using-docker-docker-compose-to-improve-your-full-stack-app-development&quot;&gt;spin the whole application up&lt;/a&gt; at once. I also added in &lt;a href=&quot;./password-reset-emails-in-your-react-app-made-easy-with-nodemailer&quot;&gt;password reset via email&lt;/a&gt; functionality with Nodemailer and &lt;a href=&quot;./setting-up-swagger-to-api-test-in-a-java-script-application&quot;&gt;Swagger API&lt;/a&gt; endpoint testing.&lt;/p&gt;
&lt;p&gt;I’ve done a lot with this little app, learned a lot along the way, and written a lot of articles about my learnings (all linked above). But then, I added ESLint into my application, thinking it would be a good way to make sure my code was well written...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And once again, I was humbled and taught how to write better JavaScript code. That’s what I want to talk about today: how ESLint can make me (and you) a better developer.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;ESLint: 21st century rules for ES6 JavaScript &amp;amp; beyond&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/eslint-logo.webp&quot; alt=&quot;ESLint logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;What is ESLint?&lt;/h3&gt;
&lt;p&gt;If you’re not familiar with &lt;a href=&quot;https://eslint.org/&quot;&gt;&lt;strong&gt;ESLint&lt;/strong&gt;&lt;/a&gt;, you can read this &lt;a href=&quot;./keep-code-consistent-across-developers-the-easy-way-with-prettier-es-lint&quot;&gt;handy post&lt;/a&gt; I wrote a few months ago. The post was more to do with using both ESLint and Prettier in the Visual Studio Code IDE to produce consistent, clean code across development teams with little effort on the part of the developers, but it still explains how ESLint works.&lt;/p&gt;
&lt;p&gt;In a nutshell:&lt;/p&gt;
&lt;p&gt;Linting tools like ESLint allow developers to discover problems with their JavaScript code without executing it. —&lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint site&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ESLint is a file in a project repo called &lt;code&gt;.eslintrc&lt;/code&gt; with a list of linting rules that runs through the project’s JavaScript code and finds problematic patterns or code that don’t adhere to certain style guidelines set forth by those rules. Then it alerts developers so they can fix it the errors.&lt;/p&gt;
&lt;p&gt;It will not (normally) rewrite or reformat code like Prettier. Nor will it tell you if you have bad business logic. But it will tell you if curly braces are missing, return statements are unreachable, or objects / arrays could be destructured, among other things.&lt;/p&gt;
&lt;h3&gt;Why ESLint is awesome&lt;/h3&gt;
&lt;p&gt;This is awesome because not only does ESLint identify ways to make code better, but if you don’t need or don’t agree with certain rules, they can be changed or ignored (either for the line, for the whole file, or for the whole project).&lt;/p&gt;
&lt;p&gt;None of the rules depend on each other, they all function independently, and some rules can even fix the code themselves to fall in line with the prescribed rules.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Airbnb ESLint&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb&quot;&gt;&lt;strong&gt;ESLint rules&lt;/strong&gt; &lt;/a&gt; that Airbnb abides by are considered among many as the gold standard for React applications. They are strict, they are unforgiving and they are thorough. They are so popular, in fact, that Airbnb created their ESLint config as an &lt;a href=&quot;https://www.npmjs.com/package/eslint-config-airbnb&quot;&gt;npm package&lt;/a&gt; that has over 1 million weekly downloads, as I write this article.&lt;/p&gt;
&lt;p&gt;They also have an entire &lt;a href=&quot;https://github.com/airbnb/javascript&quot;&gt;JavaScript style guide&lt;/a&gt; on GitHub that has some very good advice in it for writing code. But that’s a different rabbit hole than the one I’m going down today.&lt;/p&gt;
&lt;p&gt;Since I felt like holding myself to high standards (&lt;em&gt;being a masochist&lt;/em&gt;), I decided to use Airbnb’s ESLint rules as the starting place for my own &lt;code&gt;.eslintrc&lt;/code&gt; file for my full stack JavaScript project. Boy, did I learn a lot when I turned on the linter...&lt;/p&gt;
&lt;h3&gt;Before and after ESLint&apos;s cold, brutally honest linting&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;My ESLint setup &amp;amp; dev dependencies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before I could get linting for my React application going to reveal my own code’s shortcomings, I had to download a few dev dependencies for my &lt;code&gt;package.json&lt;/code&gt; file and set up my &lt;code&gt;.eslintrc&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dev dependencies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I used Create React App to create the initial front end for my full stack application, so I only had a few additional dependencies I needed to add to my &lt;code&gt;package.json&lt;/code&gt; file to make Airbnb’s ESLint config work.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.eslintrc&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Then, once all the package were installed, I set up my &lt;code&gt;.eslintrc&lt;/code&gt; file like this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{  
  &quot;extends&quot;: &quot;airbnb&quot;,  
  &quot;parser&quot;: &quot;babel-eslint&quot;,  
  &quot;env&quot;: 
    {    
      &quot;node&quot;: true,    
      &quot;es6&quot;: true,    
      &quot;browser&quot;: true  
    },  
  &quot;rules&quot;: 
    {    
      &quot;react/jsx-filename-extension&quot;: [1, { &quot;extensions&quot;: [&quot;.js&quot;, &quot;.jsx&quot;] }],    
      &quot;implicit-arrow-linebreak&quot;: &quot;off&quot;,    
      &quot;comma-dangle&quot;: &quot;off&quot;,    
      &quot;indent&quot;: &quot;off&quot;,    
      &quot;no-trailing-spaces&quot;: &quot;off&quot;  
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s really all the setup I did. I added &lt;code&gt;&quot;extends&quot;: &quot;airbnb&quot;&lt;/code&gt; as prescribed by the Airbnb’s documentation, added in that I was transpiling my ES6 code with babel, listed the environments and added a few additional rules to override the Airbnb settings.&lt;/p&gt;
&lt;p&gt;Most of these rules were overwritten because I also use Prettier’s code formatting on save in my VS Code setup, and if I didn’t turn off the rules in ESLint, Prettier would continue to reformat code and break the rules every time I saved a file. A minor inconvenience though.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The rules I set&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I extended the &lt;code&gt;react/jsx-filename-extension&lt;/code&gt; rule to apply to files ending in both &lt;code&gt;.js&lt;/code&gt; and &lt;code&gt;.jsx&lt;/code&gt; because all my files which include JSX end in &lt;code&gt;.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I turned off &lt;code&gt;implict-arrow-linebreak&lt;/code&gt; because Prettier reformatted it on save.&lt;/li&gt;
&lt;li&gt;I turned off &lt;code&gt;comma-dangle&lt;/code&gt;, &lt;code&gt;indent&lt;/code&gt;, and &lt;code&gt;no-trailing-spaces&lt;/code&gt; for the same reason.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Beyond that, there were one-off rules that ESLint highlighted, which I turned off by file or by line when I needed to (such as &lt;code&gt;console.log&lt;/code&gt;). I’m sure you’ll also come upon situations that dictate such exceptions as well.&lt;/p&gt;
&lt;h3&gt;Without ESLint enabled&lt;/h3&gt;
&lt;p&gt;Now, let’s see how my code looked before I enabled ESLint in my project.&lt;/p&gt;
&lt;p&gt;Here’s an example of two of my React components. The first is the home page file, the second is the header bar, which is a reusable component across the whole application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Home.js&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/home-no-eslint.webp&quot; alt=&quot;Code snippet of the home page, no ESLint yet&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This code looks pretty nice and unassuming right? Nothing particularly wrong with it.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This file looks OK at first glance, it seems clean and well formatted. Simple, straightforward. One prop that gets passed to the header bar itself, styling for the buttons comes from other reusable components. All pretty self-explanatory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;HeaderBar.js&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/header-bar-no-eslint.webp&quot; alt=&quot;Code snippet of the header bar component, no ESLint yet&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Again, this code looks OK to me...&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The header bar file is much the same. Nice, well known React create class component structure, some props for the header title, a default to fall back to if one wasn’t provided. Seems fine to me.&lt;/p&gt;
&lt;h3&gt;With ESLint enabled&lt;/h3&gt;
&lt;p&gt;Then, I turned on ESLint in my project (all the details on how to do this in VS Code are &lt;a href=&quot;https://itnext.io/keep-code-consistent-across-developers-the-easy-way-with-prettier-eslint-60bb7e91b76c&quot;&gt;here&lt;/a&gt;), and I saw the following horrors on pretty much every file in my project…&lt;/p&gt;
&lt;p&gt;One of the many things I appreciate about the VS Code IDE is that it has its own separate “Problems” tab where all of these ESLint errors show up. And when I hover over all the angry red squiggles or click on any of the errors, I’m directed right in the code to where those errors are. Presumably to fix them (or ignore them if necessary).&lt;/p&gt;
&lt;p&gt;Clicking the little lightbulbs that appear over the angry code will show you what ESLint rule is being broken and give you the option to ignore the rule for the line or whole file or go to the ESLint rule documentation to learn more about how to fix the error.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Home.js&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/home-eslint.webp&quot; alt=&quot;Code snippet of the home page, ESLint errors abound&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;😱 ESLint does not feel the same way about this code that I did. All the things are wrong.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Um…what is going on here? Why are there so many red squigglies everywhere?!?!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Header.js&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/header-bar-eslint.png&quot; alt=&quot;Code snippet of the header bar - the whole thing is an ESLint error&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Ugh, look at all those red lines...&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;😱 And here too? Really?!? Such a simple component, and this is what I see? What gives ESLint??&lt;/p&gt;
&lt;p&gt;After I’d gotten over my initial shock and indignation at ESLint’s very brutal and unforgiving code review, I set to work fixing the errors and learned how to write better React in the process.&lt;/p&gt;
&lt;p&gt;I did it through a combination of reading the &lt;a href=&quot;https://eslint.org/docs/rules/&quot;&gt;ESLint error documentation&lt;/a&gt; (which VS Code’s ESLint lightbulb extension linked me right to) and checking Stack Overflow for examples of how to write things the right way based on the rule being broken.&lt;/p&gt;
&lt;h3&gt;Fixed after ESLint&lt;/h3&gt;
&lt;p&gt;Let’s see what the new pro-ESLint-ed code looks like for the same files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Home.js&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/home-after-eslint.webp&quot; alt=&quot;Code snippet of the home page after fixing the ESLint errors&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;😆 Much nicer. Look — it’s clean, it’s pure and stateless, it’s easier to read.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Here’s what changed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESLint detected this home file was actually a pure, stateless component that didn’t need to be a React class. Instead, it could be written as a &lt;code&gt;const&lt;/code&gt; variable: &lt;code&gt;const Home&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It also identified that the &lt;code&gt;&amp;lt;LinkButtons&amp;gt;&lt;/code&gt; didn’t need curly braces around the &lt;code&gt;buttonText&lt;/code&gt; and &lt;code&gt;link&lt;/code&gt; properties since both properties were defined as string data types prop types in the &lt;code&gt;LinkButtons.js&lt;/code&gt; component file. Here’s what that looks like.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/link-buttons.webp&quot; alt=&quot;Code snippet of the link button props&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s the prop types for &lt;code&gt;LinkButtons&lt;/code&gt; that wasn’t previously defined before ESLint was in play.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You’ll also notice in the code snippet above, the ESLint rule I disabled regarding buttonStyle: &lt;code&gt;// eslint-disable-next-line react/forbid-prop-types&lt;/code&gt;. I did that because ESLint frowns on prop types described only as &lt;code&gt;object&lt;/code&gt; (it wants greater specificity), but since I was using the button styles provided by my React Material styling dependency, I chose not to go deeper in defining the prop types beyond &lt;code&gt;object&lt;/code&gt; in my own prop types.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happily, with these changes, the problems and red squiggles displayed in VS Code, were gone, for this file. And I have to admit, the code does look cleaner than my original React code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;HeaderBar.js&lt;/code&gt; file&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eslint-better-developer/header-bar-after-eslint.webp&quot; alt=&quot;Code snippet of the header bar after fixing the ESLint errors&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Again, looks better. Props and default props are defined, the component is stateless, title is destructured from props object being passed in.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Here’s the header bar reusable component rewritten after ESLint as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This component too, could be written as a stateless, functional component, instead of a React class. It became &lt;code&gt;const HeaderBar&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;ESLint instructed me to use ES6 object destructuring to take just the &lt;code&gt;title&lt;/code&gt; property from the object that I was passing in to the &lt;code&gt;headerBar&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;I had not defined &lt;code&gt;propTypes&lt;/code&gt; or &lt;code&gt;defaultProps&lt;/code&gt; for the component, the kind of &lt;a href=&quot;https://reactjs.org/docs/typechecking-with-proptypes.html&quot;&gt;typechecking&lt;/a&gt; that helps prevent bugs from unnecessarily entering code just because an unexpected JavaScript type was passed as a prop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After these changes were made, my code was deemed acceptable by ESLint’s strict standards.&lt;/p&gt;
&lt;p&gt;Now, imagine if you will, a series of similar errors in pretty much all the files in my code base. But these errors helped me learn how to recognize and write better JavaScript and React code, and for that I am grateful.&lt;/p&gt;
&lt;p&gt;My project was small enough I could go through file by file and fix the issues in just a few sessions, but if are implementing ESLint into a large, already existing code base, it might make more sense to just fix the files you’re currently working on as you implement new features, until all the files can be fixed to adhere to the new ESLint rules. Instead of trying to fix them all in one fell swoop.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;JavaScript is an interpreted language, and it allows developers a lot of leeway that strongly typed languages like Java won’t put up with. Most of the time, I appreciate this flexibility, but it does open up opportunities for bugs strongly typed languages don’t have to deal with.&lt;/p&gt;
&lt;p&gt;As usual, when I started to feel too confident in my JavaScript abilities, ESLint came along and took me down a few notches. But the harshness of the Airbnb linter I view as a good thing.&lt;/p&gt;
&lt;p&gt;It taught me how to better recognize and refactor React classes into stateless components, how to take advantage of ES6 features like object destructuring, and how defining prop types can prevent unnecessary bugs before they happen. It has improved my code and my coding, and will continue to do so in the future.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about React or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this helps convince you to give ESLint a try with your own React and JavaScript projects and improve your own projects and coding abilities.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;GitHub repo of &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;MERN application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Airbnb ESLint, &lt;a href=&quot;https://www.npmjs.com/package/eslint-config-airbnb&quot;&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Airbnb ESLint, &lt;a href=&quot;https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/airbnb/javascript&quot;&gt;Airbnb JavaScript Style Guide&lt;/a&gt;, GitHub&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://syntax.fm/&quot;&gt;Syntax podcast&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category><category>eslint</category><category>self improvement</category></item><item><title>The Case for Standardized Error Handling in Your Web Application’s APIs</title><link>https://www.paigeniedringhaus.com/blog/the-case-for-standardized-error-handling-in-your-web-applications-apis/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/the-case-for-standardized-error-handling-in-your-web-applications-apis/</guid><description>Because bad error messages — or worse, errors invisible to users do no one any favors.</description><pubDate>Sun, 03 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/standardized-errors/error-hero.webp&quot; alt=&quot;Error alert box with success as the message&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Bad error messages are a sin we’re all guilty of as programmers. On the server side, on the client side, they are rampant basically everywhere in web development.&lt;/p&gt;
&lt;p&gt;I write them. You write them. My whole team writes them. We all agree they’re bad: the error messages don’t tell us or our users what the real problem is and only through digging deep into the codebase and tracing through application logs can we locate the actual culprit — most of the time.&lt;/p&gt;
&lt;p&gt;This is not a new or unusual phenomenon. It’s standard, and it makes everyone’s lives infinitely more painful than they need to be. But every time we talk about how to make the error messaging better — more verbose, more pinpointed, less nebulous about what actual error occurred, these efforts to improve error messaging get deprioritized by whoever has the power to direct the dev team and we move on to more straightforward, end-user-benefitting features.&lt;/p&gt;
&lt;p&gt;And the vicious cycle continues. A user encounters an error on client side of the application, the development team is contacted after the error can’t be resolved by turning the system off and on again (see meme below), the devs look through tons of logs and try to reproduce error locally (which is sometimes an impossible feat), the team either reproduces the error and figures out what caused it and how to fix it, or they can’t reproduce the error and close the bug with no fix, until it rears its ugly head again in the future.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/standardized-errors/it-crowd.webp&quot; alt=&quot;Have you tried turning it off and turning it back on again?&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I couldn’t resist the opportunity to use this meme — it’s so accurate sometimes it’s frightening.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Does this sound like an optimum system to you? Me neither. Which is why I’m here, writing to you today.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I’m making the case for standardizing error handling from APIs so we can all stop wasting so much time tracking down bugs, and get back to the coding we all want to do — building cool things that make people’s lives better.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Standardized errors: the need &amp;amp; the ground rules&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/standardized-errors/unhelpful-error-message.webp&quot; alt=&quot;Typically unhelpful error message.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A standard, totally unhelpful, API error message example.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In case you didn’t read the error message above, the part that matters says: &lt;code&gt;Failed to execute ImportKey action in set service. Deleting created cart item. : 500 Internal Server Error&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Yes, this is an actual error message from one of my team’s actual backend web applications. No, it doesn’t make any sort of sense; I totally agree with you.&lt;/p&gt;
&lt;p&gt;In web development, we place a lot of emphasis on the “happy path”. The path that we want and expect our users to take when they’re using our tool or application — it’s the path we code for, the path we optimize for, the path we place most of our focus on.&lt;/p&gt;
&lt;p&gt;The “unhappy path”, is the path when a user doesn’t do the right thing, click the right button, or generally figures out how to use the system in some way other than its intended purpose. This is the path where things go wrong, and with bad error messaging (like the above), we, as both users and developers, have a really hard time figuring out what exactly went wrong. And in general, the unhappy paths (and the errors they produce) are given a lot less thought about how they should be handled in an effective manner.&lt;/p&gt;
&lt;p&gt;That needs to change. Here’s what I propose in the name of better error handling, all of which is based on the &lt;a href=&quot;http://www.odata.org/documentation/&quot;&gt;&lt;strong&gt;OData v4 JSON specification&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;What is OData?&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/standardized-errors/odata-logo.webp&quot; alt=&quot;OData logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Before I give my recommendations, let me give a little background on OData.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OData&lt;/strong&gt; stands for Open Data Protocol, and it is an &lt;a href=&quot;https://en.wikipedia.org/wiki/Protocol_(computing)&quot;&gt;open protocol&lt;/a&gt; which allows the creation and consumption of queryable and interoperable &lt;a href=&quot;https://en.wikipedia.org/wiki/RESTful&quot;&gt;RESTful APIs&lt;/a&gt; in a simple and standard way. &lt;a href=&quot;https://en.wikipedia.org/wiki/Microsoft&quot;&gt;Microsoft&lt;/a&gt; initiated OData in 2007. — &lt;a href=&quot;https://en.wikipedia.org/wiki/Open_Data_Protocol&quot;&gt;Wikipedia, OData&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In essence, OData defines a set of best practices for building and consuming RESTful APIs (application program interface). These practices help developers focus on business logic while building RESTful APIs without having to worry about the various approaches to define things like request and response headers, status codes, HTTP methods, URL conventions, media types, payload formats, query options and more.&lt;/p&gt;
&lt;p&gt;It proposes standards to make web development a little less haphazard and a little more predictable, regardless of programming language or development approach and team.&lt;/p&gt;
&lt;p&gt;Now, we know about OData and its legitimacy and reason for being in the world, let’s get down to the rules of handling errors.&lt;/p&gt;
&lt;h3&gt;8 error rules to follow&lt;/h3&gt;
&lt;p&gt;Below are the standards my team and wider company are working to enact with our applications — they’re generic enough recommendations to apply broadly to APIs in general, but specific enough to remove the questions around how to go about implementing the recommendations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 1: Code one, reusable error handler&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For nonsuccess conditions, developers &lt;em&gt;should&lt;/em&gt; be able to write one piece of code that handles errors consistently across different REST API methods.&lt;/li&gt;
&lt;li&gt;This allows for the building of simple and reliable infrastructure to handle exceptions as a separate flow from successful responses.&lt;/li&gt;
&lt;li&gt;Keep in mind, this error handler is very generic and does not require specific OData constructs. APIs &lt;em&gt;should&lt;/em&gt; use this format even if they are not using other OData constructs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Rule 2: The JSON error handler must have an &lt;code&gt;error&lt;/code&gt; object&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The error response &lt;em&gt;must&lt;/em&gt; be a single JSON object. This object &lt;em&gt;must&lt;/em&gt; have a name/value pair named &lt;code&gt;error&lt;/code&gt;. The value &lt;em&gt;must&lt;/em&gt; be a JSON object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/standardized-errors/basic-error.webp&quot; alt=&quot;Basic error object example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example of the most basic &lt;code&gt;error&lt;/code&gt; object.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 3: &lt;code&gt;error&lt;/code&gt; must contain &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt;, and may contain other properties For more information&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This object &lt;em&gt;must&lt;/em&gt; contain name/value pairs with the names &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt; and it &lt;em&gt;may&lt;/em&gt; contain name/value pairs with the names &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;details&lt;/code&gt;, and &lt;code&gt;innererror&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The value for the &lt;code&gt;code&lt;/code&gt; name/value pair is a language-independent string. Its value is a service-defined error code that &lt;em&gt;should&lt;/em&gt; be human-readable.&lt;/li&gt;
&lt;li&gt;This code serves as a more specific indicator of the error than the HTTP error code specified in the response.&lt;/li&gt;
&lt;li&gt;API Methods &lt;em&gt;should&lt;/em&gt; have a relatively small number (about 20) of possible values for &lt;code&gt;code&lt;/code&gt; and all clients &lt;em&gt;must&lt;/em&gt; be capable of handling all of them.&lt;/li&gt;
&lt;li&gt;Most services will require a much larger number of more specific error codes, which are not interesting to all clients. These error codes &lt;em&gt;should&lt;/em&gt; be exposed in the &lt;code&gt;innererror&lt;/code&gt; name/value pair as described below.&lt;/li&gt;
&lt;li&gt;Introducing a new value for &lt;code&gt;code&lt;/code&gt; that is visible to existing clients is a breaking change and requires a version increase. API Methods can avoid breaking changes by adding new error codes to &lt;code&gt;innererror&lt;/code&gt; instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/standardized-errors/multi-prop-error.webp&quot; alt=&quot;Multi property error object example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example of the &lt;code&gt;error&lt;/code&gt; object with multiple properties included.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 4: The &lt;code&gt;message&lt;/code&gt; should help humans debug the error&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The value for the &lt;code&gt;message&lt;/code&gt; name/value pair &lt;em&gt;must&lt;/em&gt; be a human-readable representation of the error. It is intended as an aid to developers and is not suitable for exposure to end users.&lt;/li&gt;
&lt;li&gt;API methods wanting to expose a suitable message for end users &lt;em&gt;must&lt;/em&gt; do so through an annotation or custom property.&lt;/li&gt;
&lt;li&gt;API methods &lt;em&gt;should not&lt;/em&gt; localize &lt;code&gt;message&lt;/code&gt; for the end user, because doing so &lt;em&gt;may&lt;/em&gt; make the value unreadable to the app developer who may be logging the value, as well as make the value less searchable on the Internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Rule 5: &lt;code&gt;target&lt;/code&gt; is the name of the property in error&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The value for the &lt;code&gt;target&lt;/code&gt; name/value pair is the target of the particular error (e.g., the name of the property in error).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Rule 6: &lt;code&gt;details&lt;/code&gt; is an array of objects with &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The value for the &lt;code&gt;details&lt;/code&gt; name/value pair &lt;em&gt;must&lt;/em&gt; be an array of JSON objects that &lt;em&gt;must&lt;/em&gt; contain name/value pairs for &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt;, and &lt;em&gt;may&lt;/em&gt; contain a name/value pair for &lt;code&gt;target&lt;/code&gt; as described above. The objects in the &lt;code&gt;details&lt;/code&gt; array usually represents distinct, related errors that occurred during the request. See example below.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example of the &lt;code&gt;details&lt;/code&gt; object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{   
  &quot;error&quot;: {     
    &quot;code&quot;: &quot;BadArgument&quot;,     
    &quot;message&quot;: &quot;Multiple errors in ContactInfo data&quot;,     
    &quot;target&quot;: &quot;ContactInfo&quot;,     
    &quot;details&quot;: [       
      {         
        &quot;code&quot;: &quot;NullValue&quot;,         
        &quot;target&quot;: &quot;PhoneNumber&quot;,         
        &quot;message&quot;: &quot;Phone number must not be null&quot;       
      },       
      {         
        &quot;code&quot;: &quot;NullValue&quot;,         
        &quot;target&quot;: &quot;LastName&quot;,         
        &quot;message&quot;: &quot;Last name must not be null&quot;       
      },       
      {         
        &quot;code&quot;: &quot;MalformedValue&quot;,         
        &quot;target&quot;: &quot;Address&quot;,         
        &quot;message&quot;: &quot;Address is not valid&quot;       
       }     
     ]   
   } 
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example there were multiple problems with the request, with each of the individual errors listed in &lt;code&gt;details&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 7: &lt;code&gt;innererror&lt;/code&gt; is an object with service-defined contents&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The value for the &lt;code&gt;innererror&lt;/code&gt; name/value pair &lt;em&gt;must&lt;/em&gt; be an object.&lt;/li&gt;
&lt;li&gt;The contents of this object are service-defined. API methods wanting to return more specific errors than the root-level code &lt;em&gt;must&lt;/em&gt; do so by including a name/value pair for &lt;code&gt;code&lt;/code&gt; and a nested &lt;code&gt;innererror&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each nested &lt;code&gt;innererror&lt;/code&gt; object represents a higher level of detail than its parent.&lt;/li&gt;
&lt;li&gt;When evaluating errors, clients &lt;em&gt;must&lt;/em&gt; traverse through all of the nested &lt;code&gt;innererrors&lt;/code&gt; and choose the deepest one that they understand. This scheme allows services to introduce new error codes anywhere in the hierarchy without breaking backwards compatibility, so long as old error codes still appear.&lt;/li&gt;
&lt;li&gt;The service &lt;em&gt;may&lt;/em&gt; return different levels of depth and detail to different callers. For example, in development environments, the deepest &lt;code&gt;innererror&lt;/code&gt; &lt;em&gt;may&lt;/em&gt; contain internal information that can help debug the service.&lt;/li&gt;
&lt;li&gt;To guard against potential security concerns around information disclosure, services &lt;em&gt;should&lt;/em&gt; take care not to expose too much detail unintentionally.&lt;/li&gt;
&lt;li&gt;Error objects &lt;em&gt;may&lt;/em&gt; also include custom server-defined name/value pairs that &lt;em&gt;may&lt;/em&gt; be specific to the code. Error types with custom server-defined properties &lt;em&gt;should&lt;/em&gt; be declared in the service’s metadata document. See example below.&lt;/li&gt;
&lt;li&gt;Error responses &lt;em&gt;may&lt;/em&gt; contain annotations in any of their JSON objects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/standardized-errors/inner-error.webp&quot; alt=&quot;innererror object example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example of &lt;code&gt;innererror&lt;/code&gt; object.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Example of &lt;code&gt;innererror&lt;/code&gt; object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{   
  &quot;error&quot;: {     
    &quot;code&quot;: &quot;BadArgument&quot;,     
    &quot;message&quot;: &quot;Previous passwords may not be reused&quot;,     
    &quot;target&quot;: &quot;password&quot;,     
    &quot;innererror&quot;: {       
      &quot;code&quot;: &quot;PasswordError&quot;,       
      &quot;innererror&quot;: {         
        &quot;code&quot;: &quot;PasswordDoesNotMeetPolicy&quot;,         
        &quot;minLength&quot;: &quot;6&quot;,         
        &quot;maxLength&quot;: &quot;64&quot;,         
        &quot;characterTypes&quot;:   [&quot;lowerCase&quot;,&quot;upperCase&quot;,&quot;number&quot;,&quot;symbol&quot;],         
        &quot;minDistinctCharacterTypes&quot;: &quot;2&quot;,         
        &quot;innererror&quot;: {           
          &quot;code&quot;: &quot;PasswordReuseNotAllowed&quot;         
        }       
      }     
    }   
  } 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the most basic error code is &lt;code&gt;BadArgument&lt;/code&gt;, but for clients that are interested, there are more specific error codes in &lt;code&gt;innererror&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;PasswordReuseNotAllowed&lt;/code&gt; code may have been added by the service at a later date, having previously only returned &lt;code&gt;PasswordDoesNotMeetPolicy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Existing clients do not break when the new error code is added, but new clients &lt;em&gt;may&lt;/em&gt; take advantage of it. The &lt;code&gt;PasswordDoesNotMeetPolicy&lt;/code&gt; error also includes additional name/value pairs that allow the client to determine the server’s configuration, validate the user’s input programmatically, or present the server’s constraints to the user within the client’s own localized messaging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 8: Code for failure with retries&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is recommended that for any transient errors that may be retried, services &lt;em&gt;should&lt;/em&gt; include a &lt;code&gt;Retry-After&lt;/code&gt; HTTP header indicating the minimum number of seconds that clients &lt;em&gt;should&lt;/em&gt; wait before attempting the operation again.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this concludes the rules to a standardized API error handling strategy. It’s not overly complicated, but it recommends good guidelines to try to adhere to when encountering the unhappy path.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Error messaging isn’t the most fun thing to implement, but it’s even less fun to try and debug a painfully vague (and oftentimes misleading) server message. Standardized error handling is a must — especially if you’re part of a larger team of developers, or providing an API service to external clients.&lt;/p&gt;
&lt;p&gt;Organizations like OData have helped establish best practices around writing and using APIs, which helps developers focus on the business logic of their applications instead. By following these best practices, we’ve established a set of easy to understand and repeatable rules for error handling to make the whole process of dealing with the inevitable unhappy path simpler.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about React or something else related to web development, so please follow me so you don’t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this helps you more effectively handle errors in a standardized format so you can better catch and fix bugs.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.odata.org/documentation/&quot;&gt;OData V4 JSON Specifications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Open_Data_Protocol&quot;&gt;Open Data Protocol&lt;/a&gt;, Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.odata.org/&quot;&gt;OData&lt;/a&gt; docs&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>api</category><category>errors</category><category>programming</category></item><item><title>Setting Up Swagger to API Test In a JavaScript Application</title><link>https://www.paigeniedringhaus.com/blog/setting-up-swagger-to-api-test-in-a-javascript-application/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/setting-up-swagger-to-api-test-in-a-javascript-application/</guid><description>Spring Boot makes Swagger APIs look easy, Node.js not so much.</description><pubDate>Mon, 21 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/swagger-logo.webp&quot; alt=&quot;Swagger logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If you’re like me, and you’ve ever worked with a REST API (application program interface) that doesn’t have a UI attached to it, you’ve probably stumbled more than once wondering what inputs and auth tokens the API needs to give you back the data you’re expecting and not some cryptic 400 HTTP error message.&lt;/p&gt;
&lt;p&gt;Sometimes I’ve got no idea if I need some kind of authorization header (or how to send it), if the API will accept POSTs or PUTs (and what parameters are required versus what’s optional), and if it wants &lt;code&gt;application/json&lt;/code&gt; or some other XML formatted encoding instead.&lt;/p&gt;
&lt;p&gt;Wouldn’t it be nice to be to take some of that uncertainty out of the equation? Wouldn’t it be nice if, instead of being faced with an empty &lt;a href=&quot;https://www.postman.com/&quot;&gt;Postman&lt;/a&gt; or &lt;a href=&quot;https://insomnia.rest/&quot;&gt;Insomnia&lt;/a&gt; API testing application waiting for you to configure it and provide it with everything it needs, an API route told you exactly what it needed? Request body vs. query parameter, integer vs. string, JWT auth header vs. cookie — all of it, just laid out, all the possible routes visible.&lt;/p&gt;
&lt;p&gt;Sounds too good to be true? It’s not.&lt;/p&gt;
&lt;p&gt;Before I joined my current team of developers, I had no idea such a magical API-assistant like this existed, but it does. And it’s called &lt;a href=&quot;https://swagger.io/s&quot;&gt;&lt;strong&gt;Swagger&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, we&apos;ll cover how to set up Swagger inside of a JavaScript or Node.js application and document the actual code so that you can see exactly what REST API routes are available to you and what they need to work in the browser.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I’ll give you all the details below, but here’s an example of what Swagger can provide for your JavaScript web application’s API routes.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/swagger-route-overview.webp&quot; alt=&quot;Swagger dashboard&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Yes, your API too can be this lovely, alphabetized and color-coded with Swagger’s help.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Meet Swagger, your API&apos;s new friend&lt;/h2&gt;
&lt;p&gt;Swagger’s Wikipedia page sums up what it is best:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Swagger is an open-source software framework backed by a large ecosystem of tools that helps developers design, build, document, and consume &lt;a href=&quot;https://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;RESTful Web services&lt;/a&gt;. While most users identify Swagger by the Swagger UI tool, the Swagger toolset includes support for automated documentation, code generation, and test-case generation. — &lt;a href=&quot;https://en.wikipedia.org/wiki/Swagger_(software)&quot;&gt;Wikipedia, Swagger (software)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If this doesn’t make total sense now, read on. It will make sense once you see it in practice.&lt;/p&gt;
&lt;p&gt;One of the loveliest things about &lt;a href=&quot;https://swagger.io/&quot;&gt;&lt;strong&gt;Swagger&lt;/strong&gt;&lt;/a&gt; is the fact that it can be used with most any programming language: from JavaScript to Haskell to Go to C++ to Python to Rust, the list goes on and on. The amount of &lt;a href=&quot;https://github.com/swagger-api/swagger-codegen&quot;&gt;supported languages&lt;/a&gt; is really staggering.&lt;/p&gt;
&lt;p&gt;My first introduction to Swagger was through Java’s Spring Boot applications. By including one line in the &lt;code&gt;build.gradle&lt;/code&gt; dependencies: &lt;code&gt;compile(‘io.springfox:springfox-swagger-ui:2.9.2’)&lt;/code&gt;, one annotation in the Java config files: &lt;code&gt;@EnableSwagger2&lt;/code&gt;, and the location of the &lt;code&gt;swagger.basePackage&lt;/code&gt; in the &lt;code&gt;application.yml&lt;/code&gt;, you’re provided with a beautiful API UI when the Spring Boot application compiles and runs.&lt;/p&gt;
&lt;p&gt;The Swagger UI can be reached by typing in something like http://localhost:8081/swagger-ui.html into the browser. Then, voilà, you’ve got an interactive, browser-based UI for your API service that you can test to your heart’s content.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/java-swagger-ui.webp&quot; alt=&quot;Spring Boot based Swagger&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s an example of what I see when I open up a Spring Boot Swagger HTML page.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Swagger presents a user with the routes in the project, it shows exactly what the shape of the data is and what types of properties are required for each parameter, it lets you know if headers are needed and exactly what kinds they are, if a request body or query param is optional or required, as well as possible HTTP response methods and what each one means. It’s amazing — all that for just three little updates to my Java code.&lt;/p&gt;
&lt;p&gt;It seemed like a piece of cake with Spring Boot, and I (naively) thought it would be just as easy to implement Swagger with my &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;full stack, MERN, JavaScript&lt;/a&gt; application. Silly me…&lt;/p&gt;
&lt;h3&gt;Swagger in JavaScript, there&apos;s an npm package for that, right?&lt;/h3&gt;
&lt;p&gt;Well, the short answer to that question is: yes. The longer answer to that question is: there are many packages. The longest answer is what I’ll tell you now.&lt;/p&gt;
&lt;p&gt;Unlike Spring Boot, which has, what could be considered a defacto Swagger package, the world of JavaScript and Swagger is more fractured and fragmented. From my exploration of npm and the Internet, there didn’t appear to be just one answer to generate Swagger docs and display them in the UI format I’d come to know and love.&lt;/p&gt;
&lt;p&gt;So I read some blogs, read some documentation around &lt;a href=&quot;https://swagger.io/specification/&quot;&gt;OpenAPI specification&lt;/a&gt; (formerly known as Swagger Specification), and upon learning there was no maintained Swagger docs generator for JavaScript, I ultimately decided I would use &lt;a href=&quot;https://www.npmjs.com/package/swagger-jsdoc&quot;&gt;&lt;strong&gt;Swagger JSDoc&lt;/strong&gt;&lt;/a&gt; to create my Swagger documentation for my routes, and combine it with &lt;a href=&quot;https://www.npmjs.com/package/swagger-ui-express&quot;&gt;&lt;strong&gt;Swagger UI Express&lt;/strong&gt;&lt;/a&gt; to generate the UI interface in the browser. Now let me tell you a bit more about each of these modules.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Swagger JSDoc&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once again, &lt;a href=&quot;https://www.npmjs.com/package/swagger-jsdoc&quot;&gt;Swagger JSDoc&lt;/a&gt;’s own words best describe it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;swagger-jsdoc enables you to integrate &lt;a href=&quot;http://swagger.io/&quot;&gt;Swagger&lt;/a&gt; using &lt;a href=&quot;http://usejsdoc.org/&quot;&gt;&lt;code&gt;JSDoc&lt;/code&gt;&lt;/a&gt; comments in your code. Just add &lt;code&gt;@swagger&lt;/code&gt; on top of your DocBlock and declare the meaning of your code in YAML complying to the OpenAPI specification. — &lt;a href=&quot;https://www.npmjs.com/package/swagger-jsdoc&quot;&gt;Swagger JSDoc, npm&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that above each existing API route, you write in your Swagger specs &lt;a href=&quot;https://www.cloudbees.com/blog/yaml-tutorial-everything-you-need-get-started&quot;&gt;YAML-style&lt;/a&gt; (so indentation and colons count) for that route with the &lt;code&gt;@swagger&lt;/code&gt; annotation, and this module will then translate that into the UI rendered by my second module: Swagger UI Express.&lt;/p&gt;
&lt;p&gt;This module is also especially good for already written APIs (which my project happens to be). I was adding in Swagger documentation as an afterthought — not as part of the initial architecture when I first built the app.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the swagger-jsdoc project assumes that you want document your existing/living/working code in a way to &quot;give life&quot; to it, generating a specification which can then be fed into other Swagger tools, and not the vice-versa.— &lt;a href=&quot;https://www.npmjs.com/package/swagger-jsdoc&quot;&gt;Swagger JSDoc&lt;/a&gt;, npm&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If I had decided to add Swagger earlier in the process, I would have looked at &lt;a href=&quot;http://swagger.io/swagger-editor/&quot;&gt;Swagger Editor&lt;/a&gt; or &lt;a href=&quot;http://swagger-node/&quot;&gt;Swagger Node&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Swagger UI Express&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/swagger-ui-express&quot;&gt;Swagger UI Express&lt;/a&gt;&apos;s documentation is much less verbose and involved than Swagger JSDoc, because the challenging part really is the writing of the Swagger specifications.&lt;/p&gt;
&lt;p&gt;As Swagger UI Express’s docs say, it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Adds middleware to your express app to serve the Swagger UI bound to your Swagger document. This acts as living documentation for your API hosted from within your app. — &lt;a href=&quot;https://www.npmjs.com/package/swagger-ui-express&quot;&gt;Swagger UI Express, npm&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically, you follow a prescribed formula to feed the Swagger documentation into the Swagger UI Express module and it generates the HTML UI. And thankfully, the documentation for how to do this is both up to date and accurate. It makes it really simple.&lt;/p&gt;
&lt;p&gt;Now that I’ve given a little more background on the two solutions I chose to make Swagger work with JavaScript, and more specifically, my Express/Node.js server application, it’s time to talk about how to implement it.&lt;/p&gt;
&lt;h3&gt;Let&apos;s set up Swagger in JavaScript, how hard can it be?&lt;/h3&gt;
&lt;p&gt;Once I got the hang of how to write the route specifications, implementing Swagger wasn’t too tough, but to start out with the easiest part, I’ll go over the Swagger UI Express and Swagger JSDoc server setup first.&lt;/p&gt;
&lt;p&gt;If you’d like to download my whole project and run it locally or just see the source code, here’s a link to the &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;&lt;strong&gt;repo&lt;/strong&gt;&lt;/a&gt; or you can click the link of each file name above a code snippet to see it in GitHub.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Server.js setup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/server.js&quot;&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// more JS imports here

import swaggerJSDoc from &apos;swagger-jsdoc&apos;;
import swaggerUi from &apos;swagger-ui-express&apos;;

const app = express();

const API_PORT = process.env.API_PORT || 3000;

const swaggerDefinition = {
  info: {
    title: &apos;MySQL Registration Swagger API&apos;,
    version: &apos;1.0.0&apos;,
    description: &apos;Endpoints to test the user registration routes&apos;,
  },
  host: &apos;localhost:3003&apos;,
  basePath: &apos;/&apos;,
  securityDefinitions: {
    bearerAuth: {
      type: &apos;apiKey&apos;,
      name: &apos;Authorization&apos;,
      scheme: &apos;bearer&apos;,
      in: &apos;header&apos;,
    },
  },
};

const options = {
  swaggerDefinition,
  apis: [&apos;./routes/*.js&apos;],
};

const swaggerSpec = swaggerJSDoc(options);

app.get(&apos;/swagger.json&apos;, (req, res) =&amp;gt; {
  res.setHeader(&apos;Content-Type&apos;, &apos;application/json&apos;);
  res.send(swaggerSpec);
});

app.use(&apos;/api-docs&apos;, swaggerUi.serve, swaggerUi.setup(swaggerSpec));

// more JS code here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, both &lt;code&gt;swaggerJSDoc&lt;/code&gt; and &lt;code&gt;swaggerUiExpress&lt;/code&gt; are imported into the file (this can also be done with require if you choose not to use an ES6 transpiler in Node.js like I did).&lt;/p&gt;
&lt;p&gt;This is where the magic of Swagger UI Express transforms Swagger JSDoc’s swaggerSpec into a nice browser UI.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;swaggerDefinition&lt;/code&gt; object is created (this is part of the setup required by &lt;code&gt;swagger-jsdoc&lt;/code&gt;). Its properties include &lt;code&gt;info&lt;/code&gt; like a &lt;code&gt;title&lt;/code&gt; for the app, a &lt;code&gt;version&lt;/code&gt; and a &lt;code&gt;description&lt;/code&gt;. It also needs a &lt;code&gt;host&lt;/code&gt; (in my case, port 3003 is the port exposed from my Docker container for the API) and a &lt;code&gt;basePath&lt;/code&gt;. Since I also have some routes that are only accessible to the user if they’re logged in with a valid JWT token, I also had to create one &lt;code&gt;securityDefinitions&lt;/code&gt; object with &lt;code&gt;bearerAuth&lt;/code&gt; info: &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;scheme&lt;/code&gt;, and &lt;code&gt;in&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is the &lt;code&gt;swaggerDefinition&lt;/code&gt; code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const swaggerDefinition = {
  info: {
    title: &apos;MySQL Registration Swagger API&apos;,
    version: &apos;1.0.0&apos;,
    description: &apos;Endpoints to test the user registration routes&apos;,
  },
  host: &apos;localhost:3003&apos;,
  basePath: &apos;/&apos;,
  securityDefinitions: {
    bearerAuth: {
      type: &apos;apiKey&apos;,
      name: &apos;Authorization&apos;,
      scheme: &apos;bearer&apos;,
      in: &apos;header&apos;,
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that’s defined, it’s gathered together into another object called &lt;code&gt;options&lt;/code&gt;, which includes the path for your route files. In my case, I have a folder called &lt;code&gt;routes&lt;/code&gt; where they all live, so that’s where I told Swagger to look.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const options = {
  swaggerDefinition,
  apis: [&apos;./routes/*.js&apos;],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, the &lt;code&gt;swaggerSpec&lt;/code&gt; variable is initialized, which wraps the &lt;code&gt;options&lt;/code&gt; object in &lt;code&gt;swaggerJSDoc()&lt;/code&gt;. Then, the Express server is given a route to see the full &lt;code&gt;swagger.json&lt;/code&gt; schema that gets created by the &lt;code&gt;swaggerSpec&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const swaggerSpec = swaggerJSDoc(options);

app.get(&apos;/swagger.json&apos;, function(req, res) {
  res.setHeader(&apos;Content-Type&apos;, &apos;application/json&apos;);
  res.send(swaggerSpec);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But to me, this is secondary to the piece of the code, below, which is what actually combines the &lt;code&gt;swaggerSpec&lt;/code&gt; with the &lt;code&gt;swaggerUi&lt;/code&gt; module that creates the Swagger UI I know and love.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.use(&apos;/api-docs&apos;, swaggerUi.serve, swaggerUi.setup(swaggerSpec));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right, and that’s that. It was a bit more setup than I initially thought, but as I said, the documentation for setting all this up is decent, and if you get stuck, there’s tutorials like this one to help you out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;User schema&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before I could write my routes, referencing my &lt;code&gt;User&lt;/code&gt; object, I needed to go to the actual object declaration file and tell Swagger what made up my user. After that, I’d be able to reference that schema and those defining properties in the different routes to ensure things were copacetic.&lt;/p&gt;
&lt;p&gt;I used Sequelize as the ORM for my MySQL database, so I had a &lt;code&gt;User&lt;/code&gt; schema defined for that reason. If you’d like to learn more about Sequelize, you can read this &lt;a href=&quot;./sequelize-like-mongoose-but-for-sql&quot;&gt;blog post&lt;/a&gt; I wrote.&lt;/p&gt;
&lt;p&gt;Here’s what my &lt;code&gt;user.js&lt;/code&gt; file ended up looking like. Everything between the&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * @swagger 
 * schema definition info goes here...
 */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;is part of the schema definition that will be referenced in my routes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/models/user.js&quot;&gt;&lt;strong&gt;&lt;code&gt;user.js&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable indent */
/**
 * @swagger
 * definitions:
 *   User:
 *     type: object
 *     properties:
 *       id:
 *         type: integer
 *       first_name:
 *         type: string
 *       last_name:
 *         type: integer
 *       email:
 *         type: string
 *       username:
 *         type: string
 *       password:
 *         type: string
 *         format: password
 *       resetPasswordToken:
 *         type: string
 *       resetPasswordExpires:
 *         type: string
 *         format: date-time
 *       required:
 *         - email
 *         - username
 *         - password
 */

module.exports = (sequelize, type) =&amp;gt; sequelize.define(&apos;user&apos;, {
    id: {
      type: type.INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    first_name: type.STRING,
    last_name: type.STRING,
    email: {
      type: type.STRING,
      allowNull: false,
    },
    username: {
      type: type.STRING,
      allowNull: false,
    },
    password: {
      type: type.STRING,
      allowNull: false,
    },
    resetPasswordToken: type.STRING,
    resetPasswordExpires: type.DATE,
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, each of the object’s properties is named ( &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;resetPasswordToken&lt;/code&gt;, etc.), and its data type ( &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;integer&lt;/code&gt;, etc.) is defined right underneath it. The last thing of note is the &lt;code&gt;required&lt;/code&gt; object properties.&lt;/p&gt;
&lt;p&gt;For me, these match the actual &lt;code&gt;User&lt;/code&gt; object’s properties that have the requirement &lt;code&gt;allowNull: false&lt;/code&gt;. That is &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;, and &lt;code&gt;email&lt;/code&gt; for my app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Route schema&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The next thing to cover is writing the Swagger documentation for each of the routes.&lt;/p&gt;
&lt;p&gt;I actually have nine different routes in my application, but I’ll be showing the documentation for three.&lt;/p&gt;
&lt;p&gt;One will be a route requiring no authorization, the second will be one requiring a JWT token for authorization, and the third one will need a different randomly generated string to verify it is legit. I’ll explain that one in more detail when I get there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/loginUser.js&quot;&gt;&lt;code&gt;loginUser.js&lt;/code&gt;&lt;/a&gt; - the unsecured route&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable no-console */
import jwt from &apos;jsonwebtoken&apos;;
import passport from &apos;passport&apos;;
import jwtSecret from &apos;../config/jwtConfig&apos;;
import User from &apos;../sequelize&apos;;

/**
 * @swagger
 * /loginUser:
 *   post:
 *     tags:
 *       - Users
 *     name: Login
 *     summary: Logs in a user
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     parameters:
 *       - name: body
 *         in: body
 *         schema:
 *           $ref: &apos;#/definitions/User&apos;
 *           type: object
 *           properties:
 *             username:
 *               type: string
 *             password:
 *               type: string
 *               format: password
 *         required:
 *           - username
 *           - password
 *     responses:
 *       &apos;200&apos;:
 *         description: User found and logged in successfully
 *       &apos;401&apos;:
 *         description: Bad username, not found in db
 *       &apos;403&apos;:
 *         description: Username and password don&apos;t match
 */

module.exports = app =&amp;gt; {
  app.post(&apos;/loginUser&apos;, (req, res, next) =&amp;gt; {
    passport.authenticate(&apos;login&apos;, (err, users, info) =&amp;gt; {
      if (err) {
        console.error(`error ${err}`);
      }
      if (info !== undefined) {
        console.error(info.message);
        if (info.message === &apos;bad username&apos;) {
          res.status(401).send(info.message);
        } else {
          res.status(403).send(info.message);
        }
      } else {
        req.logIn(users, () =&amp;gt; {
          User.findOne({
            where: {
              username: req.body.username,
            },
          }).then(user =&amp;gt; {
            const token = jwt.sign({ id: user.id }, jwtSecret.secret, {
              expiresIn: 60 * 60,
            });
            res.status(200).send({
              auth: true,
              token,
              message: &apos;user found &amp;amp; logged in&apos;,
            });
          });
        });
      }
    })(req, res, next);
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My first Swagger documentation example is for an unsecured route: my user login route, to be precise. Once again, all the Swagger documentation is written in this fashion, and &lt;strong&gt;be warned: spacing/indentation and colons do matter&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * @swagger
 * documentation for route goes here...
 */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Swagger documentation is written in &lt;a href=&quot;https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html&quot;&gt;YAML syntax&lt;/a&gt;, so it cares about proper indentation for each line and it also cares that there are colons for most lines — if the spacing is off or the colon is missing, the terminal running the Node server code will throw errors until it’s fixed (this tripped me up a few times as I was going through this exercise).&lt;/p&gt;
&lt;p&gt;Here’s the full Swagger documentation for the &lt;code&gt;loginUser()&lt;/code&gt; route.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * @swagger
 * /loginUser:
 *   post:
 *     tags:
 *       - Users
 *     name: Login
 *     summary: Logs in a user
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     parameters:
 *       - name: body
 *         in: body
 *         schema:
 *           $ref: &apos;#/definitions/User&apos;
 *           type: object
 *           properties:
 *             username:
 *               type: string
 *             password:
 *               type: string
 *               format: password
 *         required:
 *           - username
 *           - password
 *     responses:
 *       &apos;200&apos;:
 *         description: User found and logged in successfully
 *       &apos;401&apos;:
 *         description: Bad username, not found in db
 *       &apos;403&apos;:
 *         description: Username and password don&apos;t match
 */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the route is defined first (the actual URL route Swagger will have to hit when it’s run in the browser), then the type of HTTP call is defined ( &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;summary&lt;/code&gt; section appears next to the route in the UI, and it nicely describes what the route is used for.&lt;/p&gt;
&lt;p&gt;If there were numerous different schemas defined, the &lt;code&gt;tags&lt;/code&gt; section would be more useful in organizing different route groups. Since I only have &lt;code&gt;users&lt;/code&gt; it doesn’t really matter much for me.&lt;/p&gt;
&lt;p&gt;In case there’s something besides JSON being produced or consumed, that is defined.&lt;/p&gt;
&lt;p&gt;And then the parameters that the user will input are laid out underneath. Since my JSON is being passed in a request body, &lt;code&gt;in: body&lt;/code&gt; is defined. If it were being passed in the query params it would say &lt;code&gt;in: query&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;The only two properties of the &lt;code&gt;user&lt;/code&gt; object which is defined and referenced with &lt;code&gt;$ref: &apos;#/definitions/User&apos;&lt;/code&gt; are &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt;. Since both are required for this route to work the &lt;code&gt;required&lt;/code&gt; field is set underneath and both properties are referenced (note that must be inline with the &lt;code&gt;schema&lt;/code&gt; column for the required fields to take effect in Swagger).&lt;/p&gt;
&lt;p&gt;Finally, the HTTP responses we can expect from the server are laid out with descriptions of what each one means. They’re pretty self-explanatory.&lt;/p&gt;
&lt;p&gt;Now that I’ve covered an unsecured route, let’s move on to a JWT secured route.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/findUsers.js&quot;&gt;&lt;code&gt;findUser.js&lt;/code&gt;&lt;/a&gt; - the secured route&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable no-console */
import passport from &apos;passport&apos;;
import User from &apos;../sequelize&apos;;

/**
 * @swagger
 * /findUser:
 *   get:
 *     tags:
 *       - Users
 *     name: Find user
 *     summary: Finds a user
 *     security:
 *       - bearerAuth: []
 *     consumes:
 *       - application/json
 *     produces:
 *       - application/json
 *     parameters:
 *       - in: query
 *         name: username
 *         schema:
 *           type: string
 *         required:
 *           - username
 *     responses:
 *       &apos;200&apos;:
 *         description: A single user object
 *         schema:
 *           $ref: &apos;#/definitions/User&apos;
 *       &apos;401&apos;:
 *         description: No auth token / no user found in db with that name
 *       &apos;403&apos;:
 *         description: JWT token and username from client don&apos;t match
 */

module.exports = (app) =&amp;gt; {
  app.get(&apos;/findUser&apos;, (req, res, next) =&amp;gt; {
    passport.authenticate(&apos;jwt&apos;, { session: false }, (err, user, info) =&amp;gt; {
      if (err) {
        console.log(err);
      }
      if (info !== undefined) {
        console.log(info.message);
        res.status(401).send(info.message);
      } else if (user.username === req.query.username) {
        User.findOne({
          where: {
            username: req.query.username,
          },
        }).then((userInfo) =&amp;gt; {
          if (userInfo != null) {
            console.log(&apos;user found in db from findUsers&apos;);
            res.status(200).send({
              auth: true,
              first_name: userInfo.first_name,
              last_name: userInfo.last_name,
              email: userInfo.email,
              username: userInfo.username,
              password: userInfo.password,
              message: &apos;user found in db&apos;,
            });
          } else {
            console.error(&apos;no user exists in db with that username&apos;);
            res.status(401).send(&apos;no user exists in db with that username&apos;);
          }
        });
      } else {
        console.error(&apos;jwt id and username do not match&apos;);
        res.status(403).send(&apos;username and jwt token do not match&apos;);
      }
    })(req, res, next);
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This route is my &lt;code&gt;findUser&lt;/code&gt; route, it gets triggered after the user has logged in and the profile page component starts to mount on the client side to gather all the user info from the database.&lt;/p&gt;
&lt;p&gt;For this route’s Swagger documentation, once again, it defines the URL path, the post type, the tags, summary, produces / consumes specs, params, etc.&lt;/p&gt;
&lt;p&gt;What’s different is that this route includes the &lt;code&gt;security&lt;/code&gt; field, which is where the &lt;code&gt;securityDefinitions&lt;/code&gt; I set up in the &lt;code&gt;server.js&lt;/code&gt; file come back into play. I am passing a JWT (JSON Web Token) back and forth between my client and server to verify a user’s permissions and authorization, so by including&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * @swagger
 * ...
 * security:
 *   - bearerAuth: []
 * ...
 */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;it secures the route and requires a user to include a JWT before successfully making the call. &lt;code&gt;bearerAuth&lt;/code&gt; is just what I named the object in the &lt;code&gt;server.js&lt;/code&gt; file, it can be named however you please, the two just have to match in the server and route files, so Swagger knows how to form the request correctly.&lt;/p&gt;
&lt;p&gt;Once the JWT token is passed in and the request is sent, the Passport.js middleware I have picks up the authorization header, decodes the JWT token and verifies it’s good. If you’d like to learn more about setting up Passport with a React / Node.js project, you can read my &lt;a href=&quot;./implementing-json-web-tokens-passport-js-in-a-react-app&quot;&gt;blog post&lt;/a&gt; here.&lt;/p&gt;
&lt;p&gt;Here’s the code snippet of the Swagger documentation, I want to point out a couple more things about it that differ from the previous route.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * @swagger
 * /findUser:
 *   get:
 *     tags:
 *       - Users
 *     name: Find user
 *     summary: Finds a user
 *     security:
 *       - bearerAuth: []
 *     consumes:
 *       - application/json
 *     produces:
 *       - application/json
 *     parameters:
 *       - in: query
 *         name: username
 *         schema:
 *           type: string
 *         required:
 *           - username
 *     responses:
 *       &apos;200&apos;:
 *         description: A single user object
 *         schema:
 *           $ref: &apos;#/definitions/User&apos;
 *       &apos;401&apos;:
 *         description: No auth token / no user found in db with that name
 *       &apos;403&apos;:
 *         description: JWT token and username from client don&apos;t match
 */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aside from the &lt;code&gt;security&lt;/code&gt; option, the other difference is in the parameters. As I mentioned in the previous route, if the user input is coming through the request’s query parameters, instead of the request body, the parameters look just a smidge different.&lt;/p&gt;
&lt;p&gt;Here’s the piece to focus on — under &lt;code&gt;parameters&lt;/code&gt; the &lt;code&gt;-in&lt;/code&gt; field becomes &lt;code&gt;query&lt;/code&gt; instead of &lt;code&gt;body&lt;/code&gt;. This tells Swagger to pass whatever properties are needed in the query params of the request.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/** 
 * @swagger
 * ...
 * parameters:
 *   - in: query
 * ...
 */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other thing to notice is in the &lt;code&gt;responses&lt;/code&gt; section at the bottom of the documentation. For the 200 HTTP response, it actually produces an &lt;code&gt;application/json&lt;/code&gt; object that holds all the user information. I need to reference the User schema so that Swagger understands how to map the response object it receives without having to write out all the object properties again.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/** 
* @swagger 
* ...
*     responses:
*       200:
*         description: A single user object
*         schema:
*           $ref: &apos;#/definitions/User&apos; 
* ...
*/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Good, now I’ve detailed a secure route and an unsecured route with Swagger, now it’s time for a third, slightly different route. One that coincides with a password reset email.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/resetPassword.js&quot;&gt;&lt;code&gt;resetPassword.js&lt;/code&gt;&lt;/a&gt; - the randomly generated string route&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable no-console */
/* eslint-disable max-len */
import Sequelize from &apos;sequelize&apos;;
import User from &apos;../sequelize&apos;;

// eslint-disable-next-line prefer-destructuring
const Op = Sequelize.Op;

/**
 * @swagger
 * /reset:
 *   get:
 *     tags:
 *       - Users
 *     name: Reset Password Link
 *     summary: Create validation string in reset password link to verify user&apos;s allowed to reset their password
 *     consumes:
 *       - application/json
 *     parameters:
 *       - name: resetPasswordToken
 *         in: query
 *         schema:
 *           type: string
 *         required:
 *           - resetPasswordToken
 *     responses:
 *       &apos;200&apos;:
 *         description: User&apos;s password reset link is valid
 *       &apos;403&apos;:
 *         description: Password reset link is invalid or has expired
 */

module.exports = (app) =&amp;gt; {
  app.get(&apos;/reset&apos;, (req, res) =&amp;gt; {
    User.findOne({
      where: {
        resetPasswordToken: req.query.resetPasswordToken,
        resetPasswordExpires: {
          [Op.gt]: Date.now(),
        },
      },
    }).then((user) =&amp;gt; {
      if (user == null) {
        console.error(&apos;password reset link is invalid or has expired&apos;);
        res.status(403).send(&apos;password reset link is invalid or has expired&apos;);
      } else {
        res.status(200).send({
          username: user.username,
          message: &apos;password reset link a-ok&apos;,
        });
      }
    });
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the last route example I’ll cover here, if you’d like to see all my routes (which include all of the basic CRUD-functionality and then some), you can see my &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I include this because this route actually requires a non-expired, randomly generated string which is sent in the body of an email to a user if they’ve forgotten their login password. It’s a little different and a little tricky, so I thought it was worth going over.&lt;/p&gt;
&lt;p&gt;If you’d like to read more about sending password reset emails using Node, you can see &lt;a href=&quot;./password-reset-emails-in-your-react-app-made-easy-with-nodemailer&quot;&gt;this blog&lt;/a&gt; I wrote.&lt;/p&gt;
&lt;p&gt;Here’s the code snippet of the Swagger documentation below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * @swagger
 * /reset:
 *   get:
 *     tags:
 *       - Users
 *     name: Reset Password Link
 *     summary: Create validation string in reset password link to verify user&apos;s allowed to reset their password
 *     consumes:
 *       - application/json
 *     parameters:
 *       - name: resetPasswordToken
 *         in: query
 *         schema:
 *           type: string
 *         required:
 *           - resetPasswordToken
 *     responses:
 *       &apos;200&apos;:
 *         description: User&apos;s password reset link is valid
 *       &apos;403&apos;:
 *         description: Password reset link is invalid or has expired
 */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s really not any big differences that you can see, but you will notice, under the &lt;code&gt;parameters&lt;/code&gt; the &lt;code&gt;in&lt;/code&gt; references a &lt;code&gt;query&lt;/code&gt; param agin, meaning that the random string attached the URL link that’s sent to a user’s email address will need to be included to verify the password reset is authorized.&lt;/p&gt;
&lt;p&gt;I’ll show this one in the testing section, and it should make more sense there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summing it up&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now, you have seen how to setup both &lt;code&gt;swagger-jsdoc&lt;/code&gt; and &lt;code&gt;swagger-ui-express&lt;/code&gt; in a JavaScript project. I modified the main &lt;code&gt;server.js&lt;/code&gt; file, added a data model to the &lt;code&gt;User&lt;/code&gt; object schema and wrote Swagger documentation for three separate Node.js routes.&lt;/p&gt;
&lt;p&gt;To get to this point, I ended up referencing the &lt;a href=&quot;https://swagger.io/docs/specification/about/&quot;&gt;OpenAPI Specification docs&lt;/a&gt; a lot and the documentation around both npm modules. Don’t be afraid to use either — they’re actually pretty darn good, and there’s a ton of stuff you can add to make your Swagger docs even more helpful.&lt;/p&gt;
&lt;p&gt;Ok, that’s finished. Let’s move on to testing the API in the browser.&lt;/p&gt;
&lt;h3&gt;Testing Swagger in the browser&lt;/h3&gt;
&lt;p&gt;Testing the API in the browser via Swagger was actually a very good exercise for me, because it uncovered some logic flaws I was making in my code, and it forced me to rethink how I was handling certain situations (like sending error codes and messages from the server to the client).&lt;/p&gt;
&lt;p&gt;So, first things first, fire up the whole application or the API individually, whichever you choose. I like to just load the whole thing, because I wrote a single &lt;code&gt;docker-compose.yml&lt;/code&gt; file which takes care of it all by writing &lt;code&gt;docker-compose up&lt;/code&gt; in the terminal after the initial &lt;code&gt;docker-compose build&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once the API gets up and running, you can access the in-browser interface, by putting this URL in: http://localhost:3003/api-docs/ — at least, that’s the external port my API’s Docker container is running on, and the &lt;code&gt;/ api-docs/&lt;/code&gt; URL path is what I specified in the &lt;code&gt;server.js&lt;/code&gt; Swagger UI Express setup.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.use(&apos;/api-docs&apos;, swaggerUi.serve, swaggerUi.setup(swaggerSpec));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you used something different, reference that URL route instead.&lt;/p&gt;
&lt;p&gt;Now, if all goes according to plan, you should see a screen like this.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/swagger-route-overview.webp&quot; alt=&quot;Swagger dashboard&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is what my Swagger interface looks like when I first hit the URL.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;At this point, you can click any of the links and test out your API endpoints. I’m going to test my &lt;code&gt;/loginUser&lt;/code&gt; endpoint first.&lt;/p&gt;
&lt;p&gt;So I click that post, click the &lt;strong&gt;“Try It Out”&lt;/strong&gt; button in the top right of the expanded view, and then replace the two &quot;string&quot; placeholders with a valid username and password (which would be created in the database using the &lt;code&gt;/registerUser&lt;/code&gt; route), and hit the big blue &lt;strong&gt;&quot;Execute&quot;&lt;/strong&gt; button below.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/register-user-route.webp&quot; alt=&quot;Swagger registerUser route&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Filling out the request body (note the &quot;*required&quot; next to the body).&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As the image above shows our request body inputs are required (&quot;*required&quot;), so if they’re left as empty string, you’ll get back a 403 &quot;Missing Credentials&quot; response from the API.&lt;/p&gt;
&lt;p&gt;All the response codes I’ve written out in the Swagger documentation are there to decipher what just happened. Here’s what a successful, 200 HTTP login response looks like.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/register-user-response.webp&quot; alt=&quot;Swagger registerUser response&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A successful, 200 HTTP response.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;When a valid username and password are entered in, which you can see from the &lt;code&gt;cURL&lt;/code&gt; request box which shows you exactly what the call was to the API (helpful when debugging calls that aren’t working), the &lt;code&gt;/loginUser&lt;/code&gt; route gives back a response body object with a &lt;code&gt;token&lt;/code&gt; property that is the JWT token that will be stored in the client’s local storage and passed back in the authorization headers for every secured route call.&lt;/p&gt;
&lt;p&gt;I’ll show now how to test one of those routes. I’ll use the &lt;code&gt;/findUser&lt;/code&gt; route. First, copy the value from the &lt;code&gt;token&lt;/code&gt; property returned from the login endpoint, then open up the &lt;code&gt;/findUser&lt;/code&gt; input, and click the little lock in the top right hand of the input box. This will open up a modal for you to input the JWT token string.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/jwt-input.webp&quot; alt=&quot;Swagger JWT input modal&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;JWT authorization modal.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In here in the &quot;Value&quot; input box enter JWT &lt;code&gt;&amp;lt;token string&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/jwt-input-filled.webp&quot; alt=&quot;Swagger JWT input modal filled in with JWT token&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Add in &lt;code&gt;JWT &amp;lt;token string&amp;gt;&lt;/code&gt; in the input box and hit the &quot;Authorize&quot; button.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;For my particular application, the Authorization header that goes with each request, needs the &lt;code&gt;JWT&lt;/code&gt; ahead of the actual JWT string. That reference is how Passport finds the correct header string to decode and verify if the user’s authorized. &lt;em&gt;It must be included in this format for this API call to work.&lt;/em&gt; After this is done, click the &lt;strong&gt;&quot;Authorize&quot;&lt;/strong&gt; button, then the little lock icon will be locked for this route and you can fill out the user info and test your call.&lt;/p&gt;
&lt;p&gt;This is what a 200 HTTP response on this secured route will look like.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/jwt-success-response.webp&quot; alt=&quot;Successful response for JWT authorized route&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A successful call to the secured route using a JWT token in the &quot;Authorization&quot; header.
&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;cURL&lt;/code&gt; request box shows the route with the username query parameter and it shows the authorization JWT token I entered in the lock on the route, which is needed to return the &lt;code&gt;User&lt;/code&gt; object. Without the JWT token, or with an invalid token the 401 or 403 HTTP responses would be sent instead.&lt;/p&gt;
&lt;p&gt;The final request I’ll show is a Swagger request that deals with a password reset email (which I wrote about implementing &lt;a href=&quot;./password-reset-emails-in-your-react-app-made-easy-with-nodemailer&quot;&gt;here&lt;/a&gt;). That one’s a bit fiddly because the URL link that’s sent to the user’s email address to reset the password contains the query string needed to verify its validity AND it’s only good for the next 10 minutes.&lt;/p&gt;
&lt;p&gt;So, if a user was to send a password reset email to their inbox, they’d receive an email with the link like the image below.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/password-reset-email.webp&quot; alt=&quot;Email password reset&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The reset email the user receives — the random string at the end is what will be needed for Swagger.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;From here, the user would need to copy the string after the &lt;code&gt;/reset/&lt;/code&gt; and paste that into the swagger &lt;code&gt;/reset&lt;/code&gt; route within 10 minutes of it being sent. This randomly generated string has a timestamp attached to it, and part of the authorization involves checking the string and the timestamp against the database.&lt;/p&gt;
&lt;p&gt;If both are valid for that user, here’s what a successful verification through Swagger would look like.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/reset-route-success.webp&quot; alt=&quot;Swagger reset route 200&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The successful 200 response to verify the password reset token for this user is valid, which allows them to reach the secured route to reset their password.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If the string is invalid or the link had expired, instead Swagger would show this message.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/swagger-javascript/reset-route-denied.webp&quot; alt=&quot;Swagger reset route 403&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The 403 error a user would get if s/he were to submit a password reset token that was either invalid or had expired.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And that, my friends, is how you can test your API using Swagger’s handy interface in the browser.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is how to implement Swagger in your JavaScript or Node.js application for in-browser API testing. The initial setup isn’t quite as easy as Spring Boot makes it, but for an interpreted language like JavaScript, it really wasn’t that hard, once I got the hang of it.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this helps you more easily document and test your own web apps.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;MERN JavaScript app repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://swagger.io/&quot;&gt;Swagger&lt;/a&gt; site documentation&lt;/li&gt;
&lt;li&gt;Swagger, &lt;a href=&quot;https://en.wikipedia.org/wiki/Swagger_(software)&quot;&gt;Wikipedia article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://swagger.io/docs/specification/about/&quot;&gt;OpenAPI Specifications&lt;/a&gt; (Swagger Specification)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/swagger-jsdoc&quot;&gt;Swagger JSDoc, npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/swagger-ui-express&quot;&gt;Swagger UI Express, npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cloudbees.com/blog/yaml-tutorial-everything-you-need-get-started&quot;&gt;YAML syntax&lt;/a&gt; reference&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>nodejs</category><category>javascript</category><category>swagger</category><category>api</category><category>testing</category></item><item><title>Using Java to Read Really, Really Large Files</title><link>https://www.paigeniedringhaus.com/blog/using-java-to-read-really-really-large-files/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/using-java-to-read-really-really-large-files/</guid><description>This is the kind of stuff Java was made for.</description><pubDate>Fri, 04 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-java-on-large-datasets/java-logo-hero.webp&quot; alt=&quot;Java logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Anyone who knows me fairly well in my programming life will know that I’m not as partial to Java.&lt;/p&gt;
&lt;p&gt;I’m a JavaScript developer first and foremost. It was what I learned first, it confounded then delighted me after I started to get the hang of it, and it made a heck of a lot more sense to me than Java, what with its compilation, its need to declare every single variable type (yes, I know the latest versions of Java have done away with this requirement for some of the simpler inferences), and its massive libraries of maps, lists, collections, etc.: HashMaps, Maps, HashTables, TreeMaps, ArrayLists, LinkedLists, Arrays, it goes on and on.&lt;/p&gt;
&lt;p&gt;That being said, I do make an effort to get better at Java and the other shortcomings I have by not having a traditional computer science degree. If you’d like to know more about my atypical path to becoming a software engineer, you can read my very first blog post &lt;strong&gt;&lt;a href=&quot;./how-i-went-from-a-digital-marketer-to-a-software-engineer-in-4-months&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So when I told a colleague of mine about a coding challenge I’d come across a couple months back and how I &lt;strong&gt;&lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;solved it&lt;/a&gt;&lt;/strong&gt; (and then &lt;strong&gt;&lt;a href=&quot;./streams-for-the-win-a-performance-comparison-of-node-js-methods-for-reading-large-datasets-pt-2&quot;&gt;performance tested&lt;/a&gt;&lt;/strong&gt; my various solutions) in JavaScript, he looked back at me and said: “How would you solve it using Java?”&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-java-on-large-datasets/ill-get-back-to-you.webp&quot; alt=&quot;Well, let me get back to you on that.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;My initial reaction to the question of using Java.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I stared at him as the wheels began to turn in my head, and I accepted the challenge to find an optimal solution in Java, as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this post, I&apos;ll show you a variety of solutions (and their performance) to parse through really, really large datasets using the Java programming language.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The challenge I faced&lt;/h2&gt;
&lt;p&gt;So before I get down to how I solved my challenge using Java, let me actually recap the requirements.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;original article&lt;/a&gt; I wrote on using Node.js to read really, really large files, this was a coding challenge issued to a developer for an insurance technology company.&lt;/p&gt;
&lt;p&gt;The challenge was straightforward enough: download this large zip file of text from the Federal Elections Commission, read that data out of the &lt;code&gt;.txt&lt;/code&gt; file supplied, and supply the following info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a program that will print out the total number of lines in the file.&lt;/li&gt;
&lt;li&gt;Notice that the 8th column contains a person’s name. Write a program that loads in this data and creates an array with all name strings. Print out the 432nd and 43243rd names.&lt;/li&gt;
&lt;li&gt;Notice that the 5th column contains a form of date. Count how many donations occurred in each month and print out the results.&lt;/li&gt;
&lt;li&gt;Notice that the 8th column contains a person’s name. Create an array with each first name. Identify the most common first name in the data and how many times it occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Link to the data: ​https://www.fec.gov/files/bulk-downloads/2018/indiv18.zip*&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: I add the asterisk after the file link because others who have chosen to undertake this challenge themselves have actually seen the file size increase since I downloaded it back in the beginning of October of 2018. At last count, someone mentioned it was up to 3.5GB now, so it seems as if this data is still live and being added to all the time. I believe the solutions I present below will still work though, but your counts and numbers will vary from mine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I liked the challenge and wanted some practice manipulating files, so I decided to see if I could figure it out.&lt;/p&gt;
&lt;p&gt;Now, without further ado, let’s talk about some different solutions I came up with to read really, really large files in Java.&lt;/p&gt;
&lt;h2&gt;The three Java-based solutions I came up with&lt;/h2&gt;
&lt;p&gt;Java has long been a standard programming language with file processing capabilities, and as such, there’s been a large number of ever improving ways to read, write and manipulate files with it.&lt;/p&gt;
&lt;p&gt;Some methods are baked straight into the core Java framework, and some are still independent libraries that need to be imported and bundled together to run. But regardless, I came up with three different methods to read files in Java, and then I performance tested them to see which methods were more efficient.&lt;/p&gt;
&lt;p&gt;Below are snippets of various pieces of code, if you’d like to see all of the original code, you can access my &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/read-file-java&quot;&gt;Github repo here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You’ll notice that I used the same code logic to extract the data from each file, the major differences are between the initial file connection and text parsing. I did this so that I could have a more accurate idea of how the different methods stacked up against each other for the performance part of my evaluation. Apples to apples comparisons and all that.&lt;/p&gt;
&lt;h3&gt;Solution #1: Java &lt;code&gt;FileInputStream()&lt;/code&gt; and &lt;code&gt;Scanner()&lt;/code&gt; Implementation&lt;/h3&gt;
&lt;p&gt;The first solution I came up with uses Java’s built-in &lt;strong&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/?java/io/FileInputStream.html&quot;&gt;&lt;code&gt;FileInputStream()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; method combined with &lt;strong&gt;&lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html&quot;&gt;&lt;code&gt;Scanner()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In essence, FileInputStream just opens the connection to the file to be read, be it images, characters, etc. It doesn’t particularly care what the file actually is, because Java reads the input stream as raw bytes of data. Another option (at least for my case) is to use &lt;code&gt;FileReader()&lt;/code&gt; which is specifically for reading streams of characters, but I went with &lt;code&gt;FileInputStream()&lt;/code&gt; for this particular scenario. I used &lt;code&gt;FileReader()&lt;/code&gt; in another solution I tested later on.&lt;/p&gt;
&lt;p&gt;Once the connection to the file is established, Scanner comes into play to actually parse the text bytes into strings of readable data. &lt;code&gt;Scanner()&lt;/code&gt; breaks its inputs into tokens using a delimiter pattern, which by default matches whitespace (but can also be overridden to use regex or other values). Then, by using the &lt;code&gt;Scanner.hasNextLine()&lt;/code&gt; boolean, and the &lt;code&gt;Scanner.nextLine()&lt;/code&gt; method, I can read the contents of the text file line by line and pull out the pieces of data that I need.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Scanner.nextLine()&lt;/code&gt; actually advances this scanner past the current line and returns the input that was skipped, which is how I’m able to gather the required info from each line until there’s no more lines to read and &lt;code&gt;Scanner.hasNextLine()&lt;/code&gt; returns false and the while loop ends.&lt;/p&gt;
&lt;p&gt;Here’s a sample of code using &lt;code&gt;FileInputStream()&lt;/code&gt; and &lt;code&gt;Scanner()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;File f = new File(&quot;src/main/resources/config/test.txt&quot;);

try {
   FileInputStream inputStream = new FileInputStream(f);
   Scanner sc = new Scanner(inputStream, &quot;UTF-8&quot;);
   // do some things ...
   while (sc.hasNextLine()) {
      String line = sc.nextLine();
     //  do some more things ...
   } 
  // do some final things
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is my full code to solve all the tasks laid out above.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Click the title of any of these files to go to GitHub and see the full working code repo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/read-file-java/blob/master/src/main/java/com/example/readFile/readFileJava/ReadFileJavaApplicationFileInputStream.java&quot;&gt;&lt;code&gt;ReadFileJavaApplicationFileInputStream.java&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.example.readFile.readFileJava;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;

public class ReadFileJavaApplicationFileInputStream {

	public static void main(String[] args) throws IOException {
    File f = new File(Common.getPathToTargetFile(args));

    try {
      FileInputStream inputStream = new FileInputStream(f);
      Scanner sc = new Scanner(inputStream, &quot;UTF-8&quot;);

      // get total line count
      Instant lineCountStart = Instant.now();
      int lines = 0;

      Instant namesStart = Instant.now();
      ArrayList&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();

      // get the 432nd and 43243 names
      ArrayList&amp;lt;Integer&amp;gt; indexes = new ArrayList&amp;lt;&amp;gt;();

      indexes.add(1);
      indexes.add(433);
      indexes.add(43244);

      // count the number of donations by month
      Instant donationsStart = Instant.now();
      ArrayList&amp;lt;String&amp;gt; dates = new ArrayList&amp;lt;&amp;gt;();

      // count the occurrences of first name
      Instant commonNameStart = Instant.now();
      ArrayList&amp;lt;String&amp;gt; firstNames = new ArrayList&amp;lt;&amp;gt;();


      System.out.println(&quot;Reading file using File Input Stream&quot;);

      while (sc.hasNextLine()) {
        String line = sc.nextLine();
        lines++;

        // get all the names
        String array1[] = line.split(&quot;\\s*\\|\\s*&quot;);
        String name = array1[7];
        names.add(name);
        if (indexes.contains(lines)) {
          System.out.println(&quot;Name: &quot; + names.get(lines - 1) + &quot; at index: &quot; + (lines - 1));
        }

        if (name.contains(&quot;, &quot;)) {

          String array2[] = (name.split(&quot;, &quot;));
          String firstHalfOfName = array2[1].trim();

          if (!firstHalfOfName.isEmpty()) {
            if (firstHalfOfName.contains(&quot; &quot;)) {
              String array3[] = firstHalfOfName.split(&quot; &quot;);
              String firstName = array3[0].trim();
              firstNames.add(firstName);
            } else {
              firstNames.add(firstHalfOfName);
            }
          }
        }

        String rawDate = array1[4];
        String month = rawDate.substring(4, 6);
        String year = rawDate.substring(0, 4);
        String formattedDate = month + &quot;-&quot; + year;
        dates.add(formattedDate);

      }
      sc.close();

      Instant namesEnd = Instant.now();
      long timeElapsedNames = Duration.between(namesStart, namesEnd).toMillis();
      System.out.println(&quot;Name time: &quot; + timeElapsedNames + &quot;ms&quot;);

      System.out.println(&quot;Total file line count: &quot; + lines);
      Instant lineCountEnd = Instant.now();
      long timeElapsedLineCount = Duration.between(lineCountStart, lineCountEnd).toMillis();
      System.out.println(&quot;Line count time: &quot; + timeElapsedLineCount + &quot;ms&quot;);

      HashMap&amp;lt;String, Integer&amp;gt; dateMap = new HashMap&amp;lt;&amp;gt;();
      for (String date : dates) {
        Integer count = dateMap.get(date);
        if (count == null) {
          dateMap.put(date, 1);
        } else {
          dateMap.put(date, count + 1);
        }
      }
      for (Map.Entry&amp;lt;String, Integer&amp;gt; entry : dateMap.entrySet()) {
        String key = entry.getKey();
        Integer value = entry.getValue();
        System.out.println(&quot;Donations per month and year: &quot; + key + &quot; and donation count: &quot; + value);

      }
      Instant donationsEnd = Instant.now();
      long timeElapsedDonations = Duration.between(donationsStart, donationsEnd).toMillis();
      System.out.println(&quot;Donations time: &quot; + timeElapsedDonations + &quot;ms&quot;);

      HashMap&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
      for (String name : firstNames) {
        Integer count = map.get(name);
        if (count == null) {
          map.put(name, 1);
        } else {
          map.put(name, count + 1);
        }
      }

      LinkedList&amp;lt;Entry&amp;lt;String, Integer&amp;gt;&amp;gt; list = new LinkedList&amp;lt;&amp;gt;(map.entrySet());

      Collections.sort(list, new Comparator&amp;lt;Map.Entry&amp;lt;String, Integer&amp;gt;&amp;gt;() {
        public int compare(Map.Entry&amp;lt;String, Integer&amp;gt; o1,
                            Map.Entry&amp;lt;String, Integer&amp;gt; o2) {
          return (o2.getValue()).compareTo(o1.getValue());
        }
      });
      System.out.println(&quot;The most common first name is: &quot; + list.get(0).getKey() + &quot; and it occurs: &quot; + list.get(0).getValue() + &quot; times.&quot;);
      Instant commonNameEnd = Instant.now();
      long timeElapsedCommonName = Duration.between(commonNameStart, commonNameEnd).toMillis();
      System.out.println(&quot;Most common name time: &quot; + timeElapsedCommonName + &quot;ms&quot;);

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the file’s data is being read one line at a time, it’s simply a matter of getting the necessary data and manipulating it to fit my needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Task #1: Get the file’s total line count&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Getting the line count for the entire file was easy. All that involved was a new &lt;code&gt;int lines = 0&lt;/code&gt; declared outside the while loop, which I incremented each time the loop ran again.&lt;/p&gt;
&lt;p&gt;Request #1: done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Task #2: Create a list of all the names and find the 432nd and 43243rd names&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The second request, which was to collect all the names and print the 432nd and 43243rd names from the array, required me to create an &lt;code&gt;ArrayList&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt; and an &lt;code&gt;ArrayList&amp;lt;Integers&amp;gt; indexes = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt; which I promptly added the indexes of 432 and 43243 with &lt;code&gt;indexes.add(433)&lt;/code&gt; and &lt;code&gt;indexes.add(43244)&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;I had to add 1 to each index to get the correct name position in the array because I incremented my line count (starting at 0) as soon as &lt;code&gt;Scanner.hasNextLine()&lt;/code&gt; returned true. After &lt;code&gt;Scanner.nextLine()&lt;/code&gt; returned the previous line’s contents I could pull out the names I needed, which meant its true index (starting from index 0) was actually the index of the line count minus one. (Trust me, I triple checked this to make sure I was doing my math correctly).&lt;/p&gt;
&lt;p&gt;I used an ArrayList for the names because it maintains the element&apos;s insertion order which means while displaying ArrayList elements the result set will always have the same order in which the elements got inserted into the List. Since I’m iterating through the file line by line, the elements will always be inserted into the list in the same order.&lt;/p&gt;
&lt;p&gt;Here’s the full logic I used to get all the names and then print out the names if the indexes I had in my indexes ArrayList matched the lines count index.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int lines = 0;
ArrayList&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();

// get the 432nd and 43243 names
ArrayList&amp;lt;Integer&amp;gt; indexes = new ArrayList&amp;lt;&amp;gt;();

indexes.add(433);
indexes.add(43244);

System.out.println(&quot;Reading file using File Input Stream&quot;);

while (sc.hasNextLine()) {
   String line = sc.nextLine();
   lines++;
   // get all the names
   String array1[] = line.split(&quot;\\s*\\|\\s*&quot;);
   String name = array1[7];
   names.add(name);
   if (indexes.contains(lines)) {
      System.out.println(&quot;Name: &quot; + names.get(lines - 1) + &quot; at
      index: &quot; + (lines - 1));
   } 
   // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Request #2: done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Task #3: Count how many donations occurred in each month&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As I approached the donation counting request, I wanted to do more than count donations by month, I wanted to count them by both month and year, as I had donations from both 2017 and 2018.&lt;/p&gt;
&lt;p&gt;The very first thing I did was set up an initial ArrayList to hold all my dates: &lt;code&gt;ArrayList&amp;lt;String&amp;gt; dates = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, I took the 5th element in each line, the raw date, and used the &lt;code&gt;substring()&lt;/code&gt; method to pull out just the month and year for each donation.&lt;/p&gt;
&lt;p&gt;I reformatted each date into easier-to-read dates and added them to the new &lt;code&gt;dates&lt;/code&gt; ArrayList.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;String rawDate = array1[4];
String month = rawDate.substring(4, 6);
String year = rawDate.substring(0, 4);
String formattedDate = month + &quot;-&quot; + year;
dates.add(formattedDate);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After I’d collected all the dates, I created a HashMap to hold my dates: &lt;code&gt;HashMap&amp;lt;String, Integer&amp;gt; dateMap = new HashMap&amp;lt;&amp;gt;();&lt;/code&gt;, and then looped through the dates list to either add the dates as keys to the HashMap if they didn’t already exist or increment their value count, if they did exist.&lt;/p&gt;
&lt;p&gt;Once the HashMap was made, I ran that new map through another &lt;code&gt;for&lt;/code&gt; loop to get each object’s key and value to print out to the console. Voilà.&lt;/p&gt;
&lt;p&gt;The date results were not sorted in any particular order, but they could be by transforming the HashMap back in to an ArrayList or LinkedList, if need be. I chose not to though, because it was not a requirement.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HashMap&amp;lt;String, Integer&amp;gt; dateMap = new HashMap&amp;lt;&amp;gt;();
for (String date : dates) {
   Integer count = dateMap.get(date);
   if (count == null) {
      dateMap.put(date, 1);
   } else {
      dateMap.put(date, count + 1);
   }
}
for (Map.Entry&amp;lt;String, Integer&amp;gt; entry : dateMap.entrySet()) {
   String key = entry.getKey();
   Integer value = entry.getValue();
   System.out.println(&quot;Donations per month and year: &quot; +
   entry.getKey() + &quot; and donation count: &quot; + entry.getValue());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Request #3: done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Task #4: Identify the most common first name and how often it occurs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The fourth request, to get all the first names only and find the count of the most commonly occurring one, was trickiest.&lt;/p&gt;
&lt;p&gt;It required me to first, check if the &lt;code&gt;names&lt;/code&gt; array contained a comma (there were some business names that had no commas), then &lt;code&gt;split()&lt;/code&gt; the name on the comma and &lt;code&gt;trim()&lt;/code&gt; any extraneous white space from it.&lt;/p&gt;
&lt;p&gt;Once that was cleaned up, I had to check if the first half of the name had any white spaces (meaning the person had a first name and middle name or possibly a moniker like “Ms.”) and if it did, &lt;code&gt;split()&lt;/code&gt; it again, and &lt;code&gt;trim()&lt;/code&gt; up the first element of the newly made array (which I presumed would almost always be the first name).&lt;/p&gt;
&lt;p&gt;If the first half of the name didn’t have a space, it was added to the &lt;code&gt;firstNames&lt;/code&gt; ArrayList as is. That’s how I collected all the first names from the file. See the code snippet below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// count the occurrences of first name
ArrayList&amp;lt;String&amp;gt; firstNames = new ArrayList&amp;lt;&amp;gt;();

System.out.println(&quot;Reading file using File Input Stream&quot;);

    while (sc.hasNextLine()) {
        String line = sc.nextLine();

        // get all the names
        String array1[] = line.split(&quot;\\s*\\|\\s*&quot;);
        String name = array1[7];
        names.add(name);

        if (name.contains(&quot;, &quot;)) {
            String array2[] = (name.split(&quot;, &quot;));
            String firstHalfOfName = array2[1].trim();
  
            if (firstHalfOfName != undefined ||
                !firstHalfOfName.isEmpty()) {
                     if (firstHalfOfName.contains(&quot; &quot;)) {
                       String array3[] = firstHalfOfName.split(&quot; &quot;);
                       String firstName = array3[0].trim();
                       firstNames.add(firstName);
                     } else {
                       firstNames.add(firstHalfOfName);
                     }
                  }
               }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once I’ve collected all the first names I can, and the &lt;code&gt;while&lt;/code&gt; loop reading the file has ended, it’s time to sort the names and find the most common one.&lt;/p&gt;
&lt;p&gt;For this, I created another new HashMap: &lt;code&gt;HashMap&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();&lt;/code&gt;, then looped through all the names and if the name didn’t exist in the map already, it was created as the map’s key and the value was set as 1. If the name already existed in the HashMap, the value was incremented by 1.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HashMap&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
for (String name : firstNames) {
   Integer count = map.get(name);
   if (count == null) {
      map.put(name, 1);
   } else {
      map.put(name, count + 1);
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But wait — there’s more! Once we have the HashMap, which is unordered by nature, it needs to be sorted from largest to smallest value to get the most commonly occurring first name, so I transform each entry in the HashMap into a LinkedList, which can be ordered and iterated through.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LinkedList&amp;lt;Entry&amp;lt;String, Integer&amp;gt;&amp;gt; list = new LinkedList&amp;lt;&amp;gt;(map.entrySet());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, the list is sorted using the &lt;code&gt;Collections.sort()&lt;/code&gt; method, and invoking the &lt;code&gt;Comparator interface&lt;/code&gt; to sort the name objects according to their value counts in descending order (highest value is first). Check this out.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Collections.sort(list, new Comparator&amp;lt;Map.Entry&amp;lt;String, Integer&amp;gt;&amp;gt;()
  {
     public int compare(Map.Entry&amp;lt;String, Integer&amp;gt; o1,
     Map.Entry&amp;lt;String, Integer&amp;gt; o2) {
         return (o2.getValue()).compareTo(o1.getValue());
    }
  }
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once all of that has been done, the first key value pair of the LinkedList can finally be pulled out and displayed to the user. Here’s the whole shebang that’s put together once the all the first names have been read out of the file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HashMap&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
for (String name : firstNames) {
   Integer count = map.get(name);
   if (count == null) {
      map.put(name, 1);
   } else {
      map.put(name, count + 1);
   }
}

LinkedList&amp;lt;Entry&amp;lt;String, Integer&amp;gt;&amp;gt; list = new LinkedList&amp;lt;&amp;gt;(map.entrySet());

Collections.sort(list, new Comparator&amp;lt;Map.Entry&amp;lt;String, Integer&amp;gt;&amp;gt;()
  {
     public int compare(Map.Entry&amp;lt;String, Integer&amp;gt; o1,
     Map.Entry&amp;lt;String, Integer&amp;gt; o2) {
         return (o2.getValue()).compareTo(o1.getValue());
    }
  }
);

System.out.println(&quot;The most common first name is: &quot; + list.get(0).getKey() + &quot; and it occurs: &quot; + list.get(0).getValue() + &quot; times.&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Request #4 (and arguably the most complicated of all the tasks): done.&lt;/p&gt;
&lt;p&gt;Great, now that I’ve given you the soliloquy of my brain’s logic in Java, I can give you much quicker overviews of the other two methods I tried for reading the text data from the files. (Because the logic portion of the code is exactly the same.)&lt;/p&gt;
&lt;h3&gt;Solution #2: Java &lt;code&gt;BufferedReader()&lt;/code&gt; and &lt;code&gt;FileReader()&lt;/code&gt; implementation&lt;/h3&gt;
&lt;p&gt;My second solution involved two more of Java’s core methods: &lt;strong&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html&quot;&gt;&lt;code&gt;BufferedReader()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/?java/io/FileReader.html&quot;&gt;&lt;code&gt;FileReader()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;BufferedReader reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines, and it is wrapped around the FileReader method, which is the actual method reading the specified text file. The BufferedReader makes the FileReader more efficient in its operation, that’s all.&lt;/p&gt;
&lt;p&gt;BufferedReader’s method &lt;code&gt;readLine()&lt;/code&gt; is what actually reads back each line of the text as it is read from the stream, allowing us to pull out the data needed.&lt;/p&gt;
&lt;p&gt;The setup is similar to FileInputStream and Scanner; you can see how to implement BufferedReader and FileReader below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;File f = new File(&quot;src/main/resources/config/test.txt&quot;);

try (BufferedReader b = new BufferedReader(new FileReader(f))) { 
   String readLine = &quot;&quot;;
   // do some things ...
   while ((readLine = b.readLine()) != null) { 
     // do some more things...
   } 
  // do some final things
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is my full code using &lt;code&gt;BufferedReader()&lt;/code&gt; and &lt;code&gt;FileReader()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/read-file-java/blob/master/src/main/java/com/example/readFile/readFileJava/ReadFileJavaApplicationBufferedReader.java&quot;&gt;&lt;code&gt;ReadFileJavaApplicationBufferedReader.java&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.example.readFile.readFileJava;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;

public class ReadFileJavaApplicationBufferedReader {

	public static void main(String[] args) {
		try {
			File f = new File(Common.getPathToTargetFile(args));

			try (BufferedReader b = new BufferedReader(new FileReader(f))) {
				String readLine = &quot;&quot;;

				// get total line count
				Instant lineCountStart = Instant.now();
				int lines = 0;

				Instant namesStart = Instant.now();
				ArrayList&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();

				// get the 432nd and 43243 names
				ArrayList&amp;lt;Integer&amp;gt; indexes = new ArrayList&amp;lt;&amp;gt;();

				indexes.add(1);
				indexes.add(433);
				indexes.add(43244);

				// count the number of donations by month
				Instant donationsStart = Instant.now();
				ArrayList&amp;lt;String&amp;gt; dates = new ArrayList&amp;lt;&amp;gt;();

				// count the occurrences of first name
				Instant commonNameStart = Instant.now();
				ArrayList&amp;lt;String&amp;gt; firstNames = new ArrayList&amp;lt;&amp;gt;();


				System.out.println(&quot;Reading file using Buffered Reader&quot;);

				while ((readLine = b.readLine()) != null) {
					lines++;

					// get all the names
					String array1[] = readLine.split(&quot;\\s*\\|\\s*&quot;);
					String name = array1[7];
					names.add(name);
					if(indexes.contains(lines)){
						System.out.println(&quot;Name: &quot; + names.get(lines - 1) + &quot; at index: &quot; + (lines - 1));
					}

					if(name.contains(&quot;, &quot;)) {

						String array2[] = (name.split(&quot;, &quot;));
						String firstHalfOfName = array2[1].trim();

						if (!firstHalfOfName.isEmpty()) {
							if (firstHalfOfName.contains(&quot; &quot;)) {
								String array3[] = firstHalfOfName.split(&quot; &quot;);
								String firstName = array3[0].trim();
								firstNames.add(firstName);
							} else {
								firstNames.add(firstHalfOfName);
							}
						}
					}

					String rawDate = array1[4];
					String month = rawDate.substring(4,6);
					String year = rawDate.substring(0,4);
					String formattedDate = month + &quot;-&quot; + year;
					dates.add(formattedDate);

				}

				Instant namesEnd = Instant.now();
				long timeElapsedNames = Duration.between(namesStart, namesEnd).toMillis();
				System.out.println(&quot;Name time: &quot; + timeElapsedNames + &quot;ms&quot;);

				System.out.println(&quot;Total file line count: &quot; + lines);
				Instant lineCountEnd = Instant.now();
				long timeElapsedLineCount = Duration.between(lineCountStart, lineCountEnd).toMillis();
				System.out.println(&quot;Line count time: &quot; + timeElapsedLineCount + &quot;ms&quot;);

				HashMap&amp;lt;String, Integer&amp;gt; dateMap = new HashMap&amp;lt;&amp;gt;();
				for(String date:dates){
					Integer count = dateMap.get(date);
					if (count == null) {
						dateMap.put(date, 1);
					} else {
						dateMap.put(date, count + 1);
					}
				}
				for (Map.Entry&amp;lt;String, Integer&amp;gt; entry : dateMap.entrySet()) {
					String key = entry.getKey();
					Integer value = entry.getValue();
					System.out.println(&quot;Donations per month and year: &quot; + key + &quot; and donation count: &quot; + value);

				}
				Instant donationsEnd = Instant.now();
				long timeElapsedDonations = Duration.between(donationsStart, donationsEnd).toMillis();
				System.out.println(&quot;Donations time: &quot; + timeElapsedDonations + &quot;ms&quot;);

				HashMap&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
				for(String name:firstNames){
					Integer count = map.get(name);
					if (count == null) {
						map.put(name, 1);
					} else {
						map.put(name, count + 1);
					}
				}

				LinkedList&amp;lt;Entry&amp;lt;String, Integer&amp;gt;&amp;gt; list = new LinkedList&amp;lt;&amp;gt;(map.entrySet());

				Collections.sort(list, new Comparator&amp;lt;Map.Entry&amp;lt;String, Integer&amp;gt; &amp;gt;() {
					public int compare(Map.Entry&amp;lt;String, Integer&amp;gt; o1,
					                   Map.Entry&amp;lt;String, Integer&amp;gt; o2)
					{
						return (o2.getValue()).compareTo(o1.getValue());
					}
				});
				System.out.println(&quot;The most common first name is: &quot; + list.get(0).getKey() + &quot; and it occurs: &quot; + list.get(0).getValue() + &quot; times.&quot;);
				Instant commonNameEnd = Instant.now();
				long timeElapsedCommonName = Duration.between(commonNameStart, commonNameEnd).toMillis();
				System.out.println(&quot;Most common name time: &quot; + timeElapsedCommonName + &quot;ms&quot;);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Besides the BufferedReader and FileReader implementation, though, all the logic within is the same, so I’ll move on now to my final Java file reader implementation: FileUtils.LineIterator.&lt;/p&gt;
&lt;h3&gt;Apache Commons IO &lt;code&gt;FileUtils.LineIterator()&lt;/code&gt; Implementation&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-java-on-large-datasets/apache.webp&quot; alt=&quot;Apache logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Apache is responsible for this handy library.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The last solution I came up with involves a library made by Apache, called &lt;strong&gt;&lt;a href=&quot;https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/LineIterator.html&quot;&gt;&lt;code&gt;FileUtils.LineIterator()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;. It’s easy enough to include the dependency. I used Gradle for my Java project, so all I had to do was include the &lt;code&gt;commons-io&lt;/code&gt; library in my &lt;code&gt;build.gradle&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/read-file-java/blob/master/build.gradle&quot;&gt;&lt;code&gt;build.gradle&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dependencies {
	compile group: &apos;commons-io&apos;, name: &apos;commons-io&apos;, version: &apos;2.6&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The LineIterator, does exactly what its name suggests: it holds a reference to an open &lt;code&gt;Reader&lt;/code&gt; (like &lt;code&gt;FileReader&lt;/code&gt; in my last solution), and iterates over each line in the file. And it’s really easy to set up LineIterator in the first place.&lt;/p&gt;
&lt;p&gt;LineIterator has a built-in method called &lt;code&gt;nextLine()&lt;/code&gt;, which actually returns the next line in the wrapped reader (not unlike Scanner’s &lt;code&gt;nextLine()&lt;/code&gt; method or BufferedReader’s &lt;code&gt;readLine()&lt;/code&gt; method).&lt;/p&gt;
&lt;p&gt;Here’s the code to set up &lt;code&gt;FileUtils.LineIterator()&lt;/code&gt; once the dependency library has been included.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;File f = new File(&quot;src/main/resources/config/test.txt&quot;);

try {
   LineIterator it = FileUtils.lineIterator(f, &quot;UTF-8&quot;); 
   // do some things ...
   while (it.hasNext()) {
      String line = it.nextLine(); 
     // do some other things ...
   }
   // do some final things
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is my full code using &lt;code&gt;FileUtils.LineIterator()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/read-file-java/blob/master/src/main/java/com/example/readFile/readFileJava/ReadFileJavaApplicationLineIterator.java&quot;&gt;&lt;code&gt;ReadFileJavaApplicationLineIterator.java&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.example.readFile.readFileJava;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;

public class ReadFileJavaApplicationLineIterator {
	public static void main(String[] args) throws IOException {
		File f = new File(Common.getPathToTargetFile(args));

		try {
			LineIterator it = FileUtils.lineIterator(f, &quot;UTF-8&quot;);

			// get total line count
			Instant lineCountStart = Instant.now();
			int lines = 0;

			Instant namesStart = Instant.now();
			ArrayList&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();

			// get the 432nd and 43243 names
			ArrayList&amp;lt;Integer&amp;gt; indexes = new ArrayList&amp;lt;&amp;gt;();

			indexes.add(1);
			indexes.add(433);
			indexes.add(43244);

			// count the number of donations by month
			Instant donationsStart = Instant.now();
			ArrayList&amp;lt;String&amp;gt; dates = new ArrayList&amp;lt;&amp;gt;();

			// count the occurrences of first name
			Instant commonNameStart = Instant.now();
			ArrayList&amp;lt;String&amp;gt; firstNames = new ArrayList&amp;lt;&amp;gt;();


			System.out.println(&quot;Reading file using Line Iterator&quot;);

			while (it.hasNext()) {
				String line = it.nextLine();
				lines++;

				// get all the names
				String array1[] = line.split(&quot;\\s*\\|\\s*&quot;);
				String name = array1[7];
				names.add(name);
				if (indexes.contains(lines)) {
					System.out.println(&quot;Name: &quot; + names.get(lines - 1) + &quot; at index: &quot; + (lines - 1));
				}

				if (name.contains(&quot;, &quot;)) {

					String array2[] = (name.split(&quot;, &quot;));
					String firstHalfOfName = array2[1].trim();

					if (!firstHalfOfName.isEmpty()) {
						if (firstHalfOfName.contains(&quot; &quot;)) {
							String array3[] = firstHalfOfName.split(&quot; &quot;);
							String firstName = array3[0].trim();
							firstNames.add(firstName);
						} else {
							firstNames.add(firstHalfOfName);
						}
					}
				}

				String rawDate = array1[4];
				String month = rawDate.substring(4, 6);
				String year = rawDate.substring(0, 4);
				String formattedDate = month + &quot;-&quot; + year;
				dates.add(formattedDate);
			}

			Instant namesEnd = Instant.now();
			long timeElapsedNames = Duration.between(namesStart, namesEnd).toMillis();
			System.out.println(&quot;Name time: &quot; + timeElapsedNames + &quot;ms&quot;);

			System.out.println(&quot;Total file line count: &quot; + lines);
			Instant lineCountEnd = Instant.now();
			long timeElapsedLineCount = Duration.between(lineCountStart, lineCountEnd).toMillis();
			System.out.println(&quot;Line count time: &quot; + timeElapsedLineCount + &quot;ms&quot;);

			HashMap&amp;lt;String, Integer&amp;gt; dateMap = new HashMap&amp;lt;&amp;gt;();
			for (String date : dates) {
				Integer count = dateMap.get(date);
				if (count == null) {
					dateMap.put(date, 1);
				} else {
					dateMap.put(date, count + 1);
				}
			}

			for (Map.Entry&amp;lt;String, Integer&amp;gt; entry : dateMap.entrySet()) {
				String key = entry.getKey();
				Integer value = entry.getValue();
				System.out.println(&quot;Donations per month and year: &quot; + key + &quot; and donation count: &quot; + value);
			}

			Instant donationsEnd = Instant.now();
			long timeElapsedDonations = Duration.between(donationsStart, donationsEnd).toMillis();
			System.out.println(&quot;Donations time: &quot; + timeElapsedDonations + &quot;ms&quot;);

			HashMap&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
			for (String name : firstNames) {
				Integer count = map.get(name);
				if (count == null) {
					map.put(name, 1);
				} else {
					map.put(name, count + 1);
				}
			}

			LinkedList&amp;lt;Entry&amp;lt;String, Integer&amp;gt;&amp;gt; list = new LinkedList&amp;lt;&amp;gt;(map.entrySet());

			Collections.sort(list, new Comparator&amp;lt;Entry&amp;lt;String, Integer&amp;gt;&amp;gt;() {
				public int compare(Map.Entry&amp;lt;String, Integer&amp;gt; o1,
				                   Map.Entry&amp;lt;String, Integer&amp;gt; o2) {
					return (o2.getValue()).compareTo(o1.getValue());
				}
			});
			System.out.println(&quot;The most common first name is: &quot; + list.get(0).getKey() + &quot; and it occurs: &quot; + list.get(0).getValue() + &quot; times.&quot;);
			Instant commonNameEnd = Instant.now();
			long timeElapsedCommonName = Duration.between(commonNameStart, commonNameEnd).toMillis();
			System.out.println(&quot;Most common name time: &quot; + timeElapsedCommonName + &quot;ms&quot;);

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: There is one thing you need to be aware of if you’re running a plain Java application without the aid of Spring Boot. If you want to use this extra Apache dependency library you need to manually bundle it together with your application’s JAR file into what’s called a &lt;strong&gt;fat JAR&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A fat jar (also known as an uber jar) is a self-sufficient archive which contains both classes and dependencies needed to run an application.&lt;/p&gt;
&lt;p&gt;Spring Boot &quot;automagically&quot; bundles all of our dependencies together for us, but it’s also got a lot of extra overhead and functionalities that are totally unnecessary for this project, which is why I chose not to use it. It makes the project unnecessarily heavy.&lt;/p&gt;
&lt;p&gt;There are plugins available now, but I just wanted a quick and easy way to bundle my one dependency up with my JAR. So I modified the &lt;code&gt;jar&lt;/code&gt; task from the Java Gradle plugin. By default, this task produces jars without any dependencies.&lt;/p&gt;
&lt;p&gt;I can overwrite this behavior by adding a few lines of code. I just need two things to make it work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;Main-Class&lt;/code&gt; attribute in the manifest file (check, I had three main class files in my demo repo for testing purposes),&lt;/li&gt;
&lt;li&gt;And any dependencies jars.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://www.baeldung.com/gradle-fat-jar&quot;&gt;Baeldung&lt;/a&gt; for the help on making this fat JAR.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jar {
	manifest {
		attributes &quot;Main-Class&quot;: &quot;com.example.readFile.readFileJava.ReadFileJavaApplicationLineIterator&quot;
	}

	from {
		configurations.compile.collect {
			it.isDirectory() ? it : zipTree(it)
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the main class file has been defined (and in my &lt;a href=&quot;https://github.com/paigen11/read-file-java&quot;&gt;demo repo&lt;/a&gt;, I made three main class files, which confused my IDE to no end) and the dependencies were included, you can run the &lt;code&gt;./gradlew assemble&lt;/code&gt; command from the terminal and then:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;java -cp ./build/libs/readFileJava-0.0.1-SNAPSHOT.jar com.example.readFile.readFileJava.ReadFileJavaApplicationLineIterator
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And your program should run with the LineIterator library included.&lt;/p&gt;
&lt;p&gt;If you’re using IntelliJ as your IDE, you can also just use its run configurations locally with each of the main files specified as the correct main class, and it should run the three programs as well. See my &lt;a href=&quot;https://github.com/paigen11/read-file-java&quot;&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt; for more info on this.&lt;/p&gt;
&lt;p&gt;Great, now I have three different ways to read and process large text files in Java, my next mission: figure out which way is more performant.&lt;/p&gt;
&lt;h2&gt;How I evaluated the solution&apos;s performance and their results&lt;/h2&gt;
&lt;p&gt;For performance testing my different Java applications and the functions inside them, I came across two handy, ready-made functions in Java 8: &lt;code&gt;Instant.now()&lt;/code&gt; and &lt;code&gt;Duration.between()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What I wanted to do was see if there was any measurable differences between the different ways of reading the same file. So besides the different file read options: FileInputStream, BufferedReader and LineIterator, I tried to keep the code (and timestamps marking the start and stop of each function) as similar as possible. And I think it worked out pretty well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html&quot;&gt;&lt;code&gt;Instant.now()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Instant.now()&lt;/code&gt; does exactly what its name suggests: it holds a single, instantaneous point on the timeline, stored as a &lt;code&gt;long&lt;/code&gt; representing epoch-seconds and an &lt;code&gt;int&lt;/code&gt; representing a nanosecond-of-seconds. This isn’t incredibly useful all on it’s own, but when it’s combined with &lt;code&gt;Duration.between()&lt;/code&gt;, it becomes very useful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html&quot;&gt;&lt;code&gt;Duration.between()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Duration.between()&lt;/code&gt; takes a start interval and an end interval and finds the duration between those two times. That’s it. And that timing can be converted to all sorts of different, readable formats: milliseconds, seconds, minutes, hours, etc.&lt;/p&gt;
&lt;p&gt;Here’s an example of implementing &lt;code&gt;Instant.now()&lt;/code&gt; and &lt;code&gt;Duration.between()&lt;/code&gt; in my files. This one is timing how long it takes to get the line count of the total file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {
    LineIterator it = FileUtils.lineIterator(f, &quot;UTF-8&quot;);

    // get total line count
    Instant lineCountStart = Instant.now();
    int lines = 0;
    
    System.out.println(&quot;Reading file using Line Iterator&quot;);

    while (it.hasNext()) {
      String line = it.nextLine();
      lines++;

    }

    System.out.println(&quot;Total file line count: &quot; + lines);
    Instant lineCountEnd = Instant.now();
    
    long timeElapsedLineCount =
    Duration.between(lineCountStart, lineCountEnd).toMillis();
    
    System.out.println(&quot;Line count time: &quot; +
    timeElapsedLineCount + &quot;ms&quot;);
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Results&lt;/h3&gt;
&lt;p&gt;Here’s the results after applying &lt;code&gt;Instant.now()&lt;/code&gt; and &lt;code&gt;Duration.between()&lt;/code&gt; to all of my different file read methods in Java.&lt;/p&gt;
&lt;p&gt;I ran all three of my solutions against the 2.55GB file, which contained just over 13 million lines in total.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-java-on-large-datasets/all-results.webp&quot; alt=&quot;Performance results for 3 Java solutions&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;LineIterator just barely beats out BufferedReader, and both handily beat FileInputStream.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As you can see from the table, &lt;code&gt;BufferedReader()&lt;/code&gt; and &lt;code&gt;LineIterator()&lt;/code&gt; both fared well, but they’re so close in their timings it seems to be up to the developer which they’d rather use.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BufferedReader()&lt;/code&gt; is nice because it requires no extra dependencies, but it is slightly more complex to set up in the beginning, with the &lt;code&gt;FileReader() &lt;/code&gt;to wrap inside. Whereas &lt;code&gt;LineIterator()&lt;/code&gt; is an external library but it makes iterating over the file extra easy after it is included as a dependency.&lt;/p&gt;
&lt;p&gt;The percentage improvements are included at the end of the table above as well, for reference.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;FileInputStream&lt;/code&gt;, in an interesting twist, got blown out of the water by the other two. By buffering the data stream or using the library made specifically for iterating through text files, performance improved by about 73% on all tasks.&lt;/p&gt;
&lt;p&gt;Below are the raw screenshots from my terminal for each of my solutions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #1: &lt;code&gt;FileInputStream()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-java-on-large-datasets/result-1.webp&quot; alt=&quot;Results for FileInputStream and Scanner&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The solution using FileInputStream() and Scanner().&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #2: &lt;code&gt;BufferedReader()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-java-on-large-datasets/result-2.webp&quot; alt=&quot;Results for BufferedReader and FileReader&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The solution using BufferedReader() and FileReader().&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #3: &lt;code&gt;FileUtils.lineIterator()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-java-on-large-datasets/result-3.webp&quot; alt=&quot;Results for FileUtils.lineIterator&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The solution using FileUtils.lineIterator().&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the end, buffered streams and custom file read libraries are the most efficient ways processing large data sets in Java. At least, for the large text files I was tasked with reading.&lt;/p&gt;
&lt;p&gt;Thanks for reading my post on using Java to read really, really large files. If you’d like to see the original posts on Node.js that inspired this one, you can see &lt;strong&gt;&lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;part 1&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;./streams-for-the-win-a-performance-comparison-of-node-js-methods-for-reading-large-datasets-pt-2&quot;&gt;part 2&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about Swagger with Express.js or something else related to web development and JavaScript, so subscribe to my newsletter so you don’t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you an idea of how to handle large amounts of data with Java efficiently and performance test your solutions.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Github, &lt;a href=&quot;https://github.com/paigen11/read-file-java&quot;&gt;Read File in Java Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Link to the &lt;a href=&quot;https://www.fec.gov/files/bulk-downloads/2018/indiv18.zip&quot;&gt;FEC data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oracle Java Documentation, &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/?java/io/FileInputStream.html&quot;&gt;FileInputStream&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oracle Java Documentation, &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html&quot;&gt;Scanner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oracle Java Documentation, &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html&quot;&gt;BufferedReader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oracle Java Documentation, &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/?java/io/FileReader.html&quot;&gt;FileReader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Apache Commons Java Documentation, &lt;a href=&quot;https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/LineIterator.html&quot;&gt;LineIterator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Baeldung, &lt;a href=&quot;https://www.baeldung.com/gradle-fat-jar&quot;&gt;Creating a Fat Jar in Gradle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oracle Java Documentation, &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html&quot;&gt;Instant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Oracle Java Documentation, &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html&quot;&gt;Duration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>java</category><category>big data</category><category>performance</category><category>testing</category></item><item><title>Keep Code Consistent Across Developers The Easy Way — With Prettier &amp; ESLint</title><link>https://www.paigeniedringhaus.com/blog/keep-code-consistent-across-developers-the-easy-way-with-prettier-eslint/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/keep-code-consistent-across-developers-the-easy-way-with-prettier-eslint/</guid><description>Writing code is tough enough, don’t make it tougher with bad formatting.</description><pubDate>Sat, 22 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/fine-dog-hero.webp&quot; alt=&quot;Everything is fine dog&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A slight exaggeration, but you get the idea.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Code formatting: it’s not just for sticklers and grammar nazis&lt;/h2&gt;
&lt;p&gt;This post is for all the JavaScript developers out there who’ve ever developed any application with another person (or plan to). If that’s you, keep reading. If you’re a solo, rockstar, ninja developer, you can go on about your day.&lt;/p&gt;
&lt;p&gt;Now that I’ve got everyone else’s attention, let me give you a hypothetical (real-life) example of what you might encounter upon opening an existing JavaScript codebase that a team of developers has put together.&lt;/p&gt;
&lt;p&gt;You may see some (or all) of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Missing semi-colons.&lt;/li&gt;
&lt;li&gt;Tons of whitespace between some lines and no whitespace between others.&lt;/li&gt;
&lt;li&gt;Run on lines that cause you to scroll right for ages to see everything they contain.&lt;/li&gt;
&lt;li&gt;Seemingly random indentation.&lt;/li&gt;
&lt;li&gt;Commented out code chunks.&lt;/li&gt;
&lt;li&gt;Initialized but unused variables.&lt;/li&gt;
&lt;li&gt;Some files that use “strict” JS and others that don’t.&lt;/li&gt;
&lt;li&gt;Blocks of code with no spaces or comments anywhere making reading them and deciphering what’s happening that much harder.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take this piece of code from a codebase I’m currently working in:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/unformatted-code.webp&quot; alt=&quot;Unformatted JavaScript code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is an example of poorly formatted code. Isn’t that painful to look at? Yeah...&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Does this sound at all familiar to you? Congrats, you’re on a working dev team, and everyone has their own preferences for how they like to code.&lt;/p&gt;
&lt;p&gt;As you might already be able to imagine, what one developer is perfectly fine with (no whitespace anywhere), probably drives another one nuts. And while one dev might indent every line perfectly every time, another dev probably doesn’t care (and knows JavaScript doesn’t care too much either, so s/he can get away with it).&lt;/p&gt;
&lt;p&gt;This is a recipe for a hard-to-follow codebase, and I don’t know about you, but I find the act of understanding and writing good, functional code hard enough without having to worry about indentation, spacing, keeping track of variables and simple punctuation fixes.&lt;/p&gt;
&lt;p&gt;Not to mention, I hate being that person who makes comments all over a pull request asking for things like that to be cleaned up. Nobody wants to be that person.&lt;/p&gt;
&lt;p&gt;Which is what brings me to today’s post.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I’m going to magic away the code inconsistencies of a bunch of different developers with the help of Visual Studio Code, Prettier and ESLint, and leave you with beautiful, uniform code that your development team won’t even have to think about formatting.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sounds too good to be true? It’s not. I promise.&lt;/p&gt;
&lt;h2&gt;VS Code &amp;amp; Plugins to the Rescue&lt;/h2&gt;
&lt;p&gt;Right, so let’s get straight to the solutions to your code formatting problems. In case you’re not familiar with it, &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;&lt;strong&gt;VS Code&lt;/strong&gt;&lt;/a&gt; is the de facto &lt;a href=&quot;https://2018.stateofjs.com/other-tools/&quot;&gt;JavaScript IDE&lt;/a&gt; today.&lt;/p&gt;
&lt;p&gt;And for good reason: it’s free, it’s easy to get up and running, and it’s just an absolute pleasure to work with. That’s just the tip of the iceberg, but there’s a million other articles expounding on the awesomeness of VS Code, so I’ll leave that to them.&lt;/p&gt;
&lt;p&gt;Before this, I was a supporter of all things JetBrains like WebStorm and IntelliJ, but after giving Visual Studio Code a try, I’m sold.&lt;/p&gt;
&lt;p&gt;Which leads to...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; If you haven’t downloaded it yet, &lt;a href=&quot;https://code.visualstudio.com/download&quot;&gt;download VS Code&lt;/a&gt; now. It’s a critical piece of our puzzle to solve this formatting and code consistency problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Getting started with plugins. One of my favorite things about VS Code is the extremely robust plugin ecosystem it has, and the ease of integrating said plugins. You set them up once, then you can forget about them, and they just keep working, project after project.&lt;/p&gt;
&lt;p&gt;There’s two plugins you need in your arsenal today: &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&quot;&gt;&lt;strong&gt;Prettier&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint&quot;&gt;&lt;strong&gt;ESLint&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you open up your Extensions tab on the side of your VS Code window, you’ll see a host of extensions made for VS Code.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/vscode-marketplace.webp&quot; alt=&quot;VS Code marketplace extension tab&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;See that square thing on the far left? Click that to open up the plugin search for VS Code.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;But before I have you download these plugins, let me give you a quick overview of what these extensions can do for you.&lt;/p&gt;
&lt;h3&gt;Prettier&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/prettier-logo.webp&quot; alt=&quot;Prettier extension logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Very simply, Prettier is a &quot;VS Code package to format your JavaScript / TypeScript / CSS&quot; - Prettier site&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In practice, &lt;a href=&quot;https://prettier.io/&quot;&gt;&lt;strong&gt;Prettier&lt;/strong&gt;&lt;/a&gt; is an opinionated code formatter that does all sorts of useful things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changes all single quotes to double quotes.&lt;/li&gt;
&lt;li&gt;Adds missing semicolons.&lt;/li&gt;
&lt;li&gt;Puts spaces between curly braces or brackets and variables.&lt;/li&gt;
&lt;li&gt;Sets standard tab width.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is only a small fraction of what Prettier cares about, and in VS Code it’s really easy to override any rules that you’re not a fan of, which I’ll get to in a bit.&lt;/p&gt;
&lt;p&gt;Prettier is made for keeping code formatting consistent, and the VS Code plugin, it works based on a &lt;code&gt;.prettierrc&lt;/code&gt; file in the root of a project. It will keep your code clean and easy to read, and the same across all developers on the team.&lt;/p&gt;
&lt;p&gt;One of the biggest selling points for me?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prettier can be set up in VS Code to auto-format code &lt;em&gt;on every save&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I don’t have to think about it, I don’t have to set up complicated file watcher tasks, I change one setting in VS Code and it just works. Every time. Period. The end.&lt;/p&gt;
&lt;p&gt;I’ll show you how to do this too, but before I get there, I need you to &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&quot;&gt;download Prettier&lt;/a&gt; for VS Code.&lt;/p&gt;
&lt;p&gt;Open up the Extensions Marketplace in your VS Code window (it’s the little square looking doodad under the debugger).&lt;/p&gt;
&lt;p&gt;This is the first plugin you’ll be searching for in VS Code’s extensions. If you type &quot;Prettier&quot; into the search bar, your results should look something like this:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/prettier-extension.webp&quot; alt=&quot;Prettier extension in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Go for Prettier - Code Formatter. This is the one you want.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;You see the first result? The one with 5.7 million downloads and counting? That’s the one you want to install. When in doubt, look for the extension with the most downloads that’s closest to what you think the name of the extension is, and go with it.&lt;/p&gt;
&lt;p&gt;If you think the &quot;Install&quot; buttons on VS Code look like labels or banners instead of finished, clickable buttons, I agree with you. But that’s a debate for another day.&lt;/p&gt;
&lt;p&gt;Once the Prettier extension is installed, we’re ready to move on to our second plugin: ESLint.&lt;/p&gt;
&lt;h3&gt;ESLint&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/eslint-logo.webp&quot; alt=&quot;ESLint extension logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The thinking behind ESLint is: “JavaScript, being a dynamic and loosely-typed language, is especially prone to developer error. Without the benefit of a compilation process, JavaScript code is typically executed in order to find syntax or other errors. Linting tools like ESLint allow developers to discover problems with their JavaScript code without executing it.” — ESLint site&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://eslint.org/&quot;&gt;&lt;strong&gt;ESLint&lt;/strong&gt;&lt;/a&gt; is great for the more specific, less generic code styles that you want your development team to adhere to. Unless you specifically set it up, ESLint won’t autofix or rewrite your code, but it will let you know in a straightforward way that there’s “rules” being broken.&lt;/p&gt;
&lt;p&gt;Whether those rules include commented out code, unused variables or missing prop-types is up to you and your team, but with an &lt;code&gt;.eslintrc&lt;/code&gt; file in place in your project, it sets up guardrails around the project to ensure each JavaScript file written adheres to the same standards as the others, regardless of who’s working on it.&lt;/p&gt;
&lt;p&gt;The ESLint plugin for VS Code is an extension of the official, &lt;a href=&quot;https://eslint.org/&quot;&gt;open source ESLint&lt;/a&gt; utility used by the likes of Google, Facebook, Netflix and more.&lt;/p&gt;
&lt;p&gt;If ESLint is good enough for them, it’s certainly good enough for me.&lt;/p&gt;
&lt;p&gt;Here’s what you’ll see when searching for &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint&quot;&gt;ESLint&lt;/a&gt; in the VS Code extension marketplace:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/eslint-extension.webp&quot; alt=&quot;ESLint extension in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The one with 15 million downloads - that’s the one you want.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;One of the biggest benefits to ESLint is that each “rule” set in ESLint is entirely standalone. Every one can be turned on or off, new rules can be added, unnecessary rules can be ignored, and there’s a ton of rules that are already documented to be included with just a line of code.&lt;/p&gt;
&lt;p&gt;No rules are enabled by default, so you’re free to add them as you see fit, but a lot of development teams like to start with something like &lt;a href=&quot;https://www.npmjs.com/package/eslint-config-airbnb&quot;&gt;&lt;strong&gt;Airbnb’s ESLint file&lt;/strong&gt;&lt;/a&gt;, which is packaged as a handy NPM module(&lt;code&gt;npm i eslint-config-airbnb&lt;/code&gt;), and adjust as they need to suit their needs.&lt;/p&gt;
&lt;p&gt;As an aside: Airbnb’s whole &lt;a href=&quot;https://github.com/airbnb/javascript&quot;&gt;style guide&lt;/a&gt; is a great example of how to approach writing JavaScript, in general. I figure, 79,000+ stars on Github is a pretty good indicator of quality. But again, that’s a tangent for another post.&lt;/p&gt;
&lt;p&gt;For now, let’s download &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&quot;&gt;Prettier&lt;/a&gt; and &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint&quot;&gt;ESLint&lt;/a&gt;, and move on to getting them running in VS Code.&lt;/p&gt;
&lt;h2&gt;Setting up and configuring Prettier and ESLint&lt;/h2&gt;
&lt;p&gt;This is the fun part. It’s the super, super easy part, too. You’ll be amazed just how painless it is, and it just makes me even happier that VS Code exists.&lt;/p&gt;
&lt;p&gt;Once you’ve downloaded these plugins, it’s time to enable them.&lt;/p&gt;
&lt;p&gt;To check that your new plugins are installed and enabled, while still in the extensions screen, you can click the three dots at the top right of the search input and click the &quot;Show Installed Extensions or &quot;Show Enabled Extensions&quot; selection from the dropdown, and if your new extensions are downloaded/enabled ESLint and Prettier will show up there.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/show-extensions.webp&quot; alt=&quot;Show installed VS Code extensions&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Both ESLint and Prettier are installed and enabled for my VS Code workspaces.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If either is not enabled, just click the extension and click the &quot;Enable&quot; button (yep, it looks like a label, but it’s a button). Then restart your VS Code program for the changes to take effect.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/install-extension.webp&quot; alt=&quot;Enable extension in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;If ESLint was not enabled, the Disable button would say &quot;Enable&quot; and I could click it to turn it on from there.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Default user settings&lt;/h3&gt;
&lt;p&gt;Great, now both plugins should be enabled and we’re ready to get started. As I said before, Prettier has lots of settings enabled by default, and you can see exactly what’s enabled / disabled and make any changes you’d like to take effect globally, here.&lt;/p&gt;
&lt;p&gt;To get to these settings, go to &lt;strong&gt;Code &amp;gt; Preferences &amp;gt; Settings&lt;/strong&gt; and then search &quot;prettier&quot; in the input box. Once you’re in general Settings, click the curly braces in the top right corner of the window and it will take you to the &quot;Default User Settings&quot;, where you can see all the Prettier settings and what they default to.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/default-prettier.webp&quot; alt=&quot;Default Prettier settings in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Default Prettier configuration settings in my VS Code.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;From here, you can do the same thing by putting &quot;eslint&quot; in the search box, and see all the rules in place by default for that extension.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/default-eslint.webp&quot; alt=&quot;Default ESLint settings in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Default ESLint configuration settings in my VS Code.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And that’s the defaults. Good, now let’s customize it a little bit, because I want to make my development life even easier.&lt;/p&gt;
&lt;h3&gt;Custom user settings&lt;/h3&gt;
&lt;p&gt;VS Code offers this really handy way to override any default settings of specific extensions with what it calls &quot;User Settings&quot;.&lt;/p&gt;
&lt;p&gt;All this is, is a file that VS Code generates with settings that are specific to your text editor. If you want to override a specific rule, just hover your cursor over the rule to modify, then click the pencil that appears at the left, and a new window titled &quot;User Settings&quot; will open up and add that rule as a modifiable setting there.&lt;/p&gt;
&lt;p&gt;Here’s an example of what my user settings look like on the right in the screenshot below. I’ve overwritten a couple of the Prettier settings: &lt;code&gt;singleQuote&lt;/code&gt; and &lt;code&gt;trailingComma&lt;/code&gt;, and I’ve enabled ESLint’s &lt;code&gt;autoFixOnSave()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;By far, the best thing I enabled, though, is Prettier’s &lt;code&gt;formatOnSave()&lt;/code&gt;, so I don’t even have to think about it. This was done through the following code snippet.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;[javascript]&quot;: {
    &quot;editor.formatOnSave&quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/user-settings.webp&quot; alt=&quot;User settings in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Click the Edit pencil on the left, and the rule gets added to your custom &quot;User Settings&quot; on the right.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Prettier’s &lt;code&gt;formatOnSave()&lt;/code&gt; is on a per-language basis, so if you want to add in formatting for CSS or HTML or some other language, you just need to add it here. And then it’s ready to go.&lt;/p&gt;
&lt;p&gt;Make a change in a JavaScript file, save the change, and the code reformats itself according to Prettier. It’s glorious. Truly, one of my favorite features, by far.&lt;/p&gt;
&lt;h3&gt;Project-specific config files&lt;/h3&gt;
&lt;p&gt;And finally, the project specific configuration files.&lt;/p&gt;
&lt;p&gt;I find the default settings straight through the VS Code extension to be enough for me when I’m coding my own projects, but for a dev team, to be absolutely sure everyone’s coding to the same standards, that file could be included to take out all the guesswork.&lt;/p&gt;
&lt;p&gt;Anyway, for ESLint to work best, it needs an &lt;code&gt;.eslintrc&lt;/code&gt; file at the root of the project. Here’s an example of what that file could look like.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/eslint-config-file.webp&quot; alt=&quot;Sample ESLint config file&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example of an &lt;code&gt;.eslintrc&lt;/code&gt; file.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This is a pared down one, but you get the idea. Any rules to be linted against are added at the bottom of the file.&lt;/p&gt;
&lt;p&gt;And once this file is present, if there’s a rule that’s being broken, it will appear in the &quot;Problems&quot; section where the built-in terminal runs in the VS Code window.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/eslint-linting.webp&quot; alt=&quot;ESLint linting a file&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;ESLint doing its linting.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Without a project specific &lt;code&gt;.eslintrc&lt;/code&gt; file, unless you have a lot of hard and fast rules you want to set in your custom User Settings, you won’t get a lot of assistance from ESLint. Personally, I like the project specific ESLint file, it makes it crystal clear what the rules and standards are, and unlike Prettier, which is very opinionated by default, ESLint won’t complain unless you tell it to.&lt;/p&gt;
&lt;p&gt;And here&apos;s a basic &lt;code&gt;.prettierrc&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/prettier-eslint/prettier-config-file.png&quot; alt=&quot;Sample Prettier config file&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example of a &lt;code&gt;.prettierrc&lt;/code&gt; file.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;To wrap it up, the configuration settings in VS Code are a little like CSS and its specificity rules— the more specific the settings file, the higher the priority it is given by VS Code. If there’s no project specific config file, VS Code falls back to the custom user settings, and if there’s no custom user settings it looks for default settings last of all.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There you have it. Your dev team is now set up for success — at least when it comes to consistent, well-formatted, and clean JavaScript code. VS Code makes it so simple to implement thorough code linting and opinionated code formatting with little effort on the developer’s part. There’s no reason not to get on board with that.&lt;/p&gt;
&lt;p&gt;These simple tips will speed up development and keep everyone’s code looking consistent, even with all of their unique coding styles.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing reading really large files in Java (a follow up to my two part series on &lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;reading really large files with Node.js&lt;/a&gt;) or something else related to web development, so please follow me so you don’t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you an idea of how to easily keep your code consistent with Prettier and ESLint.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&quot;&gt;Prettier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint&quot;&gt;ESLint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org&quot;&gt;ESLint Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/eslint-config-airbnb&quot;&gt;Airbnb ESLint, npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/airbnb/javascript&quot;&gt;Airbnb Style Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://2018.stateofjs.com/other-tools/&quot;&gt;State of JavaScript, 2018: Other Tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>eslint</category><category>vscode</category></item><item><title>Getting Started with Puppeteer &amp; Headless Chrome for End-to-End Testing</title><link>https://www.paigeniedringhaus.com/blog/getting-started-with-puppeteer-headless-chrome-for-end-to-end-testing/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/getting-started-with-puppeteer-headless-chrome-for-end-to-end-testing/</guid><description>And a brief primer on integrating Puppeteer into Jest testing.</description><pubDate>Sat, 08 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/chrome-puppeteer-e2e-testing/chrome-puppeteer-jest-hero.png&quot; alt=&quot;Logos of Chrome, Puppeteer, and Jest&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Inspiration for this post&lt;/h2&gt;
&lt;p&gt;This blog post was inspired by a talk I saw at the &lt;a href=&quot;http://connect.tech/&quot;&gt;Connect.Tech Conference&lt;/a&gt; in Atlanta this year, entitled: &quot;Using Puppeteer to Write End-to-End Tests That Run On The Browser.&quot;&lt;/p&gt;
&lt;p&gt;The speaker, Taylor Krusen, gave a great talk on Puppeteer and headless Chrome and using them together to take end-to-end testing to the next level. I’d looked briefly into Puppeteer in the past, but since I couldn’t find any great examples of how to get started with it, I’d passed and chosen to use &lt;a href=&quot;https://www.cypress.io/&quot;&gt;&lt;strong&gt;Cypress.io&lt;/strong&gt;&lt;/a&gt; for my testing needs instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After the talk though, I was inspired to give Puppeteer another shot and I went a step further, figuring out how to run Puppeteer and how to use it with Jest, the testing framework most commonly associated with React.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And I want to share that today to hopefully help others get started with their own application testing suites.&lt;/p&gt;
&lt;h2&gt;What is end-to-end testing &amp;amp; why is it important?&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/chrome-puppeteer-e2e-testing/testing-pyramid.png&quot; alt=&quot;Google testing pyramid&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;End to end tests make up the smallest part of the testing pyramid, as defined by Google, but they are still a crucial part of it.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Before I dive into &lt;em&gt;how&lt;/em&gt; to use Puppeteer for end-to-end testing, I think it’s important to briefly explain what it is and why it’s important for web development today.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.techopedia.com/definition/7035/end-to-end-test&quot;&gt;Techopedia&lt;/a&gt; gives a good definition of end-to-end testing:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;End-to-end testing is a methodology used to test whether the flow of an application is performing as designed from start to finish. The purpose of carrying out end-to-end tests is to identify system dependencies and to ensure that the right information is passed between various system components and systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Essentially, end-to-end testing replicates, in an automated fashion, exactly what a user could do while interacting with the application or browser. And this is done to ensure the application works properly and as expected.&lt;/p&gt;
&lt;p&gt;As web applications get more and more complex and full featured, it becomes harder and harder for manual QA teams to keep up with testing every single piece of functionality each time the application is ready to deploy a new feature. End-to-end testing frameworks were created to take the burden (and repetitive task) of checking functionality out of the hands of people and have machines (which can move much faster than actual users and exactly replicate a test every time) shoulder more of the load.&lt;/p&gt;
&lt;p&gt;Ultimately, it still comes down to us, as developers, to ensure our applications work the way we expect, but testing helps us to better ensure we’re not introducing new bugs into our code or compromising existing functionality, which is why it’s so important.&lt;/p&gt;
&lt;h3&gt;What are Headless Chrome &amp;amp; Puppeteer?&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/chrome-puppeteer-e2e-testing/chrome-puppeteer.png&quot; alt=&quot;Logos of headless Chrome and Puppeteer&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The next thing to cover is what exactly are &lt;a href=&quot;https://developer.chrome.com/blog/headless-chrome/&quot;&gt;&lt;strong&gt;Headless Chrome&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://pptr.dev/&quot;&gt;&lt;strong&gt;Puppeteer&lt;/strong&gt;&lt;/a&gt;, and why are they always bundled together?&lt;/p&gt;
&lt;p&gt;Puppeteer’s &lt;a href=&quot;https://github.com/GoogleChrome/puppeteer&quot;&gt;GitHub&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/puppeteer&quot;&gt;npm&lt;/a&gt; pages do a great job of explaining exactly what Puppeteer is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the &lt;a href=&quot;https://chromedevtools.github.io/devtools-protocol/&quot;&gt;DevTools Protocol&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It goes on to say Puppeteer runs headless Chrome or Chromium instances by default, which is why they’re always mentioned in tandem.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Most things that you can do manually in the browser can be done using Puppeteer!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Puppeteer was made for Chrome by the Google Chrome DevTools team to help further automated/headless browser testing and make it less painful for the rest of us.&lt;/p&gt;
&lt;p&gt;The biggest drawback is that Puppeteer only works with Chrome. I have had the good fortune of working on applications where our users use Chrome exclusively, which made Puppeteer a very good option for end-to-end testing, but if the user base is more varied in its browser preferences, it may be wise to look into other testing frameworks like &lt;a href=&quot;https://www.cypress.io/&quot;&gt;Cypress.io&lt;/a&gt;, &lt;a href=&quot;https://testcafe.devexpress.com/&quot;&gt;TestCafe&lt;/a&gt;, or &lt;a href=&quot;https://www.seleniumhq.org/projects/webdriver/&quot;&gt;Selenium Web Driver&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But today, at least, I get to talk about Puppeteer.&lt;/p&gt;
&lt;h3&gt;Puppeteer examples&lt;/h3&gt;
&lt;p&gt;Now it’s time to get down to the business of getting Puppeteer up and running.&lt;/p&gt;
&lt;p&gt;Getting started with Puppeteer is actually incredibly easy — just type &lt;code&gt;npm i puppeteer&lt;/code&gt; and you’re ready to go. Yes, it really is that simple. It’s this easy because the Chrome DevTools team conveniently packages each version of Puppeteer with a version of Chromium (the headless Chrome part) that it’s guaranteed to run with.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Puppeteer requires at least Node v6.4.0, but the examples below use async/await which is only supported in Node v7.6.0 or greater. Just so ya know.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s take a look at what Puppeteer can automate.&lt;/p&gt;
&lt;p&gt;If you’d like to play with these examples yourself, you can download my &lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example&quot;&gt;GitHub repo here&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can also click on the file name for each of these code samples below to see the actual code in GitHub.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Take a screenshot of a page: &lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example/blob/master/saveFileExample.js&quot;&gt;&lt;code&gt;saveFileExample.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const puppeteer = require(&apos;puppeteer&apos;);

(async () =&amp;gt; {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(&apos;https://www.google.com&apos;);
  await page.screenshot({ path: &apos;google.png&apos; });

  await browser.close();
})();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you’ll see with all these scripts, as long as &lt;code&gt;puppeteer&lt;/code&gt; is imported at the top of the file, it’s good to go and all the methods packaged along with Puppeteer like &lt;code&gt;newPage()&lt;/code&gt; and &lt;code&gt;browser&lt;/code&gt; are instantly available to you.&lt;/p&gt;
&lt;p&gt;This first sample script goes to the Google home page and takes a photo of the page and saves it to a .png file inside of the repo named &quot;google.png&quot;.&lt;/p&gt;
&lt;p&gt;The code is pretty self-explanatory. To begin, a headless Chrome browser is launched, a new page is opened, the URL for that page is set to Google, a screenshot is taken for posterity and the browser is closed. The whole thing is clean, elegant, asynchronous and wrapped within an IIFE (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IIFE&quot;&gt;immediately invoked function expression&lt;/a&gt;) so as soon as the script is called, the function runs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create a PDF: &lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example/blob/master/createPDF.js&quot;&gt;&lt;code&gt;createPDF.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const puppeteer = require(&apos;puppeteer&apos;);

(async () =&amp;gt; {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(&apos;https://www.thinkgeek.com/&apos;, { waitUntil: &apos;networkidle2&apos; });
  await page.pdf({ path: &apos;thinkGeek.pdf&apos;, format: &apos;A4&apos; });

  await browser.close();
})();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second Puppeteer example goes to a website (the fun retail website, ThinkGeek, in this case) and makes the site page it visits into a PDF.&lt;/p&gt;
&lt;p&gt;Similar to the first script, this one sets up Puppeteer, creates a new browser page, goes to ThinkGeek’s website and then uses the &lt;code&gt;page.pdf()&lt;/code&gt; method to make a PDF of the whole page. That PDF is once again, saved into the project folder under the name &quot;thinkGeek.pdf&quot;. Pretty simple.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Google something: &lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example/blob/master/searchGoogle.js&quot;&gt;&lt;code&gt;searchGoogle.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const puppeteer = require(&apos;puppeteer&apos;);

(async () =&amp;gt; {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(&apos;https://www.google.com&apos;);

  const searchBox = await page.$(&apos;input[type=text]&apos;);
  await searchBox.type(&apos;cookies&apos;);
  const inputElement = await page.$(
    &apos;input[type=submit][value=&quot;Google Search&quot;]&apos;,
  );
  await inputElement.click();
  const [response] = await Promise.all([
    page.waitForNavigation(),
    page.once(&apos;load&apos;, () =&amp;gt; console.log(&apos;Cookies loaded!&apos;)),
  ]);

  await page.screenshot({ path: &apos;cookies.png&apos; });
  await browser.close();
})();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This third example is probably something more like what would be tested in an end-to-end test — it’s automating a Google search (and taking a screenshot to confirm the search worked, in headless mode).&lt;/p&gt;
&lt;p&gt;In this script, Puppeteer launches a new browser page, it goes to Google, it waits for the search box and the search button to be visible and types &quot;cookies&quot; into the input, then it waits for the page to navigate to the cookies search results and takes a screenshot before closing the browser at the end.&lt;/p&gt;
&lt;p&gt;And that’s all there is to it. To see more of what Puppeteer can do, I recommend checking out their very thorough &lt;a href=&quot;https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md&quot;&gt;documentation&lt;/a&gt; — there’s a whole lot of info and functionality to discover there.&lt;/p&gt;
&lt;h3&gt;Debugging Puppeteer&lt;/h3&gt;
&lt;p&gt;Now that Puppeteer is running, I want to call out some awesome tools that are built into it to make debugging it much less painful. Here&apos;s the code snippet you need, which I&apos;ll break down next.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const browser = await puppeteer.launch({
  headless: false,
  slowMo: 500,
  devtools: true
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Turn off headless mode&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first (and most obvious one) is how to turn off Chrome’s headless mode; meaning you can watch the automated browser open and attempt to go through the steps laid out for it.&lt;/p&gt;
&lt;p&gt;This is a cinch. Inside the script where Puppeteer is launched (pretty much the first thing that happens when the script runs), just add the following line: &lt;code&gt;puppeteer.launch({headless: false});&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enable SlowMo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SlowMo is just what it sounds like, it slows down Puppeteer’s operations so normal humans can see what’s going on. It can be instantiated in the same command where headless is set to false for Puppeteer; the &lt;code&gt;puppeteer.launch()&lt;/code&gt; command. Just add &lt;code&gt;puppeteer.launch({slowMo: 500})&lt;/code&gt; or however many milliseconds you want to slow down the actions by.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Auto-open DevTools panel&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The third debugging trick I have is how to tell Puppeteer whether to auto-open a Chrome DevTools panel with each tab. So if you need to, you can catch things being logged to the console inside the automated test run.&lt;/p&gt;
&lt;p&gt;Once again, inside the initial command launching Puppeteer, add in &lt;code&gt;puppeteer.launch({headless: false, devtools: true});&lt;/code&gt; to open a DevTools panel.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If this option is &lt;code&gt;true&lt;/code&gt;, the &lt;code&gt;headless&lt;/code&gt; option will be set &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can even &lt;code&gt;console.log()&lt;/code&gt; events from the headless Chrome browser to your own terminal by simply throwing this method from &lt;code&gt;page.exposeFunction()&lt;/code&gt; into the mix. Right after the page object is defined in the Puppeteer script, you can do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;page.on(&quot;console&quot;, msg =&amp;gt; console.log(`Page Console: ${msg.text()}`));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to catch messages from &lt;code&gt;console.log&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That should help get you on your way to debugging your Puppeteer headless Chrome instances and tests like a pro.&lt;/p&gt;
&lt;h3&gt;More cool features of Puppeteer&lt;/h3&gt;
&lt;p&gt;In addition to debugging Puppeteer, I wanted to point out a few more cool features that it offers. If you’re interested in learning more about any of them, I’d recommend checking out their &lt;a href=&quot;https://www.npmjs.com/package/puppeteer&quot;&gt;npm page&lt;/a&gt; for more info.&lt;/p&gt;
&lt;p&gt;Puppeteer can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run in a Docker container or serverless environment,&lt;/li&gt;
&lt;li&gt;Intercept network requests,&lt;/li&gt;
&lt;li&gt;Capture performance info,&lt;/li&gt;
&lt;li&gt;Test a Chrome extension,&lt;/li&gt;
&lt;li&gt;Run code in a page, and&lt;/li&gt;
&lt;li&gt;Emulate Chrome on a mobile device.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s a lot of additional useful things it can be used for. The team really wants to make it useful to devs in many ways.&lt;/p&gt;
&lt;h3&gt;Bonus: React &amp;amp; Jest &amp;amp; Puppeteer&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/chrome-puppeteer-e2e-testing/react-jest.png&quot; alt=&quot;Logos of React and Jest&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I’d be remiss if I didn’t also briefly mention how to integrate Puppeteer into a React project with Jest tests. React is my current JavaScript framework of choice (and it seems the same for many JS developers), so I created a quick setup and test script using the two together, also housed in the my sample &lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example&quot;&gt;GitHub repo here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configuration for Jest &amp;amp; Puppeteer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Jest has some very helpful &lt;a href=&quot;https://jestjs.io/docs/en/puppeteer&quot;&gt;documentation&lt;/a&gt; to smoothly work Puppeteer into its own testing framework, and there’s even an entire npm package named &lt;code&gt;jest-puppeteer&lt;/code&gt; to help the process along. Here’s what to install and configure to make Jest and Puppeteer play nice.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev jest-puppeteer puppeteer jest 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once everything’s been installed, you can either configure your Jest config file, Webpack file or your &lt;code&gt;package.json&lt;/code&gt; file to let Jest know that Puppeteer’s there and ready to be used. Here’s how I did it in the &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Right above the scripts in the file, I added this snippet, and inside the &lt;code&gt;scripts&lt;/code&gt;, I included a &lt;code&gt;test&lt;/code&gt; command which just runs Jest.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example/blob/master/package.json&quot;&gt;&lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;jest&quot;: {
    &quot;preset&quot;: &quot;jest-puppeteer&quot;
  },
  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;jest&quot;,
    /* more scripts here */
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, I’m ready to write tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jest &amp;amp; Puppeteer Test: &lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example/blob/master/google.test.js&quot;&gt;&lt;code&gt;google.test.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;describe(&apos;Google&apos;, () =&amp;gt; {
  beforeAll(async () =&amp;gt; {
    await page.goto(&apos;https://google.com&apos;);
  });

  it(&apos;should display &quot;google&quot; text on page&apos;, async () =&amp;gt; {
    await expect(page).toMatch(&apos;google&apos;);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’ve ever written a Jest test before, the syntax should look familiar. Since I don’t have a full React project as part of my sample repo, I’ll use this simple example test where Jest should go to the Google homepage and find the text &quot;Google” on said page after it’s loaded.&lt;/p&gt;
&lt;p&gt;From my repo, I set up the npm script to run the &lt;code&gt;jest&lt;/code&gt; command when &lt;code&gt;npm run test&lt;/code&gt; is entered into the terminal. Jest looks for any files with the &lt;code&gt;*.test.js&lt;/code&gt; syntax, by default and tries to run those. When it finds my test file entitled google.test.js it runs it (headlessly, unless I were to specify differently) and logs out the test results to the console, like so.&lt;/p&gt;
&lt;p&gt;If tests failed, you can debug just as you normally would (and even turn on the automated Chrome browser if you need to see what’s messing up), and if not, your computer screen can be test free as your end-to-end tests still run in the background.&lt;/p&gt;
&lt;p&gt;Awesome. That doesn’t seem so hard, now does it?&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Puppeteer is a powerful tool developed by the Google DevTools team to make headless, automated browser testing easier in every way. There’s less configuration to get started, the syntax makes more sense, and it has uses that extend far beyond just testing web apps during development. Likewise, it’s easy to integrate into React applications to automate Jest tests to run headlessly as well.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about something else related to web development, so subscribe to my free newsletter so you don’t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you an idea of how to get started using Puppeteer for your own end-to-end testing and integrating with React and Jest tests.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/puppeteer-and-jest-example&quot;&gt;Puppeteer Jest sample repo&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.techopedia.com/definition/7035/end-to-end-test&quot;&gt;End-to-end testing&lt;/a&gt; on Techopedia&lt;/li&gt;
&lt;li&gt;Puppeteer docs on &lt;a href=&quot;https://www.npmjs.com/package/puppeteer&quot;&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Puppeteer repo on &lt;a href=&quot;https://github.com/GoogleChrome/puppeteer&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md&quot;&gt;Puppeteer API docs&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/docs/en/puppeteer&quot;&gt;Jest with Puppeteer site docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>e2e</category><category>jest</category><category>puppeteer</category><category>testing</category></item><item><title>Password Reset Emails In Your React App Made Easy with Nodemailer</title><link>https://www.paigeniedringhaus.com/blog/password-reset-emails-in-your-react-app-made-easy-with-nodemailer/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/password-reset-emails-in-your-react-app-made-easy-with-nodemailer/</guid><description>Resetting passwords in JavaScript apps doesn’t have to be complicated.</description><pubDate>Thu, 22 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/password-reset-email-nodemailer/nodemailer-hero.png&quot; alt=&quot;Logos of React, Node.js, and Nodemailer&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Password Resets in a MERN Application&lt;/h2&gt;
&lt;p&gt;Before I actually attempted to build in an email-based password reset for my MERN app, I thought it would be tougher to do. From everything I’d heard before, sending emails in a JavaScript application was painful, but I still wanted to attempt it.&lt;/p&gt;
&lt;p&gt;For a few months, to hone my full stack JavaScript skills, I’ve been slowly building and adding on to a &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;user registration service&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, I built it with a React frontend, an Express / Node.js backend and a Docker-powered MySQL database. I used a &lt;code&gt;docker-compose.yml&lt;/code&gt; to start the whole app with one command (if you’d like to read more about my use of Docker for development, you can see &lt;a href=&quot;./using-docker-docker-compose-to-improve-your-full-stack-app-development&quot;&gt;&lt;strong&gt;this blog post&lt;/strong&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;After I’d gotten that working, I added in authorization to the app using Passport.js and JSON Web Tokens (JWTs). You can read about the fun (pain) of that &lt;a href=&quot;./implementing-json-web-tokens-passport-js-in-a-react-app&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;, if you’re curious. And it took me a while — I ran into a bunch of road blocks and obstacles that stalled me out multiple times. But grit and my inability to let go of a problem once it’s taken root in my brain prevailed, and I figured it out and moved on.&lt;/p&gt;
&lt;p&gt;When I decided to tackle sending password reset links via email (just like real sites when users, myself included, inevitably forget their password), I figured I was in for more pain. It just couldn’t be too easy, no matter that practically every site out there has this very functionality. But I was wrong. And I’m so glad I was.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how to set up your own password reset system with help from Nodemailer.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Nodemailer: the magic bullet&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/password-reset-email-nodemailer/nodemailer-logo.png&quot; alt=&quot;Nodemailer logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Once I started googling around looking for solutions to my password reset feature, I came across a number of articles recommending &lt;a href=&quot;https://nodemailer.com/about/&quot;&gt;Nodemailer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When I visited the website, the first lines I read were:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nodemailer is a module for Node.js applications to allow easy as cake email sending. The project got started back in 2010 when there was no sane option to send email messages, today it is the solution most Node.js users turn to by default. — Nodemailer&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And you know what? It wasn’t kidding. Easy as cake isn’t too far wrong.&lt;/p&gt;
&lt;p&gt;Of course, before I got started, I did a little more digging to make sure I was placing my faith in a decent piece of technology, and what I saw on &lt;a href=&quot;https://www.npmjs.com/package/nodemailer&quot;&gt;npm&lt;/a&gt; and &lt;a href=&quot;https://github.com/nodemailer/nodemailer&quot;&gt;GitHub&lt;/a&gt; put my mind at ease.&lt;/p&gt;
&lt;p&gt;Nodemailer has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Over 615,000 weekly downloads from NPM,&lt;/li&gt;
&lt;li&gt;Over 10,000 stars on Github,&lt;/li&gt;
&lt;li&gt;206 releases to date,&lt;/li&gt;
&lt;li&gt;Over 2,500 dependent packages,&lt;/li&gt;
&lt;li&gt;And it’s been around in some form or fashion since 2010.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ok, that seemed good enough for me to give it a shot in my own project.&lt;/p&gt;
&lt;h3&gt;Implementation of Nodemailer in my code (frontend and backend)&lt;/h3&gt;
&lt;p&gt;I didn’t need anything fancy for my password reset, just:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A way to send an email to a user’s address.&lt;/li&gt;
&lt;li&gt;That email would contain a link that would redirect them to a protected page on my site where they could reset their password.&lt;/li&gt;
&lt;li&gt;Then they could log in using their new password.&lt;/li&gt;
&lt;li&gt;I also wanted the password reset link to expire after a certain time period for better security.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s how I did it.&lt;/p&gt;
&lt;h3&gt;Frontend code (client folder): send reset email&lt;/h3&gt;
&lt;p&gt;I’ll start with the React code first, because I had to have a page where users could enter their email addresses and fire off the email with the reset link.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/client/src/containers/ForgotPassword.js&quot;&gt;&lt;strong&gt;&lt;code&gt;ForgotPassword.js&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable no-console */
import React, { Component } from &apos;react&apos;;
import TextField from &apos;@material-ui/core/TextField&apos;;
import axios from &apos;axios&apos;;
import {
  LinkButtons,
  SubmitButtons,
  registerButton,
  homeButton,
  forgotButton,
  inputStyle,
  HeaderBar,
} from &apos;../components&apos;;

const title = {
  pageTitle: &apos;Forgot Password Screen&apos;,
};

class ForgotPassword extends Component {
  constructor() {
    super();

    this.state = {
      email: &apos;&apos;,
      showError: false,
      messageFromServer: &apos;&apos;,
      showNullError: false,
    };
  }

  handleChange = name =&amp;gt; (event) =&amp;gt; {
    this.setState({
      [name]: event.target.value,
    });
  };

  sendEmail = async (e) =&amp;gt; {
    e.preventDefault();
    const { email } = this.state;
    if (email === &apos;&apos;) {
      this.setState({
        showError: false,
        messageFromServer: &apos;&apos;,
        showNullError: true,
      });
    } else {
      try {
        const response = await axios.post(
          &apos;http://localhost:3003/forgotPassword&apos;,
          {
            email,
          },
        );
        if (response.data === &apos;recovery email sent&apos;) {
          this.setState({
            showError: false,
            messageFromServer: &apos;recovery email sent&apos;,
            showNullError: false,
          });
        }
      } catch (error) {
        console.error(error.response.data);
        if (error.response.data === &apos;email not in db&apos;) {
          this.setState({
            showError: true,
            messageFromServer: &apos;&apos;,
            showNullError: false,
          });
        }
      }
    }
  };

  render() {
    const { email, messageFromServer, showNullError, showError } = this.state;

    return (
      &amp;lt;div&amp;gt;
        &amp;lt;HeaderBar title={title} /&amp;gt;
        &amp;lt;form className=&quot;profile-form&quot; onSubmit={this.sendEmail}&amp;gt;
          &amp;lt;TextField
            style={inputStyle}
            id=&quot;email&quot;
            label=&quot;email&quot;
            value={email}
            onChange={this.handleChange(&apos;email&apos;)}
            placeholder=&quot;Email Address&quot;
          /&amp;gt;
          &amp;lt;SubmitButtons
            buttonStyle={forgotButton}
            buttonText=&quot;Send Password Reset Email&quot;
          /&amp;gt;
        &amp;lt;/form&amp;gt;
        {showNullError &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;The email address cannot be null.&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        {showError &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;
              That email address isn&apos;t recognized. Please try again or
              register for a new account.
            &amp;lt;/p&amp;gt;
            &amp;lt;LinkButtons
              buttonText=&quot;Register&quot;
              buttonStyle={registerButton}
              link=&quot;/register&quot;
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        {messageFromServer === &apos;recovery email sent&apos; &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;h3&amp;gt;Password Reset Email Successfully Sent!&amp;lt;/h3&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        &amp;lt;LinkButtons buttonText=&quot;Go Home&quot; buttonStyle={homeButton} link=&quot;/&quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
}

export default ForgotPassword;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, I know this is a big code snippet but I’ll break it down.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you want to copy/paste the actual code, you can see the whole repo &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What you should really focus on here is the &lt;code&gt;sendEmail() &lt;/code&gt;function and the &lt;code&gt;render()&lt;/code&gt; method of the component. The rest is just setting initial state and variables, and styling of buttons and elements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The render() method&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;render() {
    const { email, messageFromServer, showNullError, showError } = this.state;

    return (
      &amp;lt;div&amp;gt;
        &amp;lt;HeaderBar title={title} /&amp;gt;
        &amp;lt;form className=&quot;profile-form&quot; onSubmit={this.sendEmail}&amp;gt;
          &amp;lt;TextField
            style={inputStyle}
            id=&quot;email&quot;
            label=&quot;email&quot;
            value={email}
            onChange={this.handleChange(&apos;email&apos;)}
            placeholder=&quot;Email Address&quot;
          /&amp;gt;
          &amp;lt;SubmitButtons
            buttonStyle={forgotButton}
            buttonText=&quot;Send Password Reset Email&quot;
          /&amp;gt;
        &amp;lt;/form&amp;gt;
        {showNullError &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;The email address cannot be null.&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        {showError &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;
              That email address isn&amp;amp;apos;t recognized. Please try again or
              register for a new account.
            &amp;lt;/p&amp;gt;
            &amp;lt;LinkButtons
              buttonText=&quot;Register&quot;
              buttonStyle={registerButton}
              link=&quot;/register&quot;
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        {messageFromServer === &apos;recovery email sent&apos; &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;h3&amp;gt;Password Reset Email Successfully Sent!&amp;lt;/h3&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        &amp;lt;LinkButtons buttonText=&quot;Go Home&quot; buttonStyle={homeButton} link=&quot;/&quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice inside the &lt;code&gt;render()&lt;/code&gt; method, that I have a simple input box for the user to enter his/her email address, and a submit button which triggers the &lt;code&gt;this.sendEmail()&lt;/code&gt; function when clicked. Beyond that, I have a little error and success handling built in based on if the user hasn’t entered an email, if the server responds back the email was successfully sent or it wasn’t a recognized address.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The sendEmail() function&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  sendEmail = async (e) =&amp;gt; {
    e.preventDefault();
    const { email } = this.state;
    if (email === &apos;&apos;) {
      this.setState({
        showError: false,
        messageFromServer: &apos;&apos;,
        showNullError: true,
      });
    } else {
      try {
        const response = await axios.post(
          &apos;http://localhost:3003/forgotPassword&apos;,
          {
            email,
          },
        );
        if (response.data === &apos;recovery email sent&apos;) {
          this.setState({
            showError: false,
            messageFromServer: &apos;recovery email sent&apos;,
            showNullError: false,
          });
        }
      } catch (error) {
        console.error(error.response.data);
        if (error.response.data === &apos;email not in db&apos;) {
          this.setState({
            showError: true,
            messageFromServer: &apos;&apos;,
            showNullError: false,
          });
        }
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For all of my HTTP requests, I’m using the &lt;a href=&quot;https://www.npmjs.com/package/axios&quot;&gt;Axios library&lt;/a&gt;, which just makes it really easy to make AJAX calls to the server, even easier than the built in fetch() web API, in my opinion.&lt;/p&gt;
&lt;p&gt;When the user enters his/her email, I make a &lt;code&gt;POST&lt;/code&gt; request to the server, and wait for a response. If the email address isn’t found, I can tell the user they entered it wrong or if they’re new, they can go to the register page and create an account, and if the address does match one in my database, they’ll get back a success message saying the password reset link has been sent to their email address.&lt;/p&gt;
&lt;p&gt;Let’s move on to the backend code now.&lt;/p&gt;
&lt;h3&gt;Backend code (API Folder): send reset email&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/forgotPassword.js&quot;&gt;&lt;strong&gt;&lt;code&gt;forgotPassword.js&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable max-len */
/* eslint-disable no-console */
import crypto from &apos;crypto&apos;;
import User from &apos;../sequelize&apos;;

require(&apos;dotenv&apos;).config();

const nodemailer = require(&apos;nodemailer&apos;);

module.exports = (app) =&amp;gt; {
  app.post(&apos;/forgotPassword&apos;, (req, res) =&amp;gt; {
    if (req.body.email === &apos;&apos;) {
      res.status(400).send(&apos;email required&apos;);
    }
    console.error(req.body.email);
    User.findOne({
      where: {
        email: req.body.email,
      },
    }).then((user) =&amp;gt; {
      if (user === null) {
        console.error(&apos;email not in database&apos;);
        res.status(403).send(&apos;email not in db&apos;);
      } else {
        const token = crypto.randomBytes(20).toString(&apos;hex&apos;);
        user.update({
          resetPasswordToken: token,
          resetPasswordExpires: Date.now() + 3600000,
        });

        const transporter = nodemailer.createTransport({
          service: &apos;gmail&apos;,
          auth: {
            user: `${process.env.EMAIL_ADDRESS}`,
            pass: `${process.env.EMAIL_PASSWORD}`,
          },
        });

        const mailOptions = {
          from: &apos;mySqlDemoEmail@gmail.com&apos;,
          to: `${user.email}`,
          subject: &apos;Link To Reset Password&apos;,
          text:
            &apos;You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n&apos;
            + &apos;Please click on the following link, or paste this into your browser to complete the process within one hour of receiving it:\n\n&apos;
            + `http://localhost:3031/reset/${token}\n\n`
            + &apos;If you did not request this, please ignore this email and your password will remain unchanged.\n&apos;,
        };

        console.log(&apos;sending mail&apos;);

        transporter.sendMail(mailOptions, (err, response) =&amp;gt; {
          if (err) {
            console.error(&apos;there was an error: &apos;, err);
          } else {
            res.status(200).json(&apos;recovery email sent&apos;);
          }
        });
      }
    });
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The backend code is a little more involved. This is where Nodemailer comes into play.&lt;/p&gt;
&lt;p&gt;When the user hits the &lt;code&gt;forgotPassword&lt;/code&gt; route on the backend with the email address they entered, the first thing &lt;a href=&quot;./sequelize-like-mongoose-but-for-sql&quot;&gt;Sequelize&lt;/a&gt; (my SQL ORM) does is check if that email exists in my database. If it doesn’t the user gets notified they may have mistyped it, if it does exist, then a series of other events starts.&lt;/p&gt;
&lt;p&gt;None of the following steps is very difficult, it’s just chaining them all together that was a little tricky, at first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Generate an expiring token for the user&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; const token = crypto.randomBytes(20).toString(&apos;hex&apos;);
        user.update({
          resetPasswordToken: token,
          resetPasswordExpires: Date.now() + 3600000,
        });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first step after confirming the email belongs to a user in the database, is generating a token that can be attached to the user’s account and setting a time limit for that token to be valid.&lt;/p&gt;
&lt;p&gt;Node.js has a built in module called &lt;a href=&quot;https://nodejs.org/api/crypto.html#crypto_crypto&quot;&gt;Crypto&lt;/a&gt;, which provides cryptographic functionality, which is a fancy way of saying, I can generate a unique hash token easily using the JavaScript &lt;code&gt;crypto.randomBytes(20).toString(&apos;hex&apos;);&lt;/code&gt;. Then, I save that new token to my user’s profile in the database under the column name &lt;code&gt;resetPasswordToken&lt;/code&gt;. I also set a timestamp for how long that token will be valid. I made mine valid for one hour after sending the link: &lt;code&gt;Date.now() + 3600000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Create Nodemailer transport&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; const transporter = nodemailer.createTransport({
          service: &apos;gmail&apos;,
          auth: {
            user: `${process.env.EMAIL_ADDRESS}`,
            pass: `${process.env.EMAIL_PASSWORD}`,
          },
        });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I created the transporter which is actually the account sending the password reset email link.&lt;/p&gt;
&lt;p&gt;I chose to use Gmail, because I use Gmail personally, and I created a new dummy account to send the emails. Since I don’t want to give out the credentials for that account to anyone, I put the credentials into a &lt;code&gt;.env&lt;/code&gt; file that is included in my &lt;code&gt;.gitignore&lt;/code&gt; so it never gets committed to GitHub or anywhere else.&lt;/p&gt;
&lt;p&gt;The npm package &lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot;&gt;dotenv&lt;/a&gt; is used to read the contents of the file and insert the email address and password for Nodemailer’s [createTransport()] function to pick up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Create mail options&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; const mailOptions = {
          from: &apos;mySqlDemoEmail@gmail.com&apos;,
          to: `${user.email}`,
          subject: &apos;Link To Reset Password&apos;,
          text:
            &apos;You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n&apos;
            + &apos;Please click on the following link, or paste this into your browser to complete the process within one hour of receiving it:\n\n&apos;
            + `http://localhost:3031/reset/${token}\n\n`
            + &apos;If you did not request this, please ignore this email and your password will remain unchanged.\n&apos;,
        };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The third step is creating the email template or &lt;code&gt;mailOptions&lt;/code&gt; as Nodemailer calls it that the user will see (and this is also where the verified email address they pass from the frontend input gets used).&lt;/p&gt;
&lt;p&gt;There are whole third-party libraries for making great looking emails to go with the Nodemailer module, but I just wanted a bare bones email, so I made this one myself.&lt;/p&gt;
&lt;p&gt;It contains the &lt;code&gt;from&lt;/code&gt; email address (mySqlDemoEmail[at]gmail.com, for me), the user’s email goes in the &lt;code&gt;to&lt;/code&gt; box, the &lt;code&gt;subject&lt;/code&gt; line is something along the lines of reset password link, and the &lt;code&gt;text&lt;/code&gt; is a simple string containing a little info and the website’s URL reset route including the token I created earlier, tacked on to the end. This will allow me to verify the user is who they say they are when they click the link and go to the site to reset their password.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Send Email&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        transporter.sendMail(mailOptions, (err, response) =&amp;gt; {
          if (err) {
            console.error(&apos;there was an error: &apos;, err);
          } else {
            res.status(200).json(&apos;recovery email sent&apos;);
          }
        });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final step of this file actually putting together the pieces I created: the &lt;code&gt;transporter&lt;/code&gt;, the &lt;code&gt;mailOptions&lt;/code&gt;, the &lt;code&gt;token&lt;/code&gt; and using Nodemailer’s &lt;code&gt;sendMail()&lt;/code&gt; function. If it works, I’ll get back a 200 response, which I then use to trigger a success call to the client, and if it fails, I log out the error to see what went wrong.&lt;/p&gt;
&lt;h3&gt;Enabling Gmail to send reset emails&lt;/h3&gt;
&lt;p&gt;There’s an extra gotcha to be aware of when setting up the transporter email that all the emails are sent from, at least, when using Gmail.&lt;/p&gt;
&lt;p&gt;In order to be able to send emails from an account, 2-Step verification must be disabled, and a setting titled ‘Allow less secure apps’ must be toggled to on. See screenshot below. To do this, I went to my settings &lt;a href=&quot;https://myaccount.google.com/lesssecureapps&quot;&gt;here&lt;/a&gt;, and turned it on.&lt;/p&gt;
&lt;p&gt;Now, I could send reset emails with no problems. If you’re having trouble, check Nodemailer’s FAQs for more help.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/password-reset-email-nodemailer/gmail-less-secure.png&quot; alt=&quot;Make Gmail less secure to practice sending reset emails&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is the screen you should see where you can turn ‘on’ less secure apps. Just one more reason to use some dummy email account instead of your actual Gmail account too.
&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Frontend code: update password screen&lt;/h3&gt;
&lt;p&gt;Great, now users should be getting reset emails in their inbox that look something like this.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/password-reset-email-nodemailer/password-reset-email.png&quot; alt=&quot;Password reset email&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;It’s a simple email, but it does what I need it to do.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If you notice, the third line is a link to my website (running locally on port 3031), to another page called ‘Reset’, followed by the hashed token I generated back in step 1 with the Node.js &lt;code&gt;crypto&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;When a user clicks this link, they’re directed to a new page in the application entitled ‘Password Reset Screen’, which can only be accessed with a valid token. If the token has expired or is otherwise invalid, the user will see an error screen with links to go home or attempt to send a new password reset email.&lt;/p&gt;
&lt;p&gt;Here’s the React code for the reset screen.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/client/src/containers/ResetPassword.js&quot;&gt;&lt;strong&gt;&lt;code&gt;ResetPassword.js&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable no-console */
import React, { Component } from &apos;react&apos;;
import PropTypes from &apos;prop-types&apos;;
import axios from &apos;axios&apos;;
import TextField from &apos;@material-ui/core/TextField&apos;;

import {
  LinkButtons,
  updateButton,
  homeButton,
  loginButton,
  HeaderBar,
  forgotButton,
  inputStyle,
  SubmitButtons,
} from &apos;../components&apos;;

const loading = {
  margin: &apos;1em&apos;,
  fontSize: &apos;24px&apos;,
};

const title = {
  pageTitle: &apos;Password Reset Screen&apos;,
};

export default class ResetPassword extends Component {
  constructor() {
    super();

    this.state = {
      username: &apos;&apos;,
      password: &apos;&apos;,
      updated: false,
      isLoading: true,
      error: false,
    };
  }

  async componentDidMount() {
    const {
      match: {
        params: { token },
      },
    } = this.props;
    try {
      const response = await axios.get(&apos;http://localhost:3003/reset&apos;, {
        params: {
          resetPasswordToken: token,
        },
      });
      if (response.data.message === &apos;password reset link a-ok&apos;) {
        this.setState({
          username: response.data.username,
          updated: false,
          isLoading: false,
          error: false,
        });
      }
    } catch (error) {
      console.log(error.response.data);
      this.setState({
        updated: false,
        isLoading: false,
        error: true,
      });
    }
  }

  handleChange = name =&amp;gt; (event) =&amp;gt; {
    this.setState({
      [name]: event.target.value,
    });
  };

  updatePassword = async (e) =&amp;gt; {
    e.preventDefault();
    const { username, password } = this.state;
    const {
      match: {
        params: { token },
      },
    } = this.props;
    try {
      const response = await axios.put(
        &apos;http://localhost:3003/updatePasswordViaEmail&apos;,
        {
          username,
          password,
          resetPasswordToken: token,
        },
      );
      if (response.data.message === &apos;password updated&apos;) {
        this.setState({
          updated: true,
          error: false,
        });
      } else {
        this.setState({
          updated: false,
          error: true,
        });
      }
    } catch (error) {
      console.log(error.response.data);
    }
  };

  render() {
    const {
 password, error, isLoading, updated 
} = this.state;

    if (error) {
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;HeaderBar title={title} /&amp;gt;
          &amp;lt;div style={loading}&amp;gt;
            &amp;lt;h4&amp;gt;Problem resetting password. Please send another reset link.&amp;lt;/h4&amp;gt;
            &amp;lt;LinkButtons
              buttonText=&quot;Go Home&quot;
              buttonStyle={homeButton}
              link=&quot;/&quot;
            /&amp;gt;
            &amp;lt;LinkButtons
              buttonStyle={forgotButton}
              buttonText=&quot;Forgot Password?&quot;
              link=&quot;/forgotPassword&quot;
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      );
    }

    if (isLoading) {
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;HeaderBar title={title} /&amp;gt;
          &amp;lt;div style={loading}&amp;gt;Loading User Data...&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      );
    }

    return (
      &amp;lt;div&amp;gt;
        &amp;lt;HeaderBar title={title} /&amp;gt;
        &amp;lt;form className=&quot;password-form&quot; onSubmit={this.updatePassword}&amp;gt;
          &amp;lt;TextField
            style={inputStyle}
            id=&quot;password&quot;
            label=&quot;password&quot;
            onChange={this.handleChange(&apos;password&apos;)}
            value={password}
            type=&quot;password&quot;
          /&amp;gt;
          &amp;lt;SubmitButtons
            buttonStyle={updateButton}
            buttonText=&quot;Update Password&quot;
          /&amp;gt;
        &amp;lt;/form&amp;gt;

        {updated &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;
              Your password has been successfully reset, please try logging in
              again.
            &amp;lt;/p&amp;gt;
            &amp;lt;LinkButtons
              buttonStyle={loginButton}
              buttonText=&quot;Login&quot;
              link=&quot;/login&quot;
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        &amp;lt;LinkButtons buttonText=&quot;Go Home&quot; buttonStyle={homeButton} link=&quot;/&quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
}

ResetPassword.propTypes = {
  // eslint-disable-next-line react/require-default-props
  match: PropTypes.shape({
    params: PropTypes.shape({
      token: PropTypes.string.isRequired,
    }),
  }),
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here’s the three main pieces of this component that do the heavy lifting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The initial componentDidMount() lifecycle method&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  async componentDidMount() {
    const {
      match: {
        params: { token },
      },
    } = this.props;
    try {
      const response = await axios.get(&apos;http://localhost:3003/reset&apos;, {
        params: {
          resetPasswordToken: token,
        },
      });
      if (response.data.message === &apos;password reset link a-ok&apos;) {
        this.setState({
          username: response.data.username,
          updated: false,
          isLoading: false,
          error: false,
        });
      }
    } catch (error) {
      console.log(error.response.data);
      this.setState({
        updated: false,
        isLoading: false,
        error: true,
      });
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method fires as soon as the page is reached. It extracts the token from the URL query parameters and passes it back to the server’s &lt;code&gt;reset&lt;/code&gt; route to verify the token is legit.&lt;/p&gt;
&lt;p&gt;Then, the server either responds with an &quot;a-ok&quot;, this token is valid and associated with the user or a &quot;no&quot;, the token’s no good anymore for some reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The updatePassword() function&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; updatePassword = async (e) =&amp;gt; {
    e.preventDefault();
    const { username, password } = this.state;
    const {
      match: {
        params: { token },
      },
    } = this.props;
    try {
      const response = await axios.put(
        &apos;http://localhost:3003/updatePasswordViaEmail&apos;,
        {
          username,
          password,
          resetPasswordToken: token,
        },
      );
      if (response.data.message === &apos;password updated&apos;) {
        this.setState({
          updated: true,
          error: false,
        });
      } else {
        this.setState({
          updated: false,
          error: true,
        });
      }
    } catch (error) {
      console.log(error.response.data);
    }
  };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the function that will fire if the user is authenticated and allowed to reset their password. It also accesses a specific route on the server called &lt;code&gt;updatePasswordViaEmail()&lt;/code&gt; (I did this because I gave users a separate route to update their password while logged in to the app, as well), and once the updated password has been saved to the database, a success message response is sent back to the client.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The render() method&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  render() {
    const { password, error, isLoading, updated } = this.state;

    if (error) {
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;HeaderBar title={title} /&amp;gt;
          &amp;lt;div style={loading}&amp;gt;
            &amp;lt;h4&amp;gt;Problem resetting password. Please send another reset link.&amp;lt;/h4&amp;gt;
            &amp;lt;LinkButtons
              buttonText=&quot;Go Home&quot;
              buttonStyle={homeButton}
              link=&quot;/&quot;
            /&amp;gt;
            &amp;lt;LinkButtons
              buttonStyle={forgotButton}
              buttonText=&quot;Forgot Password?&quot;
              link=&quot;/forgotPassword&quot;
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      );
    }

    if (isLoading) {
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;HeaderBar title={title} /&amp;gt;
          &amp;lt;div style={loading}&amp;gt;Loading User Data...&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      );
    }

    return (
      &amp;lt;div&amp;gt;
        &amp;lt;HeaderBar title={title} /&amp;gt;
        &amp;lt;form className=&quot;password-form&quot; onSubmit={this.updatePassword}&amp;gt;
          &amp;lt;TextField
            style={inputStyle}
            id=&quot;password&quot;
            label=&quot;password&quot;
            onChange={this.handleChange(&apos;password&apos;)}
            value={password}
            type=&quot;password&quot;
          /&amp;gt;
          &amp;lt;SubmitButtons
            buttonStyle={updateButton}
            buttonText=&quot;Update Password&quot;
          /&amp;gt;
        &amp;lt;/form&amp;gt;

        {updated &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;
              Your password has been successfully reset, please try logging in again.
            &amp;lt;/p&amp;gt;
            &amp;lt;LinkButtons
              buttonStyle={loginButton}
              buttonText=&quot;Login&quot;
              link=&quot;/login&quot;
            /&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
        &amp;lt;LinkButtons buttonText=&quot;Go Home&quot; buttonStyle={homeButton} link=&quot;/&quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last piece of this component, is the &lt;code&gt;render()&lt;/code&gt; method. Initially, while the token is being verified for its validity, the &lt;code&gt;loading&lt;/code&gt; message shows.&lt;/p&gt;
&lt;p&gt;If the link is invalid in some way, the &lt;code&gt;error&lt;/code&gt; message shows on the screen with links back to the home screen or forgot password page.&lt;/p&gt;
&lt;p&gt;If the user is authorized to reset their password, they get the new password input with the &lt;code&gt;updatePassword()&lt;/code&gt; function attached to it, and once the server’s responded with success updating the password, the &lt;code&gt;updated&lt;/code&gt; boolean is set to true and the &lt;code&gt;Your password has been successfully reset...&lt;/code&gt; message is shown along with a login button.&lt;/p&gt;
&lt;h3&gt;Backend code: reset password &amp;amp; update password&lt;/h3&gt;
&lt;p&gt;Ok, I’m in the home stretch now. Here’s the last two routes on the server side you’ll need. These correspond to the two methods I just walked through on the client side in the React &lt;code&gt;ResetPassword.js&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/resetPassword.js&quot;&gt;&lt;strong&gt;&lt;code&gt;resetPassword.js&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable no-console */
/* eslint-disable max-len */
import Sequelize from &apos;sequelize&apos;;
import User from &apos;../sequelize&apos;;

// eslint-disable-next-line prefer-destructuring
const Op = Sequelize.Op;

module.exports = (app) =&amp;gt; {
  app.get(&apos;/reset&apos;, (req, res) =&amp;gt; {
    User.findOne({
      where: {
        resetPasswordToken: req.query.resetPasswordToken,
        resetPasswordExpires: {
          [Op.gt]: Date.now(),
        },
      },
    }).then((user) =&amp;gt; {
      if (user == null) {
        console.error(&apos;password reset link is invalid or has expired&apos;);
        res.status(403).send(&apos;password reset link is invalid or has expired&apos;);
      } else {
        res.status(200).send({
          username: user.username,
          message: &apos;password reset link a-ok&apos;,
        });
      }
    });
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the route that’s called on the &lt;code&gt;componentDidMount()&lt;/code&gt; lifecycle method on the client side. It checks the &lt;code&gt;resetPasswordToken&lt;/code&gt; passed from the link’s query parameters and date timestamp to ensure that everything’s good.&lt;/p&gt;
&lt;p&gt;You’ll notice the &lt;code&gt;resetPasswordExpires&lt;/code&gt; parameter has an odd looking &lt;code&gt;$gt: Date.now()&lt;/code&gt; parameter. This is an &lt;a href=&quot;http://docs.sequelizejs.com/manual/tutorial/querying.html#operators-aliases&quot;&gt;operator alias comparator&lt;/a&gt;, which &lt;a href=&quot;http://docs.sequelizejs.com/&quot;&gt;Sequelize&lt;/a&gt; allows me to use, and all the &lt;code&gt;$gt:&lt;/code&gt; stands for is &quot;greater than&quot; whatever it is being compared to. In this instance, it’s comparing the current time to the expiration time stamp saved to the database when the reset password email was sent, to make sure the password’s being reset less than an hour after the email was sent.&lt;/p&gt;
&lt;p&gt;As long as both parameters are valid for that user, the client is sent a successful response and the user can proceed with the password reset.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/updatePasswordViaEmail.js&quot;&gt;&lt;strong&gt;&lt;code&gt;updatePasswordViaEmail.js&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* eslint-disable no-console */
import bcrypt from &apos;bcrypt&apos;;
import Sequelize from &apos;sequelize&apos;;
import User from &apos;../sequelize&apos;;

// eslint-disable-next-line prefer-destructuring
const Op = Sequelize.Op;

const BCRYPT_SALT_ROUNDS = 12;

module.exports = app =&amp;gt; {
  app.put(&apos;/updatePasswordViaEmail&apos;, (req, res) =&amp;gt; {
    User.findOne({
      where: {
        username: req.body.username,
        resetPasswordToken: req.body.resetPasswordToken,
        resetPasswordExpires: {
          [Op.gt]: Date.now(),
        },
      },
    }).then(user =&amp;gt; {
      if (user == null) {
        console.error(&apos;password reset link is invalid or has expired&apos;);
        res.status(403).send(&apos;password reset link is invalid or has expired&apos;);
      } else if (user != null) {
        console.log(&apos;user exists in db&apos;);
        bcrypt
          .hash(req.body.password, BCRYPT_SALT_ROUNDS)
          .then(hashedPassword =&amp;gt; {
            user.update({
              password: hashedPassword,
              resetPasswordToken: null,
              resetPasswordExpires: null,
            });
          })
          .then(() =&amp;gt; {
            console.log(&apos;password updated&apos;);
            res.status(200).send({ message: &apos;password updated&apos; });
          });
      } else {
        console.error(&apos;no user exists in db to update&apos;);
        res.status(401).json(&apos;no user exists in db to update&apos;);
      }
    });
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the second route that’s called when the user submits his/her password to be updated.&lt;/p&gt;
&lt;p&gt;Once again, I find the user in the database and double check that the &lt;code&gt;resetPasswordToken&lt;/code&gt; also exists and is valid (the &lt;code&gt;username&lt;/code&gt; was passed back to the client from the reset route above and held in the app’s state until the update function was called), I hash the new password using my &lt;code&gt;bcrypt&lt;/code&gt; module (just like my Passport.js middleware does when a new user is being written into the database initially),update that user’s &lt;code&gt;password&lt;/code&gt; in the database with the new hash and set both the &lt;code&gt;resetPasswordToken&lt;/code&gt; and &lt;code&gt;resetPasswordExpires&lt;/code&gt; columns back to null, so the same link can’t be used more than once.&lt;/p&gt;
&lt;p&gt;As soon as that’s complete, the server sends back a 200 response with the success message, &lt;code&gt;Password updated&lt;/code&gt; for the client.&lt;/p&gt;
&lt;p&gt;And you’ve successfully reset a user’s password via email. Not too tough.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;At first glance, resetting a user’s password via an email link seems a bit daunting. But Nodemailer helps make a major factor (the emailing bit) simple. And once that’s done it’s just a few routes on the server side and inputs on the client side to get that password updated for the user.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about using Puppeteer and headless Chrome for end-to-end testing or something else related to web development, so subscribe to my free newsletter so you don’t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you an idea of how to use Nodemailer to send password reset emails for a MERN application.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodemailer.com/about/&quot;&gt;Nodemailer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nodemailer, &lt;a href=&quot;https://github.com/nodemailer/nodemailer&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nodemailer, &lt;a href=&quot;https://www.npmjs.com/package/nodemailer&quot;&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;MERN app with Nodemailer repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>nodejs</category><category>react</category><category>javascript</category></item><item><title>The Absolute Easiest Way to Debug Node.js - with VS Code</title><link>https://www.paigeniedringhaus.com/blog/the-absolute-easiest-way-to-debug-nodejs-with-vs-code/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/the-absolute-easiest-way-to-debug-nodejs-with-vs-code/</guid><description>Let’s face it…debugging Node.js is (and always has been) kind of a pain.</description><pubDate>Sun, 11 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/easiest-way-to-debug-nodejs/most-interesting-man.jpeg&quot; alt=&quot;The most interesting man in the world meme&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Enter the Pain of Debugging in Node.js&lt;/h2&gt;
&lt;p&gt;If you’ve ever had the pleasure of writing code for a Node.js project, you know what I’m talking about when I say debugging it to figure out what’s going wrong isn’t the easiest thing.&lt;/p&gt;
&lt;p&gt;Unlike JavaScript in the browser, or Java with a powerful IDE like IntelliJ, you can’t just set breakpoints everywhere, refresh the page or restart the compiler and slowly walk through the code examining objects, evaluating functions and finding the mutation or missing variable, etc. You just can’t, and it stinks.&lt;/p&gt;
&lt;p&gt;But Node &lt;em&gt;is&lt;/em&gt; possible to debug, it just takes a little more elbow grease.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let’s go over the debugging options and then I’ll show you the easiest way I’ve come across to debug Node.js in my own development.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Options to debug in Node.js&lt;/h2&gt;
&lt;p&gt;There’s a number of ways to debug your misbehaving Node.js program, I’ve listed them out below with links to learn more if you so desire.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;console.log()&lt;/code&gt;&lt;/strong&gt; — the tried and true standby, this one really needs no further explanation if you’ve ever written a line of JavaScript. It’s built in to Node.js and prints in the terminal just like it’s built into JavaScript and prints in the browser’s console.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Java, it’s &lt;code&gt;System.out.println()&lt;/code&gt;, in Python it’s &lt;code&gt;print()&lt;/code&gt; - you get the idea. This is the easiest one to implement, and it’s the fastest way to litter your clean code with extra lines of info — but it can also (sometimes) help you find and fix the error.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node.js documentation &lt;code&gt;—-inspect&lt;/code&gt;&lt;/strong&gt; — The Node.js docs themselves understand debugging isn’t the easiest, so they’ve made a &lt;a href=&quot;https://nodejs.org/en/docs/guides/debugging-getting-started/&quot;&gt;handy reference&lt;/a&gt; to help get people started.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s useful, but honestly, unless you’ve been programming for a while, it’s not exactly the easiest thing to decipher. They pretty quickly go down the rabbit hole of UUIDs, WebSockets, and security implications and I start to feel in over my head. And thinking to myself: there’s got to be a less complex way to do this.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chrome DevTools&lt;/strong&gt; — &lt;a href=&quot;https://medium.com/@paul_irish&quot;&gt;Paul Irish&lt;/a&gt; wrote a great &lt;a href=&quot;https://medium.com/@paul_irish/debugging-node-js-nightlies-with-chrome-devtools-7c4a1b95ae27&quot;&gt;blog post&lt;/a&gt; back in 2016 (updated in 2018) about debugging Node.js using Chrome DevTools, and from the looks of things it sounded pretty simple, and like a great step forward for debugging.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fast forward half an hour, and I still hadn’t managed to connect a DevTools window to my simple Node program and I wasn’t so sure anymore. Maybe I just can’t follow directions, but Chrome DevTools seems to make it more complicated to debug than it should be.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JetBrains&lt;/strong&gt; — one of my very favorite software development companies and makers of IntelliJ and WebStorm to name just a few IDEs, JetBrains is great. They’ve got a fantastic ecosystem of plugins for their tools and until recently, they were my go-to IDE without question.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With such a dedicated user base came lots of helpful articles like &lt;a href=&quot;https://www.jetbrains.com/help/webstorm/running-and-debugging-node-js.html&quot;&gt;this&lt;/a&gt;, which walk through debugging Node, but similar to the Node documentation and the Chrome DevTools options, it’s not easy. You have to create a debugging configuration, attach running processes and do a good bit of configuration in the preferences before WebStorm is ready to go.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visual Studio Code&lt;/strong&gt; — this is my new gold standard for Node debugging. I never thought I’d say it, but I am all in on &lt;a href=&quot;https://code.visualstudio.com/download&quot;&gt;VS Code&lt;/a&gt;, and every new feature release the team does, makes me love this IDE more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;VS Code does what every other option for &lt;a href=&quot;https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_attaching-to-nodejs&quot;&gt;debugging Node.js&lt;/a&gt; fails to do, it makes it stupid simple. If you want to get fancier with your debugging you absolutely can, but they break it down to make it simple enough anyone can get up and running quickly, regardless of how familiar you are with IDEs, Node, programming, etc. And it’s awesome.&lt;/p&gt;
&lt;h3&gt;Setting up VS Code to debug in Node.js&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/easiest-way-to-debug-nodejs/caveman-could-do-it.jpeg&quot; alt=&quot;VS Code debugging - so easy a caveman can do it&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Sorry, I couldn’t resist this meme — it’s just so appropriate.&lt;/p&gt;
&lt;p&gt;Ok, so let’s walk through setting up VS Code to debug Node. I’ll assume you’ve already downloaded VS Code from the &lt;a href=&quot;https://code.visualstudio.com/download&quot;&gt;link&lt;/a&gt; I posted above, so we’re ready to start setting it up.&lt;/p&gt;
&lt;p&gt;In VS Code, open up &lt;strong&gt;Preferences &amp;gt; Settings&lt;/strong&gt; and in the search box type in “node debug”. Under the &lt;strong&gt;Extensions&lt;/strong&gt; tab there should be one extension titled “Node debug”. From here, click the first box: &lt;strong&gt;Debug &amp;gt; Node: Auto Attach&lt;/strong&gt; and set the drop down to “on”. You’re almost ready to go now. Yes, it really is that easy.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/easiest-way-to-debug-nodejs/debug-settings.png&quot; alt=&quot;Node debug in VS Code settings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s what you should see under the Settings tab. Set the first drop down &quot;Debug &amp;gt; Node: Auto Attach&quot; to &quot;on&quot;.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Now, go to your Node.js project file, and set some breakpoints by clicking on the left hand side of the file wherever you’d like to see your code stop, and in the terminal type &lt;code&gt;node --inspect &amp;lt;FILE NAME&amp;gt;&lt;/code&gt;. Now watch the magic happen…&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/easiest-way-to-debug-nodejs/debug-breakpoints.png&quot; alt=&quot;Debug breakpoints example in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;See the red breakpoints on the lefthand side of the file? See the &lt;code&gt;node — inspect readFileStream.js&lt;/code&gt; in the terminal? That’s it.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;VS Code debugging in action&lt;/h3&gt;
&lt;p&gt;If you need a Node.js project to test this out with, you can download my repo &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;. It was made to test different forms of streaming large amounts of data with Node, but it works really well for this demo. If you’d like to see more about streaming data with Node and performance optimization, you can see my posts &lt;strong&gt;&lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;here&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;./streams-for-the-win-a-performance-comparison-of-node-js-methods-for-reading-large-datasets-pt-2&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Once you hit Enter, your VS Code terminal should turn orange at the bottom to indicate you’re in debug mode and your console will print some message along the lines of &lt;code&gt;&quot;Debugger Attached&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/easiest-way-to-debug-nodejs/debugger-attached.png&quot; alt=&quot;Debugger stopping at breakpoints in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The orange toolbar and &quot;Debugger attached&quot; message will tell you VS Code is running correctly in debug mode.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Once you see this happening, congrats, you’re running in debug mode in Node.js!&lt;/p&gt;
&lt;p&gt;Now, you can see your breakpoints in the bottom left corner of the screen (and can toggle them on and off with the checkboxes), and you can step through the code just like you would in a browser with the little play, step over, step in, restart, etc. buttons at the top center of the IDE. VS Code even highlights the breakpoint and line you’ve stopped on with yellow, making it easier to follow along.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/easiest-way-to-debug-nodejs/debugger-step-through.png&quot; alt=&quot;Step through breakpoints in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Hit the play button at the top to step from one break point to the next one in your code.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As you step from breakpoint to breakpoint, you can see the program printing out the &lt;code&gt;console.log&lt;/code&gt;s in the debug console at the bottom of the VS Code IDE and the yellow highlighting will travel with you, as well.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/easiest-way-to-debug-nodejs/debugger-step-through-2.png&quot; alt=&quot;Explore local scope info as debugger breakpoints are stopped at in VS Code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;As you can see, when we stop on breakpoints, we can see all the local scope info we could explore in the console in the upper left corner of VS Code.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As you can see, as I progress through the program, more prints out to the debug console the further through the breakpoints I go, and along the way, I can explore the objects and functions in the local scope using the tools in the upper left hand corner of VS Code, just like I can explore scope and objects in the browser. Nice!&lt;/p&gt;
&lt;p&gt;That was pretty painless, huh?&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Node.js debugging doesn’t have to be the headache it was in the past, and it doesn’t need to involve 500 console.log()s in the codebase to figure out where the bug is.&lt;/p&gt;
&lt;p&gt;Visual Studio Code’s Debug &amp;gt; Node: Auto Attach setting makes that a thing of the past, and I, for one, am so thankful.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks, I’ll be writing about end-to-end testing with Puppeteer and headless Chrome or using Nodemailer to reset passwords in a MERN application, so please follow me so you don’t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you an idea of how to more easily and effectively debug your Node.js programs with a little assistance from VS Code.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge&quot;&gt;Github, Node Read File Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Node.js documentation, &lt;a href=&quot;https://nodejs.org/en/docs/guides/debugging-getting-started/&quot;&gt;inspector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Paul Irish’s &lt;a href=&quot;https://medium.com/@paul_irish/debugging-node-js-nightlies-with-chrome-devtools-7c4a1b95ae27&quot;&gt;blog on using Chrome DevTools to debug Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JetBrains documentation, &lt;a href=&quot;https://www.jetbrains.com/help/webstorm/running-and-debugging-node-js.html&quot;&gt;Running and Debugging Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/download&quot;&gt;Visual Studio Code download&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;VS Code &lt;a href=&quot;https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_attaching-to-nodejs&quot;&gt;debugging Node.js docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>testing</category><category>nodejs</category><category>vscode</category></item><item><title>Streams For the Win: A Performance Comparison of Node.js Methods for Reading Large Datasets (Pt 2)</title><link>https://www.paigeniedringhaus.com/blog/streams-for-the-win-a-performance-comparison-of-nodejs-methods-for-reading-large-datasets-pt-2/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/streams-for-the-win-a-performance-comparison-of-nodejs-methods-for-reading-large-datasets-pt-2/</guid><description>How readFile(), createReadStream() and event-stream stack up.</description><pubDate>Wed, 24 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/streams-ftw-node-performance/node-2.jpeg&quot; alt=&quot;Node.js logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If you’ve been keeping up with my writing, a few weeks ago, I published a &lt;strong&gt;&lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;blog&lt;/a&gt;&lt;/strong&gt; talking about a variety of ways to use Node.js to read really large datasets.&lt;/p&gt;
&lt;p&gt;To my surprise, it did exceptionally well with readers — this seemed (to me) like a topic many others have already covered in posts, blogs and forums, but for whatever reason, it got the attention of a lot of people. So, thank you to all of you who took the time to read it! I really appreciate it.&lt;/p&gt;
&lt;p&gt;One particularly astute reader: &lt;a href=&quot;https://medium.com/u/8405c208bb0a&quot;&gt;Martin Kock&lt;/a&gt;, went so far as to ask how long it took to parse the files. It seemed as if he’d read my mind, because part two of my series on using Node.js to read really, really large files and datasets involves just that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this post, I’ll evaluate the three different methods in Node.js I used to read the files, to determine which is most performant.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The challenge from part 1&lt;/h2&gt;
&lt;p&gt;I won’t go into the specifics of the challenge and solution, because you can read &lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;my first post&lt;/a&gt; for all the details, but I will give you the high level overview.&lt;/p&gt;
&lt;p&gt;A person from a Slack channel I’m a member of, posted a coding challenge he’d received, which involved reading a very large dataset (over 2.5GB in total), parsing through the data and pulling out various pieces of information.&lt;/p&gt;
&lt;p&gt;It challenged programmers to print out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Total lines in the file.&lt;/li&gt;
&lt;li&gt;Names in the 432nd and 43243rd indexes.&lt;/li&gt;
&lt;li&gt;Counts for total numbers donations per month.&lt;/li&gt;
&lt;li&gt;And the most common first name in the files, and how a count of how often that name occurred.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&apos;s a link to the data if you&apos;d like to view it: ​https://www.fec.gov/files/bulk-downloads/2018/indiv18.zip&lt;/p&gt;
&lt;h3&gt;The three different solutions for smaller datasets&lt;/h3&gt;
&lt;p&gt;As I worked towards my ultimate end goal of processing a large dataset, I came up with three solutions in Node.js.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #1: &lt;code&gt;fs.readFile()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first involved Node.js’s native method of &lt;strong&gt;&lt;a href=&quot;https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback&quot;&gt;&lt;code&gt;fs.readFile()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, and consisted of reading in the whole file, holding it in memory, and performing the operations on the entire file, then returning the results. At least for smaller files it worked, but when I got to the largest file size, my server crashed with a JavaScript &lt;code&gt;heap out of memory error&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #2: &lt;code&gt;fs.createReadStream()&lt;/code&gt; &amp;amp; &lt;code&gt;rl.readLine()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My second solution also involved another couple of methods native to Node.js: &lt;strong&gt;&lt;a href=&quot;https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options&quot;&gt;&lt;code&gt;fs.createReadStream()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://nodejs.org/api/readline.html#readline_event_line&quot;&gt;&lt;code&gt;rl.readLine()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;. In this iteration, the file was streamed through Node.js in an &lt;code&gt;input&lt;/code&gt; stream, and I was able to perform individual operations on each line, then cobble all those results together in the output stream.&lt;/p&gt;
&lt;p&gt;Again, this worked pretty well on smaller files, but once I got to the biggest file, the same error happened. Although Node.js was streaming the inputs and outputs, it still attempted to hold the whole file in memory while performing the operations (and couldn’t handle the whole file).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #3: &lt;code&gt;event-stream&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the end, I came up with only one solution in Node.js that was able to handle the full 2.55GB file I wanted to parse through at once.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fun fact:&lt;/strong&gt; Node.js can only hold up to 1.67GB in memory at any one time, after that, it throws a JavaScript &lt;code&gt;heap out of memory error&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My solution involved a popular NPM package called &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/event-stream&quot;&gt;event-stream&lt;/a&gt;&lt;/strong&gt;, which actually let me perform operations on the &lt;em&gt;throughput stream&lt;/em&gt; of data, instead of just the input and output streams, as Node.js’s native capabilities allow.&lt;/p&gt;
&lt;p&gt;You can see all three of my solutions &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge&quot;&gt;here&lt;/a&gt;&lt;/strong&gt; in GitHub.&lt;/p&gt;
&lt;p&gt;And I solved the problem, which was my initial goal, but it got me thinking: was my solution really the most performant of the three options?&lt;/p&gt;
&lt;h2&gt;Comparing solutions to find the optimal one&lt;/h2&gt;
&lt;p&gt;Now I had a new goal: determine which of my solutions was best.&lt;/p&gt;
&lt;p&gt;Since I couldn’t use the full 2.55GB file with the Node.js native solutions, I chose to use one of the smaller files that was about 400MB worth of data, which I’d used for testing while I was developing my solutions.&lt;/p&gt;
&lt;p&gt;For performance testing Node.js, I came across two ways to keep track of the file and individual function processing times, and I decided to incorporate both to see how great the differences were between the two methods (and make sure I wasn’t completely off the rails with my timing).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;console.time()&lt;/code&gt; &amp;amp; &lt;code&gt;console.timeEnd()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Node.js has some handy, built-in methods available to it for timing and performance testing, called &lt;strong&gt;&lt;a href=&quot;https://nodejs.org/api/console.html#console_console_time_label&quot;&gt;&lt;code&gt;console.time()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://nodejs.org/api/console.html#console_console_timeend_label&quot;&gt;&lt;code&gt;console.timeEnd()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, respectively. To use these methods, I only had to pass in the same label parameter for both &lt;code&gt;time()&lt;/code&gt; and &lt;code&gt;timeEnd()&lt;/code&gt;, like the code below, and Node’s smart enough to output the time between them after the function’s done.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// timer start
console.time(&apos;label1&apos;);

// run function doing something in the code
doSomething();

// timer end, where the difference between the timer start and timer end is printed out
console.timeEnd(&apos;label1&apos;);

// output in console looks like: label1 0.002ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s one method I used to figure out how long it took to process the dataset.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;performance-now&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The other, tried and well-liked performance testing module I came across for Node.js, is hosted on NPM as &lt;a href=&quot;https://www.npmjs.com/package/performance-now&quot;&gt;performance-now&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;7+ million downloads per week from NPM, can’t be too wrong, right??&lt;/p&gt;
&lt;p&gt;Implementing the &lt;code&gt;performance-now&lt;/code&gt; module into my files was also almost as easy as the native Node.js methods, too. Import the module, set a variable for the start and end of the instantiation of the method, and compute the time difference between the two.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// import the performance-now module at the top of the file
const now = require(&apos;performance-now&apos;);

// set the start of the timer as a variable
const start = now();

// run function doing something in the code
doSomething();

// set the end of the timer as a variable
const end = now();

// Compute the duration between the start and end
console.log(&apos;Performance for timing for label:&apos; + (end — start).toFixed(3) + &apos;ms&apos;;

// console output looks like: Performance for timing label: 0.002ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I figured that by using both Node’s &lt;code&gt;console.time()&lt;/code&gt; and &lt;code&gt;performance-now&lt;/code&gt; at the same time, I could split the difference and get a pretty accurate read on how long my file parsing functions were really taking.&lt;/p&gt;
&lt;p&gt;Below are code snippets implementing &lt;code&gt;console.time()&lt;/code&gt; and &lt;code&gt;performance-now&lt;/code&gt; in each of my scripts. These are only snippets of one function each — for the full code, you can see my repo &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Fs.readFile() code implementation sample&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;console.time(&apos;line count&apos;);
let t0 = now();

if(contents === undefined){
  totalLines = contents.split(&apos;\n&apos;).length - 1;
}
console.log(totalLines);

let t1 = now();
console.timeEnd(&apos;line count&apos;);

console.log(`Performance now line count timing: ` + (t1 - t0).toFixed(3));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since this script is using the &lt;code&gt;fs.readFile()&lt;/code&gt; implementation, where the entire file is read into memory before any functions are executed on it, this is the most synchronous-looking code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s not actually synchronous, that’s an entirely separate Node method called &lt;code&gt;fs.readFileSync()&lt;/code&gt; - this method just resembles it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But it’s easy to see the total line count of the file and the two timing methods bookending it to determine how long it takes to execute the line count.&lt;/p&gt;
&lt;h3&gt;Fs.createReadStream() code implementation sample&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Input Stream (line-by-line):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.time(&apos;line count&apos;);

let t0 = now();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output Stream (once full file’s been read during input):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let t1 = now();

console.log(lineCount);
console.timeEnd(&apos;line count&apos;);
console.log(`Performance now line count timing: ` + (t1 - t0).toFixed(3));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the second solution using &lt;code&gt;fs.createReadStream()&lt;/code&gt; involved creating an input and output stream for the file, I broke the code snippets into two separate screenshots, as the first is from the input stream (which is running through the code line by line) and the second is the output stream (compiling all the resulting data).&lt;/p&gt;
&lt;h3&gt;Event Stream code implementation sample&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Throughput Stream (also line-by-line):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.time(&apos;line count&apos;);

let t0 = now();

totalLines++;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;On Stream End:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let t1 = now();

console.log(totalLines);
console.timeEnd(&apos;line count&apos;);
console.log(`Performance now line count timing: ` + (t1 - t0).toFixed(3));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;event-stream&lt;/code&gt; solution looks pretty similar to the &lt;code&gt;fs.createReadStream()&lt;/code&gt;, except instead of an &lt;em&gt;input stream&lt;/em&gt;, the data is processed in a &lt;em&gt;throughput stream&lt;/em&gt;. And then once the whole file’s been read and all the functions have been done on the file, the stream’s ended and the required information is printed out.&lt;/p&gt;
&lt;h3&gt;Results&lt;/h3&gt;
&lt;p&gt;Now on to the moment we’ve all been waiting for: the results!&lt;/p&gt;
&lt;p&gt;I ran all three of my solutions against the same 400MB dataset, which contained almost 2 million records to parse through.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/streams-ftw-node-performance/stream-ftw.png&quot; alt=&quot;Solution printouts&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Streams for the win!&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As you can see from the table, &lt;code&gt;fs.createReadStream()&lt;/code&gt; and &lt;code&gt;event-stream&lt;/code&gt; both fared well, but overall, &lt;code&gt;event-stream&lt;/code&gt; has to be the grand winner in my mind, if only for the fact that it can process much larger file sizes than either &lt;code&gt;fs.readFile()&lt;/code&gt; or &lt;code&gt;fs.createReadStream()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The percentage improvements are included at the end of the table above as well, for reference.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fs.readFile()&lt;/code&gt; just got blown out of the water by the competition. By streaming the data, processing times for the file improved by at least 78% — sometimes close to almost a 100%, which is pretty darn impressive.&lt;/p&gt;
&lt;p&gt;Below are the raw screenshots from my terminal for each of my solutions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #1: &lt;a href=&quot;https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback&quot;&gt;&lt;code&gt;fs.readFile()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/streams-ftw-node-performance/solution-1.png&quot; alt=&quot;Solution 1 print out&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The solution using only: fs.readFile()&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #2: &lt;a href=&quot;https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options&quot;&gt;&lt;code&gt;fs.createReadStream()&lt;/code&gt;&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://nodejs.org/api/readline.html#readline_event_line&quot;&gt;&lt;code&gt;rl.readLine()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/streams-ftw-node-performance/solution-2.png&quot; alt=&quot;Solution 2 print out&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The solution using fs.createReadStream() and rl.readLine()&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #3: &lt;a href=&quot;https://www.npmjs.com/package/event-stream&quot;&gt;&lt;code&gt;event-stream&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/streams-ftw-node-performance/solution-3.png&quot; alt=&quot;Solution 3 print out&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The solution using event-stream&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here’s a screenshot of my &lt;code&gt;event-stream&lt;/code&gt; solution churning through the 2.55GB monster file, as well. And here’s the time difference between the 400MB file and the 2.55GB file too.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/streams-ftw-node-performance/bonus-results.png&quot; alt=&quot;Bonus solution print out&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Look at those blazing fast speeds, even as the file size climbs by almost 6X.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution #3: &lt;code&gt;event-stream&lt;/code&gt; (on the 2.55GB file)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/streams-ftw-node-performance/solution-3.2.png&quot; alt=&quot;Bonus solution print out&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Look at those blazing fast speeds, even as the file size climbs by almost 6X.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the end, streams both native to Node.js and not, are way, WAY more efficient at processing large data sets.&lt;/p&gt;
&lt;p&gt;Thanks for coming back for part 2 of my series using Node.js to read really, really large files. If you’d like to read the first blog again, you can access it &lt;strong&gt;&lt;a href=&quot;./using-node-to-read-really-really-large-datasets-pt-1&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I’ll be back in a couple weeks with a new JavaScript topic — possibly debugging in Node or end-to-end testing with Puppeteer and headless Chrome, so subscribe to my free newsletter so you don&apos;t miss out.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you an idea of how to handle large amounts of data with Node.js efficiently and performance test your solutions.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge&quot;&gt;Github, Read File Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Node.js Documentation, &lt;a href=&quot;https://nodejs.org/api/fs.html&quot;&gt;File System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Node.js Documentation, &lt;a href=&quot;https://nodejs.org/api/console.html#console_console_time_label&quot;&gt;Console.Time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NPM, &lt;a href=&quot;https://www.npmjs.com/package/performance-now&quot;&gt;Performance Now&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NPM, &lt;a href=&quot;https://www.npmjs.com/package/event-stream&quot;&gt;EventSream&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Link to the &lt;a href=&quot;https://www.fec.gov/files/bulk-downloads/2018/indiv18.zip&quot;&gt;FEC data&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>big data</category><category>performance</category><category>testing</category></item><item><title>Using Node to Read Really, Really Large Datasets (Pt 1)</title><link>https://www.paigeniedringhaus.com/blog/using-node-to-read-really-really-large-datasets-pt-1/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/using-node-to-read-really-really-large-datasets-pt-1/</guid><description>Node.js can handle big data pretty, darn well.</description><pubDate>Thu, 11 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-node-on-large-datasets/node-logo.png&quot; alt=&quot;Node.js logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This blog post has an interesting inspiration point. Last week, someone in one of my Slack channels, posted a coding challenge he’d received for a developer position with an insurance technology company.&lt;/p&gt;
&lt;p&gt;It piqued my interest as the challenge involved reading through very large files of data from the Federal Elections Commission and displaying back specific data from those files. Since I’ve not worked much with raw data, and I’m always up for a new challenge, I decided to tackle this with Node.js and see if I could complete the challenge myself, for the fun of it.&lt;/p&gt;
&lt;p&gt;Here’s the 4 questions asked, and a link to the data set that the program was to parse through.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a program that will print out the total number of lines in the file.&lt;/li&gt;
&lt;li&gt;Notice that the 8th column contains a person’s name. Write a program that loads in this data and creates an array with all name strings. Print out the 432nd and 43243rd names.&lt;/li&gt;
&lt;li&gt;Notice that the 5th column contains a form of date. Count how many donations occurred in each month and print out the results.&lt;/li&gt;
&lt;li&gt;Notice that the 8th column contains a person’s name. Create an array with each first name. Identify the most common first name in the data and how many times it occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Link to the data: ​https://www.fec.gov/files/bulk-downloads/2018/indiv18.zip&lt;/p&gt;
&lt;p&gt;When you unzip the folder, you should see one main &lt;code&gt;.txt&lt;/code&gt; file that’s 2.55GB and a folder containing smaller pieces of that main file (which is what I used while testing my solutions before moving to the main file).&lt;/p&gt;
&lt;p&gt;Not too terrible, right? Seems doable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today let’s talk about how I approached parsing this really, really large file using Node.js, and some various solutions I came up with along the way.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The Two Original Node.js Solutions I Came Up With&lt;/h2&gt;
&lt;p&gt;Processing large files is nothing new to JavaScript, in fact, in the core functionality of Node.js, there are a number of standard solutions for reading and writing to and from files.&lt;/p&gt;
&lt;p&gt;The most straightforward is &lt;strong&gt;&lt;a href=&quot;https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback&quot;&gt;&lt;code&gt;fs.readFile()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; wherein, the whole file is read into memory and then acted upon once Node has read it, and the second option is &lt;strong&gt;&lt;a href=&quot;https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options&quot;&gt;&lt;code&gt;fs.createReadStream()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, which streams the data in (and out) similar to other languages like Python and Java.&lt;/p&gt;
&lt;h3&gt;The Solution I Chose to Run With &amp;amp; Why&lt;/h3&gt;
&lt;p&gt;Since my solution needed to involve such things as counting the total number of lines and parsing through each line to get donation names and dates, I chose to use the second method: fs.createReadStream(). Then, I could use the rl.on(‘line’,...) function to get the necessary data from each line of code as I streamed through the document.&lt;/p&gt;
&lt;p&gt;It seemed easier to me then having to split apart the whole file once it was read in and run through the lines that way.&lt;/p&gt;
&lt;h3&gt;Node.js &lt;code&gt;createReadStream()&lt;/code&gt; &amp;amp; &lt;code&gt;readFile()&lt;/code&gt; Code Implementation&lt;/h3&gt;
&lt;p&gt;Below is the code I came up with using Node.js’s fs.createReadStream() function. I’ll break it down below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge/blob/master/readFileStream.js&quot;&gt;&lt;code&gt;readFileStream.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var fs = require(&apos;fs&apos;);
var readline = require(&apos;readline&apos;);
var stream = require(&apos;stream&apos;);

var instream = fs.createReadStream(&apos;itcont.txt&apos;);
var outstream = new stream();
var rl = readline.createInterface(instream, outstream);

//get line count for file
var lineCount = 0;

// create array list of names
var names = [];

// donations occurring in each month
var dateDonationCount = [];
var dateDonations = {};

// list of first names, and most common first name
var firstNames = [];
var dupeNames = {};

rl.on(&apos;line&apos;, function(line) {
  // increment line count
  lineCount++;

  // get all names
  var name = line.split(&apos;|&apos;)[7];
  names.push(name);

  // get all first halves of names
  var firstHalfOfName = name.split(&apos;, &apos;)[1];
  if (firstHalfOfName !== undefined) {
    firstHalfOfName.trim();
    // filter out middle initials
    if (firstHalfOfName.includes(&apos; &apos;) &amp;amp;&amp;amp; firstHalfOfName !== &apos; &apos;) {
      firstName = firstHalfOfName.split(&apos; &apos;)[0];
      firstName.trim();
      firstNames.push(firstName);
      dupeNames[firstName] = (dupeNames[firstName] || 0) + 1;
    } else {
      firstNames.push(firstHalfOfName);
      dupeNames[firstHalfOfName] = (dupeNames[firstHalfOfName] || 0) + 1;
    }
  }

  // year and month
  var timestamp = line.split(&apos;|&apos;)[4].slice(0, 6);
  var formattedTimestamp = timestamp.slice(0, 4) + &apos;-&apos; + timestamp.slice(4, 6);
  dateDonationCount.push(formattedTimestamp);
  dateDonations[formattedTimestamp] =
    (dateDonations[formattedTimestamp] || 0) + 1;
});

rl.on(&apos;close&apos;, function() {
  // total line count
  console.log(lineCount);

  // names at various points in time
  console.log(names[432]);
  console.log(names[43243]);

  // most common first name
  var sortedDupeNames = Object.entries(dupeNames);

  sortedDupeNames.sort((a, b) =&amp;gt; {
    return b[1] - a[1];
  });
  console.log(sortedDupeNames[0]);

  const name = sortedDupeNames[0][0];
  const nameOccurrences = sortedDupeNames[0][1];
  console.log(
    `The most common name is &apos;${name}&apos; with ${nameOccurrences} occurrences.`,
  );

  // number of donations per month
  const logDateElements = (key, value, map) =&amp;gt; {
    console.log(
      `Donations per month and year: ${value} and donation count ${key}`,
    );
  };
  new Map(Object.entries(dateDonations)).forEach(logDateElements);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The very first things I had to do to set this up, were import the required functions from Node.js: &lt;code&gt;fs&lt;/code&gt; (file system), &lt;code&gt;readline&lt;/code&gt;, and &lt;code&gt;stream&lt;/code&gt;. These imports allowed me to then create an &lt;code&gt;instream&lt;/code&gt; and &lt;code&gt;outstream&lt;/code&gt; and then the &lt;code&gt;readLine.createInterface()&lt;/code&gt;, which would let me read through the stream line by line and print out data from it.&lt;/p&gt;
&lt;p&gt;I also added some variables (and comments) to hold various bits of data: a &lt;code&gt;lineCount&lt;/code&gt;, &lt;code&gt;names&lt;/code&gt; array, &lt;code&gt;donation&lt;/code&gt; array and object, and &lt;code&gt;firstNames&lt;/code&gt; array and &lt;code&gt;dupeNames&lt;/code&gt; object. You’ll see where these come into play a little later.&lt;/p&gt;
&lt;p&gt;Inside of the &lt;code&gt;rl.on(&apos;line&apos;,...)&lt;/code&gt; function, I was able to do all of my line-by-line data parsing. In here, I incremented the &lt;code&gt;lineCount&lt;/code&gt; variable for each line it streamed through. I used the JavaScript &lt;code&gt;split()&lt;/code&gt; method to parse out each name and added it to my &lt;code&gt;names&lt;/code&gt; array. I further reduced each name down to just first names, while accounting for middle initials, multiple names, etc. along with the first name with the help of the JavaScript &lt;code&gt;trim()&lt;/code&gt;, &lt;code&gt;includes()&lt;/code&gt;, and &lt;code&gt;split()&lt;/code&gt; methods. And I sliced the year and date out of date column, reformatted those to a more readable &lt;code&gt;YYYY-MM&lt;/code&gt; format, and added them to the &lt;code&gt;dateDonationCount&lt;/code&gt; array.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;rl.on(&apos;close&apos;,...)&lt;/code&gt; function, I did all the transformations on the data I’d gathered into arrays and &lt;code&gt;console.log&lt;/code&gt;ged out all my data for the user to see.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;lineCount&lt;/code&gt; and &lt;code&gt;names&lt;/code&gt; at the 432nd and 43,243rd index, required no further manipulation. Finding the most common name and the number of donations for each month was a little trickier.&lt;/p&gt;
&lt;p&gt;For the most common first name, I first had to create an object of key value pairs for each name (the key) and the number of times it appeared (the value), then I transformed that into an array of arrays using the ES6 function &lt;code&gt;Object.entries()&lt;/code&gt;. From there, it was a simple task to sort the names by their value and print the largest value.&lt;/p&gt;
&lt;p&gt;Donations also required me to make a similar object of key value pairs, create a &lt;code&gt;logDateElements()&lt;/code&gt; function where I could nicely using ES6’s string interpolation to display the keys and values for each donation month. And then create a &lt;code&gt;new Map()&lt;/code&gt; transforming the &lt;code&gt;dateDonations&lt;/code&gt; object into an array of arrays, and looping through each array calling the &lt;code&gt;logDateElements()&lt;/code&gt; function on it. Whew! Not quite as simple as I first thought.&lt;/p&gt;
&lt;p&gt;But it worked. At least with the smaller 400MB file I was using for testing…&lt;/p&gt;
&lt;p&gt;After I’d done that with &lt;code&gt;fs.createReadStream()&lt;/code&gt;, I went back and also implemented my solutions with &lt;code&gt;fs.readFile()&lt;/code&gt;, to see the differences. Here’s the code for that, but I won’t go through all the details here — it’s pretty similar to the first snippet, just more synchronous looking (unless you use the &lt;code&gt;fs.readFileSync()&lt;/code&gt; function, though, JavaScript will run this code just as asynchronously as all its other code, not to worry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge/blob/master/readFile.js&quot;&gt;&lt;code&gt;readFile.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var fs = require(&apos;fs&apos;);

var totalLines = 0;
var lines = [];
var names = [];
var firstNames = [];
var dupeNames = {};
var dateDonationCount = [];
var dateDonations = {};

fs.readFile(&apos;itcont.txt&apos;, &apos;utf8&apos;, (err, contents) =&amp;gt; {
  if (contents !== undefined) {
    totalLines = contents.split(&apos;\n&apos;).length - 1;
  }
  console.log(totalLines);

  if (contents !== undefined) {
    lines = contents.split(&apos;\n&apos;);
    lines.forEach(line =&amp;gt; {
      var name = line.split(&apos;|&apos;)[7];
      names.push(name);
    });
  }

  console.log(names[432]);
  console.log(names[43243]);

  names.forEach(name =&amp;gt; {
    var firstHalfOfName = name.split(&apos;, &apos;)[1];
    if (firstHalfOfName !== undefined) {
      firstHalfOfName.trim();

      if (firstHalfOfName !== &apos; &apos; &amp;amp;&amp;amp; firstHalfOfName.includes(&apos; &apos;)) {
        firstName = firstHalfOfName.split(&apos; &apos;)[0];
        firstName.trim();
        firstNames.push(firstName);
      } else {
        firstNames.push(firstHalfOfName);
      }
    }
  });

  firstNames.forEach(x =&amp;gt; {
    dupeNames[x] = (dupeNames[x] || 0) + 1;
  });
  var sortedDupeNames = [];
  sortedDupeNames = Object.entries(dupeNames);

  sortedDupeNames.sort((a, b) =&amp;gt; {
    return b[1] - a[1];
  });
  console.log(sortedDupeNames[0]);

  lines.forEach(line =&amp;gt; {
    var timestamp = line.split(&apos;|&apos;)[4].slice(0, 6);
    var formattedTimestamp =
      timestamp.slice(0, 4) + &apos;-&apos; + timestamp.slice(4, 6);
    dateDonationCount.push(formattedTimestamp);
  });

  dateDonationCount.forEach(x =&amp;gt; {
    dateDonations[x] = (dateDonations[x] || 0) + 1;
  });
  
  const logDateElements = (key, value, map) =&amp;gt; {
    console.log(
      `Donations per month and year: ${value} and donation count ${key}`,
    );
  };
  new Map(Object.entries(dateDonations)).forEach(logDateElements);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’d like to see my full repo with all my code, you can see it &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Initial Results: Round 1&lt;/h3&gt;
&lt;p&gt;With my working solution, I added the file path into &lt;code&gt;readFileStream.js&lt;/code&gt; file for the 2.55GB monster file, and watched my Node server crash with a JavaScript heap out of memory error.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-node-on-large-datasets/node-out-of-memory.png&quot; alt=&quot;Console output when Node program ran out of memory and crashed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Failed. Whomp, whomp...&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;As it turns out, although Node.js is streaming the file input and output, in between, it is still attempting to hold the entire file contents in memory, which it can’t do with a file that size. Node can hold up to 1.5GB in memory at one time, but no more.&lt;/p&gt;
&lt;p&gt;So neither of my current solutions was up for the full challenge.&lt;/p&gt;
&lt;p&gt;I needed a new solution. A solution for even larger datasets running through Node.&lt;/p&gt;
&lt;h2&gt;The New Data Streaming Solution&lt;/h2&gt;
&lt;p&gt;I found my solution in the form of &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/event-stream&quot;&gt;EventStream&lt;/a&gt;&lt;/strong&gt;, a popular NPM module with over 2 million weekly downloads and a promise “to make creating and working with streams easy”.&lt;/p&gt;
&lt;p&gt;With a little help from &lt;a href=&quot;https://github.com/dominictarr/event-stream&quot;&gt;EventStream’s documentation&lt;/a&gt;, I was able to figure out how to, once again, read the code line by line and do what needed to be done, hopefully, in a more CPU friendly way to Node.&lt;/p&gt;
&lt;h3&gt;EventStream Code Implementation&lt;/h3&gt;
&lt;p&gt;Here’s my code new code using the NPM module EventStream.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/file-read-challenge/blob/master/readFileEventStream.js&quot;&gt;&lt;code&gt;readFileEventStream.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var fs = require(&apos;fs&apos;);
var es = require(&apos;event-stream&apos;);

var totalLines = 0;
var names = [];
var firstNames = [];
var dupeNames = {};
var dateDonationCount = [];
var dateDonations = {};

var s = fs
  .createReadStream(&apos;itcont.txt&apos;)
  .pipe(es.split())
  .pipe(
    es
      .mapSync(function(line) {
        totalLines++;

        // get all names
        var name = line.split(&apos;|&apos;)[7];
        if (totalLines === 433 || totalLines === 43244) {
          names.push(name);
        }

        // get all first halves of names
        var firstHalfOfName = name.split(&apos;, &apos;)[1];

        if (firstHalfOfName !== undefined) {
          firstHalfOfName.trim();

          // filter out middle initials
          if (firstHalfOfName.includes(&apos; &apos;) &amp;amp;&amp;amp; firstHalfOfName !== &apos; &apos;) {
            firstName = firstHalfOfName.split(&apos; &apos;)[0];
            firstName.trim();
            firstNames.push(firstName);
            dupeNames[firstName] = (dupeNames[firstName] || 0) + 1;
          } else {
            firstNames.push(firstHalfOfName);
            dupeNames[firstHalfOfName] = (dupeNames[firstHalfOfName] || 0) + 1;
          }
        }

        // year and month
        var timestamp = line.split(&apos;|&apos;)[4].slice(0, 6);
        var formattedTimestamp =
          timestamp.slice(0, 4) + &apos;-&apos; + timestamp.slice(4, 6);
        dateDonationCount.push(formattedTimestamp);
        dateDonations[formattedTimestamp] =
          (dateDonations[formattedTimestamp] || 0) + 1;
      })
      .on(&apos;error&apos;, function(err) {
        console.log(&apos;Error while reading file.&apos;, err);
      })
      .on(&apos;end&apos;, function() {
        console.log(&apos;Read entire file.&apos;);
        console.log(totalLines);

        sortedDupeNames = Object.entries(dupeNames);

        sortedDupeNames.sort((a, b) =&amp;gt; {
          return b[1] - a[1];
        });
        console.log(sortedDupeNames[0]);

        const name = sortedDupeNames[0][0];
        const nameOccurrences = sortedDupeNames[0][1];
        console.log(
          `The most common name is &apos;${name}&apos; with ${nameOccurrences} occurrences.`,
        );

        // number of donations per month
        const logDateElements = (key, value, map) =&amp;gt; {
          console.log(
            `Donations per month and year: ${value} and donation count ${key}`,
          );
        };
        new Map(Object.entries(dateDonations)).forEach(logDateElements);
      }),
  );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The biggest change was the pipe commands at the beginning of the file — all of that syntax is the way EventStream’s documentation recommends you break up the stream into chunks delimited by the &lt;code&gt;\n&lt;/code&gt; character at the end of each line of the &lt;code&gt;.txt&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The only other thing I had to change was the &lt;code&gt;names&lt;/code&gt; answer. I had to fudge that a little bit since if I tried to add all 13MM names into an array, I again, hit the out of memory issue. I got around it, by just collecting the 432nd and 43,243rd names and adding them to their own array. Not quite what was being asked, but hey - I had to get a little creative.&lt;/p&gt;
&lt;h3&gt;Results from Node.js &amp;amp; EventStream: Round 2&lt;/h3&gt;
&lt;p&gt;Ok, with the new solution implemented, I again, fired up Node.js with my 2.55GB file and my fingers crossed this would work. Check out the results.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/using-node-on-large-datasets/node-event-stream-results.png&quot; alt=&quot;Console output when Node Event Stream program successfully chewed through 2.55GB of file data&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Woo hoo!&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the end, Node.js’s pure file and big data handling functions fell a little short of what I needed, but with just one extra NPM package, EventStream, I was able to parse through a massive dataset without crashing the Node server.&lt;/p&gt;
&lt;p&gt;Stay tuned for part two of this series where I compare my three different ways of reading data in Node.js with performance testing to see which one is truly superior to the others. The results are pretty eye opening — especially as the data gets larger…&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you an idea of how to handle large amounts of data with Node.js.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Node.js Documentation, &lt;a href=&quot;https://nodejs.org/api/fs.html&quot;&gt;File System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Node.js Documentation, &lt;a href=&quot;https://nodejs.org/api/readline.html#readline_event_line&quot;&gt;Readline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Github, &lt;a href=&quot;https://github.com/paigen11/file-read-challenge&quot;&gt;Read File Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NPM, &lt;a href=&quot;https://www.npmjs.com/package/event-stream&quot;&gt;EventSream&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>big data</category></item><item><title>How to Use Netflix&apos;s Eureka and Spring Cloud for Service Registry</title><link>https://www.paigeniedringhaus.com/blog/how-to-use-netflixs-eureka-and-spring-cloud-for-service-registry/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/how-to-use-netflixs-eureka-and-spring-cloud-for-service-registry/</guid><description>Remove the complexity from microservice architectures.</description><pubDate>Sun, 30 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eureka-registry-service/spring-eureka-logo.png&quot; alt=&quot;Spring Eureka logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;One of the main tenets of the &lt;strong&gt;&lt;a href=&quot;https://microservices.io/patterns/microservices.html&quot;&gt;microservice architecture pattern&lt;/a&gt;&lt;/strong&gt; is that a set of loosely-coupled, collaborating services works together to form a cohesive, whole application. In this way, it’s not so much about the individual services, it’s more about ensuring the interactions between the services remains reliable and failure-tolerant.&lt;/p&gt;
&lt;p&gt;What this means in practice, is removing hard-coded information and replacing it with dynamically updating environment variables, having separate databases for each service, removing as much dependency between services as possible (so if necessary, a service that needs more instances can easily scale without impacting its counterparts), and generally decreasing the complexity of managing the whole by increasing the complexity of each individual service.&lt;/p&gt;
&lt;p&gt;It sounds like a good strategy, but keeping track of all the smaller pieces of the whole makes it a burden on the client to manage all of this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which brings me to the topic of my blog today: the Netflix Eureka service registry — and how to use it with Spring Cloud to more effectively manage the complex task of keeping track of services.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As the Github repo for Netflix’s Eureka registry says itself:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers.”&lt;/p&gt;
&lt;p&gt;— &lt;a href=&quot;https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance&quot;&gt;Netflix: Eureka at a Glance, Github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds good? Good. Without further ado, let’s get to setting up this Eureka service registry and a couple of services to see it in practice.&lt;/p&gt;
&lt;h2&gt;Set Up the Eureka Server&lt;/h2&gt;
&lt;p&gt;Setting up a Spring-based Eureka server is actually pretty simple. &lt;a href=&quot;https://spring.io/&quot;&gt;Spring.io&lt;/a&gt;, itself, has a great &lt;strong&gt;&lt;a href=&quot;https://spring.io/guides/gs/service-registration-and-discovery/&quot;&gt;walkthrough here&lt;/a&gt;&lt;/strong&gt;, that helped get me up and running quickly with both a Eureka server and a sample Spring Boot project.&lt;/p&gt;
&lt;p&gt;I won’t go through it step-by-step, as you can do that with the tutorial I linked to, or you can download my &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example&quot;&gt;working code example here&lt;/a&gt;&lt;/strong&gt;. But I will highlight the important things to include for the server setup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; All the code snippets shown below have file names linked to the actual GitHub files in my example repo. Feel free to click on them to see the working code in its entirety.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/master/eureka-service/build.gradle&quot;&gt;&lt;code&gt;build.gradle&lt;/code&gt;&lt;/a&gt; File&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ext {
	springCloudVersion = &apos;Finchley.SR1&apos;
}

dependencies {
	compile(&apos;org.springframework.cloud:spring-cloud-starter-netflix-eureka-server&apos;)
	testCompile(&apos;org.springframework.boot:spring-boot-starter-test&apos;)
}

dependencyManagement {
	imports {
		mavenBom &quot;org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}&quot;
	}
}

repositories {
	maven {
		url &apos;https://repo.spring.io/libs-milestone&apos;
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside of your &lt;code&gt;build.gradle&lt;/code&gt; file, you must include the dependencies above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server&quot;&gt;&lt;code&gt;spring-cloud-starter-netflix-eureka-server&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;and the &lt;strong&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies&quot;&gt;&lt;code&gt;spring-cloud-dependencies&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that done, next up is the &lt;code&gt;application.yml&lt;/code&gt; file in the resources folder.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/464d42752919fc8ba554ee9cce8797a00c8a226e/eureka-service/build/jib-docker-context/resources/application.yml&quot;&gt;&lt;code&gt;application.yml&lt;/code&gt;&lt;/a&gt; File&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;spring:
    application:
        name: eureka-service

server:
    port: 8761

eureka:
    client:
        register-with-eureka: false
        fetch-registry: false
        serviceUrl:
            defaultZone: http://eureka-service:8761/eureka

logging:
    level:
        com:
            netflix:
                eureka: OFF
                discovery: OFF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This file doesn’t need much, either. It needs a server port specified so the service doesn’t automatically start on port 8080, which would then conflict with our other Spring Boot client services, when running locally.&lt;/p&gt;
&lt;p&gt;A couple more configurations are specified as well, for convenience. The Eureka client is instructed not to register &lt;em&gt;itself&lt;/em&gt; upon start up: &lt;code&gt;eureka.client.register-with-eureka: false&lt;/code&gt;, and it is told not to search for other registry nodes to connect to, as there are none (at least not while running locally ): &lt;code&gt;eureka.client.fetch-registry: false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A default URL is listed and the verbose logging for Eureka and any subsequent discovery of services is also turned off.&lt;/p&gt;
&lt;p&gt;Right, now there’s just one final step on the main class path.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/464d42752919fc8ba554ee9cce8797a00c8a226e/eureka-service/src/main/java/eurekaServer/EurekaServerApplication.java&quot;&gt;&lt;code&gt;EurekaServerApp.java&lt;/code&gt;&lt;/a&gt; File&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package eurekaServer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaServerApplication.class, args);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only addition the main file needs is the &lt;strong&gt;&lt;code&gt;@EnableEurekaServer&lt;/code&gt;&lt;/strong&gt; annotation, which tells the Spring Boot service to enable the server. Easy enough.&lt;/p&gt;
&lt;p&gt;Ok, we can move on to the services now — this is where things start to get more interesting.&lt;/p&gt;
&lt;h2&gt;Set Up a Spring Boot Java Service for Eureka to Register&lt;/h2&gt;
&lt;p&gt;Once again, the Spring.io &lt;strong&gt;&lt;a href=&quot;https://spring.io/guides/gs/service-registration-and-discovery/&quot;&gt;walkthrough here&lt;/a&gt;&lt;/strong&gt;, does a very good job of setting up the first Spring Boot server and client project, so I’ll just hit the highlights again of what you must include.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dependencyManagement {
	imports {
		mavenBom &apos;org.springframework.cloud:spring-cloud-dependencies:Finchley.SR1&apos;
	}
}

repositories {
	maven {
		url &apos;https://repo.spring.io/libs-milestone&apos;
	}
}

dependencies {
	compile(&apos;org.springframework.cloud:spring-cloud-starter-netflix-eureka-client&apos;)
	compile(&apos;org.springframework.boot:spring-boot-starter-web&apos;)
	testCompile(&apos;org.springframework.boot:spring-boot-starter-test&apos;)
	testCompile(&apos;org.springframework.cloud:spring-cloud-starter-eurekaServer&apos;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the client service’s &lt;code&gt;build.gradle&lt;/code&gt; file, just be sure to include the &lt;strong&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client&quot;&gt;&lt;code&gt;spring-cloud-starter-netflix-eureka-client&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, and the &lt;strong&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies&quot;&gt;&lt;code&gt;spring-cloud-dependencies&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web&quot;&gt;&lt;code&gt;spring-boot-starter-web&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; dependencies are included so a web endpoint can be created in the service that will show us what the service’s information relative to the Eureka server looks like.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;bootstrap.yml&lt;/code&gt; &amp;amp; &lt;code&gt;application.yml&lt;/code&gt; Files&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/master/eureka-client-java/bin/main/bootstrap.yml&quot;&gt;&lt;code&gt;bootstrap.yml&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spring:
    application:
        name: a-java-service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once again, some minor configurations are needed for the &lt;code&gt;boostrap.yml&lt;/code&gt; and &lt;code&gt;application.yml&lt;/code&gt; files. The &lt;code&gt;bootstrap.yml&lt;/code&gt; is pictured above, it is picked up before the &lt;code&gt;application.yml&lt;/code&gt; file by Spring, so this is where we set the service’s name.&lt;/p&gt;
&lt;p&gt;I chose the very original &lt;code&gt;spring.application.name: a-java-service&lt;/code&gt;, for this project. That’s how the Eureka server will reference it going forward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/master/eureka-client-java/bin/main/application.yml&quot;&gt;&lt;code&gt;application.yml&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server:
    port: 8091

eureka:
    client:
        serviceUrl:
            defaultZone: http://localhost:8761/eureka
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then the &lt;code&gt;application.yml&lt;/code&gt; file has configs similar to the Eureka server setup. A port number and the default URL for the Eureka server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/master/eureka-client-java/src/main/java/eurekaClient/EurekaClientApplication.java&quot;&gt;&lt;code&gt;EurekaClientApplication.java&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; File&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package eurekaClient;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaClientApplication.class, args);
	}
}

@RestController
class ServiceInstanceRestController {

	@Autowired
	private DiscoveryClient discoveryClient;

	@RequestMapping(&quot;/service-instances/{applicationName}&quot;)
	public List&amp;lt;ServiceInstance&amp;gt; serviceInstancesByApplicationName(
			@PathVariable String applicationName) {
		return this.discoveryClient.getInstances(applicationName);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, the service is annotated in the main class path file with &lt;strong&gt;&lt;code&gt;@EnableDiscoveryClient&lt;/code&gt;&lt;/strong&gt;, which tells the Spring Boot service to activate the Netflix Eureka DiscoveryClient implementation and register its own host and port with the Eureka server.&lt;/p&gt;
&lt;p&gt;The REST endpoint defined below on the REST Controller can be used to see all the service instances registered in the Eureka registry at the local URL: http://localhost:8091/service-instances/a-java-service.&lt;/p&gt;
&lt;p&gt;The JSON info for the service looks like this:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eureka-registry-service/a-java-service-json.png&quot; alt=&quot;JSON data from the Java microservice&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Set Up a Node Service for Eureka to Register&lt;/h2&gt;
&lt;p&gt;Now, that&apos;s a good start, but to be more real-world, I decided I wanted to also register a Node.js service to the Eureka server as well, and that proved a little more challenging.&lt;/p&gt;
&lt;p&gt;Luckily, there’s a handy little NPM package out there for just such needs, called &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/eureka-js-client&quot;&gt;&lt;code&gt;eureka-js-client&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, which is billed as a:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JavaScript implementation of a client for &lt;a href=&quot;https://github.com/Netflix/eureka&quot;&gt;Eureka&lt;/a&gt;, the Netflix OSS service registry.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The documentation must be read through to the end because there’s some special gotchas when using the Spring implementation with Eureka, but I managed to get it working with some trial and error.&lt;/p&gt;
&lt;p&gt;Here’s what you need to get a sample Node.js project up and running.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/master/eureka-client-node/package.json&quot;&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &quot;dependencies&quot;: {
    &quot;eureka-js-client&quot;: &quot;^4.4.1&quot;,
    &quot;express&quot;: &quot;^4.16.3&quot;,
    &quot;nodemon&quot;: &quot;^1.18.4&quot;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this Node.js service, we just need to install the &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/eureka-js-client&quot;&gt;&lt;code&gt;eureka-js-client&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, and I added &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/express&quot;&gt;&lt;code&gt;express&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/express&quot;&gt;&lt;code&gt;nodemon&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; so I could easily make some REST calls to the application, as well as have the Node server automatically reload as I made tweaks to the system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/master/eureka-client-node/server.js&quot;&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&apos;use strict&apos;;

const express = require(&apos;express&apos;);
const Eureka = require(&apos;eureka-js-client&apos;).Eureka;

// Constants
const PORT = 3000;
const HOST = &apos;0.0.0.0&apos;;
const app = express();

// example configuration
const client = new Eureka({
  // application instance information
  instance: {
    app: &apos;a-node-service&apos;,
    hostName: &apos;localhost&apos;,
    ipAddr: &apos;127.0.0.1&apos;,
    statusPageUrl: &apos;http://localhost:3000&apos;,
    vipAddress: &apos;a-node-service&apos;,
    port: {
      $: PORT,
      &apos;@enabled&apos;: &apos;true&apos;,
    },
    dataCenterInfo: {
      &apos;@class&apos;: &apos;com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo&apos;,
      name: &apos;MyOwn&apos;,
    },
    registerWithEureka: true,
    fetchRegistry: true,
  },
  eureka: {
    // eureka server host / port
    host: &apos;localhost&apos;,
    port: 8761,
    servicePath: &apos;/eureka/apps/&apos;,
  },
});

client.logger.level(&apos;debug&apos;);
client.start(error =&amp;gt; {
  console.log(error || &apos;NodeJS Eureka Started!&apos;);

  // App
  app.get(&apos;/&apos;, (req, res) =&amp;gt; {
    res.send(&apos;Hello from NodeJS Eureka Client\n&apos;);
    res.end();
  });
});  

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used just one &lt;code&gt;server.js&lt;/code&gt; file for convenience and because this project is so small to begin with.&lt;/p&gt;
&lt;p&gt;What’s important is the &lt;code&gt;new Eureka()&lt;/code&gt; set up. Whereas with the Spring Boot projects, we set the application configurations in the &lt;code&gt;bootstrap.yml&lt;/code&gt; and &lt;code&gt;application.yml&lt;/code&gt;, for the JavaScript project, this config is set in the &lt;code&gt;server.js&lt;/code&gt; file or injected with a config file (for larger projects or projects with multiple different configurations based on production lifecycle).&lt;/p&gt;
&lt;p&gt;In here is where the application name is defined: &lt;code&gt;app: &apos;a-node-service&apos;&lt;/code&gt;, the host name, IP address, port, data center info, etc. are defined.&lt;/p&gt;
&lt;p&gt;Every parameter up to the &lt;code&gt;registerWithEureka&lt;/code&gt; and &lt;code&gt;fetchRegistry&lt;/code&gt; options are required or else the server will crash, but the &lt;code&gt;vipAddress&lt;/code&gt; and &lt;code&gt;dataCenterInfo&lt;/code&gt; fields can be added exactly as they’re written in the &lt;code&gt;eureka-client-js&lt;/code&gt; &lt;a href=&quot;https://www.npmjs.com/package/eureka-js-client#add-eureka-client-to-a-node-application&quot;&gt;documentation&lt;/a&gt;. They just have to be filled out.&lt;/p&gt;
&lt;p&gt;Last, but not least, once the client service has been set up, it is started with the &lt;code&gt;client.start()&lt;/code&gt; command, where I am console logging either the &lt;code&gt;error&lt;/code&gt; message if it fails to start or the &lt;code&gt;‘Node.js Eureka Started’&lt;/code&gt; message if connecting to the Eureka registry is successful.&lt;/p&gt;
&lt;h2&gt;Run the Eureka Service Registry&lt;/h2&gt;
&lt;p&gt;Let’s get this service registry up and running now. I’ve got full details to run all the service in the &lt;code&gt;README.md&lt;/code&gt; of my &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example&quot;&gt;example project here&lt;/a&gt;&lt;/strong&gt;, but here it is as well.&lt;/p&gt;
&lt;p&gt;We’ll &lt;code&gt;cd&lt;/code&gt; into each service contained within the one master project folder, if you have a file structure similar to the one prescribed by the Sping.io starter tutorial. Here’s what mine looks like for reference:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root/
├── eureka-client-java/ 
| ├── build.gradle 
| ├── src/ 
| | | ├── main/ 
| | | | ├── java/ 
| | | | ├── resources/ 
| | | | | ├── application.yml 
| | | | | ├── bootstrap.yml
├── eureka-client-node/ 
| ├── server.js
| ├── package.json
| ├── node-modules/
├── eureka-service/
| ├── build.gradle 
| ├── src/ 
| | | ├── main/ 
| | | | ├── java/ 
| | | | ├── resources/ 
| | | | | ├── application.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As I said, &lt;code&gt;cd&lt;/code&gt; into each repo &lt;code&gt;eureka-client-java/&lt;/code&gt;, &lt;code&gt;eureka-client-node/&lt;/code&gt;, and &lt;code&gt;eureka-service/&lt;/code&gt;, and for the two Spring Boot projects run &lt;code&gt;gradle clean build&lt;/code&gt; and then &lt;code&gt;gradle bootRun&lt;/code&gt; from the command line.&lt;/p&gt;
&lt;p&gt;For the Node.js project, run &lt;code&gt;npm start&lt;/code&gt; from another terminal window.&lt;/p&gt;
&lt;p&gt;Give it a minute for all the projects to spin up and be found by the registry service, then go to http://localhost:8761 and this is what you should see.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eureka-registry-service/spring-eureka-registry.png&quot; alt=&quot;Spring Eureka Registry application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;If you look closely in the ‘Instances currently registered with Eureka’ section, you’ll see our applications.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This is the Eureka server homepage, and if you look in the second section down the page, you’ll see ‘Instance currently registered with Eureka’, and the two service we built registered with it.&lt;/p&gt;
&lt;p&gt;To verify these services are really running, you can go to http://localhost:8091/service-instances/a-java/service and http://localhost:3000/ to see info from each service.&lt;/p&gt;
&lt;p&gt;Now, let’s take it a step further, because the whole point of having a service registry is to make it easier for clients registered there to ask questions about how to connect and communicate with the other available services:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Each service registers itself with the service registry and tells the registry where it lives (host, port, node name) and perhaps other service-specific metadata — things that other services can use to make informed decisions about it. Clients can ask questions about the service topology (“are there any ‘fulfillment-services’ available, and if so, where?”) and service capabilities (“can you handle X, Y, and Z?”).”&lt;/p&gt;
&lt;p&gt;— &lt;a href=&quot;https://spring.io/blog/2015/01/20/microservice-registration-and-discovery-with-spring-cloud-and-netflix-s-eureka&quot;&gt;Spring, Microservice Registration and Discovery with Spring Cloud and Netflix’s Eureka&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Set Up Extra Endpoints for the Services to Communicate&lt;/h2&gt;
&lt;p&gt;The next step I wanted to take was making it so I could get the service instance JSON data supplied by the Java service available through an endpoint from the Node.js service — which it can only get by communicating with the info supplied by the Eureka service registry.&lt;/p&gt;
&lt;p&gt;Here’s what to do:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example/blob/master/eureka-client-node/server.js&quot;&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var javaInstance = &apos;&apos;;

client.logger.level(&apos;debug&apos;);
client.start(error =&amp;gt; {
  console.log(error || &apos;NodeJS Eureka Started!&apos;);

  javaInstance = client.getInstancesByAppId(&apos;A-JAVA-SERVICE&apos;);
  // console.log(javaInstance);

  // App
  app.get(&apos;/&apos;, (req, res) =&amp;gt; {
    res.send(&apos;Hello from NodeJS Eureka Client\n&apos;);
    res.end();
  });

  const javaUrl = `${javaInstance[0].hostName}:${
    javaInstance[0].port.$
  }/service-instances/${javaInstance[0].app}`;

  console.log(javaUrl);

  // get java service info endpoint
  app.get(`/serviceInfo/${javaUrl}`, (req, res) =&amp;gt; {
    res.send(JSON.stringify(javaInstance), null, 2);
    res.end();
  });
});  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right before the &lt;code&gt;client.start()&lt;/code&gt; command in the &lt;code&gt;server.js&lt;/code&gt; file, I defined a variable called &lt;code&gt;javaInstance&lt;/code&gt;, and then used the method provided by the &lt;code&gt;eureka-client-js&lt;/code&gt; plugin &lt;code&gt;getInstancesByAppId()&lt;/code&gt; calling the Spring Boot service registered as &lt;code&gt;a-java-service&lt;/code&gt; to get its service information.&lt;/p&gt;
&lt;p&gt;With this, I could reconstruct the URL information supplied by the Spring Boot REST endpoint to get that service’s information. In short, I was able to parse out all the necessary info from the Java instance supplied by the Eureka server to reach it through the Node.js endpoint.&lt;/p&gt;
&lt;p&gt;Here’s what the URL comes out to be once the host name, port number and app name are acquired: http://localhost:3000/serviceInfo/192.168.1.18:8091/service-instances/A-JAVA-SERVICE .&lt;/p&gt;
&lt;p&gt;And here’s what you’d see if both the Node.js and Java services are running and registered with the Eureka server:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/eureka-registry-service/spring-boot-json.png&quot; alt=&quot;JSON for Spring Boot service&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Spring Boot service data courtesy of a Node.js service endpoint.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Voila. The above JSON (not well formatted) is for the a-java-service, accessed through an endpoint on the Node.js service. Just be sure to make that URL call to the Spring Boot service inside of the client.start() command, otherwise you won’t be able to access all the instance information supplied from the getInstancesByAppId() call to the Eureka server.&lt;/p&gt;
&lt;p&gt;At this point, Eureka is doing what it’s designed to do: it registers services and provides information from one to the other, minus the hardcoded complexity developers used to have to be responsible for remembering and implementing manually.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As I said at the beginning, building applications according to the microservice architecture pattern means more complexity managing the individual services, but greater fault tolerance and reliability of the application as a whole.&lt;/p&gt;
&lt;p&gt;Service registries like Netflix’s Eureka server help manage this additional complexity, and when coupled with Spring’s Cloud technology it becomes infinitely easier to use. The next step after this would be using something like Zuul to assist with dynamic routing, load balancing between instances, handling security, and more. But that’s for another blog post.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this proves helpful and gives you a better understanding of how to use Netflix’s Eureka server with the help of Spring Cloud, and discover Java and Node.js services.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://microservices.io/patterns/microservices.html&quot;&gt;Microservice Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/eureka-services-example&quot;&gt;Eureka Service Registry Example Github repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Netflix/eureka/wiki&quot;&gt;Netflix Eureka Github repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/guides/gs/service-registration-and-discovery/&quot;&gt;Spring: Service Registration and Discovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/eureka-js-client&quot;&gt;Eureka Client JS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/blog/2015/01/20/microservice-registration-and-discovery-with-spring-cloud-and-netflix-s-eureka&quot;&gt;Spring: Microservice Registration and Discovery with Spring Cloud and Netflix’s Eureka&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>java</category><category>javascript</category><category>nodejs</category><category>spring boot</category></item><item><title>Implementing JSON Web Tokens &amp; Passport.js in a React App</title><link>https://www.paigeniedringhaus.com/blog/implementing-json-web-tokens-passportjs-in-a-react-app/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/implementing-json-web-tokens-passportjs-in-a-react-app/</guid><description>How and why to use the various auth options Passport.js has to offer.</description><pubDate>Wed, 12 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/jwt-passportjs-react-app/passport-hero.png&quot; alt=&quot;Passport, JWT, Express, and React logos&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Before you say it, I know, I know. There’s already a literal ton of MERN tutorials out there showing how to use JSON Web Tokens (JWT, pronounced &quot;jot&quot;) and Passport.js with Express.&lt;/p&gt;
&lt;p&gt;But here’s what every one of those tutorials failed to mention, and what mine will cover: &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt; to use the various authentication flavors Passport offers (including &lt;code&gt;passport-jwt&lt;/code&gt;), and the gotchas that tripped me up for hours on end as I put together a user registration application.&lt;/p&gt;
&lt;p&gt;I don’t know what your experience has been, but the majority of the projects I’ve worked on professionally have come with authorization already prebuilt by someone else. So in addition to improving my MERN skills, I viewed this as an opportunity to learn more about security and authentication and different ways to do it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This post will mainly cover how to implement of Passport and JWT on the server side, because that’s where most of the magic happens, but if you want, you can see the source files and download the full MERN project &lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once it’s correctly hooked up on the backend, the frontend is purely React.&lt;/p&gt;
&lt;p&gt;Before I jump into all that though, let me give you a quick run down of JWT and Passport.js authentication.&lt;/p&gt;
&lt;h2&gt;What is a JSON Web Token?&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/jwt-passportjs-react-app/jwt.png&quot; alt=&quot;JWT logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;&lt;a href=&quot;https://jwt.io/&quot;&gt;JSON Web Token&lt;/a&gt;&lt;/strong&gt;, according to the site is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“…an open standard (&lt;a href=&quot;https://tools.ietf.org/html/rfc7519&quot;&gt;RFC 7519&lt;/a&gt;) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.” — &lt;a href=&quot;https://jwt.io/&quot;&gt;JWT.io&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Essentially, JWTs are digitally signed tokens that can be verified and trusted, and they’re becoming more and more popular for security and authorization between parties (like servers and clients) and for exchanging sensitive information, while verifying the token hasn’t been tampered with or decoded.&lt;/p&gt;
&lt;p&gt;I won’t go into the details of how the tokens work, you can read all about that from a much more qualified source than I am &lt;a href=&quot;https://jwt.io/introduction/&quot;&gt;here&lt;/a&gt;, but suffice it to say, I chose to use JWT as part of my user verification strategy along with Passport.js to make my simple user registration application secure (and because I was curious to see if I could do it, since I didn’t have a whole lot of hands on experience implementing authorization).&lt;/p&gt;
&lt;p&gt;With that covered, the next piece of my authentication solution is Passport.js.&lt;/p&gt;
&lt;h2&gt;What is Passport.js &amp;amp; Why Should I Use it?&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/jwt-passportjs-react-app/passport.png&quot; alt=&quot;Passport logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.passportjs.org/&quot;&gt;Passport.js&lt;/a&gt;&lt;/strong&gt; is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Simple, unobtrusive authentication for Node.js — &lt;a href=&quot;https://www.passportjs.org/&quot;&gt;Passport.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And it works exceedingly well with Express.js. Passport is authentication middleware for Node, which serves one purpose, to authenticate requests, in a modular way that leaves all other functionality to the application itself, making code cleaner, easier to maintain and provides a clear separation of concerns.&lt;/p&gt;
&lt;p&gt;If you type the term &quot;JavaScript authentication middleware&quot; or even just &quot;JavaScript authentication&quot; into the Google search bar, Passport.js ranks within the top 5 search results. That’s how ubiquitous this solution is in the JavaScript ecosystem.&lt;/p&gt;
&lt;p&gt;Did I mention it boasts more than 500+ authentication strategies? It does. Whether you wish to log in with a simple username and password, with Github credentials, Facebook, oAuth, etc., there’s probably a Passport.js strategy for it.&lt;/p&gt;
&lt;p&gt;So it was a simple decision to choose Passport as part of my authorization strategy.&lt;/p&gt;
&lt;p&gt;I’d like to add documentation on the site is pretty good, though some things like custom callbacks require much more careful reading (and trial and error, for me) to correctly set up. But I’m getting ahead of myself, I’ll cover the gotchas in implementation.&lt;/p&gt;
&lt;h2&gt;How Do I Implement Them in Express.js (and a little React)?&lt;/h2&gt;
&lt;p&gt;Now on to the fun part, how do you implement both Passport.js and JWT into an Express/Node application? To be honest, it stumped me for a good while. But after numerous tutorials, re-readings of documentation and turning to Stack Overflow for help, I got to a place of understanding and satisfaction.&lt;/p&gt;
&lt;p&gt;I should say, one of my goals for this app was to make it modular, make it super simple to add or remove functionality, so when you see my file structure, you’ll notice all the routes for the CRUD functionality (create, read, update, delete) are built into separate files, and all the Passport authentication is handled in one, centralized file as well. Here’s a look at the file structure of the API portion of my app.&lt;/p&gt;
&lt;h3&gt;The API File Tree&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;root/
├── api/ 
| ├── config 
| | ├── passport.js 
| | ├── jwtConfig.js
| ├── server.js 
| ├── sequelize.js 
| ├── package.json
| ├── models/ 
| | ├── user.js
| ├── routes/ 
| | ├── deleteUser.js 
| | ├── findUsers.js 
| | ├── loginUser.js 
| | ├── registerUser.js
| | ├── updateUser.js
| ├── node-modules/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The &lt;code&gt;package.json&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;And here is the &lt;code&gt;package.json&lt;/code&gt; and its dependencies so you can see exactly what I’m using.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/package.json&quot;&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;mysqlregistration-api&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;nodemon server.js --exec babel-node --presets es2015&quot;
  },
  &quot;repository&quot;: {
    &quot;type&quot;: &quot;git&quot;,
    &quot;url&quot;: &quot;git+https://github.com/paigen11/mysqlRegistration.git&quot;
  },
  &quot;author&quot;: &quot;Paige Niedringhaus&quot;,
  &quot;license&quot;: &quot;MIT&quot;,
  &quot;bugs&quot;: {
    &quot;url&quot;: &quot;https://github.com/paigen11/mysqlRegistration/issues&quot;
  },
  &quot;homepage&quot;: &quot;https://github.com/paigen11/mysqlRegistration#readme&quot;,
  &quot;dependencies&quot;: {
    &quot;babel-cli&quot;: &quot;^6.26.0&quot;,
    &quot;babel-preset-es2015&quot;: &quot;^6.24.1&quot;,
    &quot;babel-preset-stage-0&quot;: &quot;^6.24.1&quot;,
    &quot;bcrypt&quot;: &quot;^3.0.2&quot;,
    &quot;body-parser&quot;: &quot;^1.18.3&quot;,
    &quot;cors&quot;: &quot;^2.8.4&quot;,
    &quot;dotenv&quot;: &quot;^6.1.0&quot;,
    &quot;express&quot;: &quot;^4.16.3&quot;,
    &quot;helmet&quot;: &quot;^3.20.1&quot;,
    &quot;jsonwebtoken&quot;: &quot;^8.3.0&quot;,
    &quot;morgan&quot;: &quot;^1.9.0&quot;,
    &quot;mysql2&quot;: &quot;^1.5.3&quot;,
    &quot;nodemailer&quot;: &quot;^4.6.8&quot;,
    &quot;nodemon&quot;: &quot;^1.18.3&quot;,
    &quot;passport&quot;: &quot;^0.4.0&quot;,
    &quot;passport-jwt&quot;: &quot;^4.0.0&quot;,
    &quot;passport-local&quot;: &quot;^1.0.0&quot;,
    &quot;sequelize&quot;: &quot;^5.3.0&quot;,
    &quot;sequelize-cli&quot;: &quot;^4.0.0&quot;,
    &quot;swagger-jsdoc&quot;: &quot;^3.2.9&quot;,
    &quot;swagger-ui-express&quot;: &quot;^4.0.2&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The dependencies include a few extras like &lt;code&gt;babel&lt;/code&gt; so I can use ES6 syntax in my Node.js app, &lt;code&gt;bcrypt&lt;/code&gt; for password hashing and &lt;code&gt;sequelize&lt;/code&gt; as my MySQL ORM, but the things you need to focus on are &lt;code&gt;jsonwebtoken&lt;/code&gt;, &lt;code&gt;passport&lt;/code&gt;, &lt;code&gt;passport-local&lt;/code&gt; and &lt;code&gt;passport-jwt&lt;/code&gt;. These are the necessities for this blog.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;server.js&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;I’ll start with the &lt;code&gt;server.js&lt;/code&gt; file first, as it requires the least explanation. This file is purely for starting the server, initializing the use of Passport in the app and setting up the routes and parsing of requests from the client side.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/server.js&quot;&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import express from &apos;express&apos;;
import Cors from &apos;cors&apos;;
import bodyParser from &apos;body-parser&apos;;
import logger from &apos;morgan&apos;;
import passport from &apos;passport&apos;;
import helmet from &apos;helmet&apos;;

const app = express();

const API_PORT = process.env.API_PORT || 3000;

require(&apos;./config/passport&apos;);

app.use(Cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(logger(&apos;dev&apos;));
app.use(helmet());
app.use(passport.initialize());

require(&apos;./routes/loginUser&apos;)(app);
require(&apos;./routes/registerUser&apos;)(app);
require(&apos;./routes/findUsers&apos;)(app);
require(&apos;./routes/deleteUser&apos;)(app);
require(&apos;./routes/updateUser&apos;)(app);

// eslint-disable-next-line no-console
app.listen(API_PORT, () =&amp;gt; console.log(`Listening on port ${API_PORT}`));

module.exports = app;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A little ES6 in the &lt;code&gt;imports&lt;/code&gt; and &lt;code&gt;consts&lt;/code&gt;, but what you should focus on is the &lt;code&gt;passport.initialize()&lt;/code&gt; and the &lt;code&gt;routes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pretty straightforward right? Great. Moving on.&lt;/p&gt;
&lt;p&gt;You might also have noticed the &lt;code&gt;require(&apos;./config/passport&apos;);&lt;/code&gt;, this is the next step I’ll go over. The JWT and Passport configuration, inside of the folder named &lt;code&gt;config/&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;jwtConfig.js&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;The JWT config is very simple, it’s the secret required by JWT to encode and decode the tokens. Typically, this would be stored as an environmental variable in a file that’s not checked in to Github, but to show how this works, I’ve set it in here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/config/jwtConfig.js&quot;&gt;&lt;code&gt;jwtConfig.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = {
  secret: &apos;jwt-secret&apos;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The &lt;code&gt;passport.js&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/config/passport.js&quot;&gt;&lt;code&gt;passport.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import bcrypt from &apos;bcrypt&apos;;
import jwtSecret from &apos;./jwtConfig&apos;;

const BCRYPT_SALT_ROUNDS = 12;

const passport = require(&apos;passport&apos;);
const LocalStrategy = require(&apos;passport-local&apos;).Strategy;
const JWTstrategy = require(&apos;passport-jwt&apos;).Strategy;
const ExtractJWT = require(&apos;passport-jwt&apos;).ExtractJwt;
const User = require(&apos;../sequelize&apos;);

passport.use(
  &apos;register&apos;,
  new LocalStrategy(
    {
      usernameField: &apos;username&apos;,
      passwordField: &apos;password&apos;,
      passReqToCallback: true,
      session: false,
    },
    (req, username, password, done) =&amp;gt; {
      try {
        User.findOne({
          where: {
            [Op.or]: [
              {
                username,
              },
              { email: req.body.email },
            ],
          },
        }).then(user =&amp;gt; {
          if (user != null) {
            console.log(&apos;username or email already taken&apos;);
            return done(null, false, {
              message: &apos;username or email already taken&apos;,
            });
          }
          bcrypt.hash(password, BCRYPT_SALT_ROUNDS).then(hashedPassword =&amp;gt; {
            User.create({
              username,
              password: hashedPassword,
              email: req.body.email,
            }).then(user =&amp;gt; {
              console.log(&apos;user created&apos;);
              return done(null, user);
            });
          });
        });
      } catch (err) {
        return done(err);
      }
    },
  ),
);

passport.use(
  &apos;login&apos;,
  new LocalStrategy(
    {
      usernameField: &apos;username&apos;,
      passwordField: &apos;password&apos;,
      session: false,
    },
    (username, password, done) =&amp;gt; {
      try {
        User.findOne({
          where: {
            username,
          },
        }).then(user =&amp;gt; {
          if (user === null) {
            return done(null, false, { message: &apos;bad username&apos; });
          }
          bcrypt.compare(password, user.password).then(response =&amp;gt; {
            if (response !== true) {
              console.log(&apos;passwords do not match&apos;);
              return done(null, false, { message: &apos;passwords do not match&apos; });
            }
            console.log(&apos;user found &amp;amp; authenticated&apos;);
            return done(null, user);
          });
        });
      } catch (err) {
        done(err);
      }
    },
  ),
);

const opts = {
  jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme(&apos;JWT&apos;),
  secretOrKey: jwtSecret.secret,
};

passport.use(
  &apos;jwt&apos;,
  new JWTstrategy(opts, (jwt_payload, done) =&amp;gt; {
    try {
      User.findOne({
        where: {
          id: jwt_payload.id,
        },
      }).then(user =&amp;gt; {
        if (user) {
          console.log(&apos;user found in db in passport&apos;);
          done(null, user);
        } else {
          console.log(&apos;user not found in db&apos;);
          done(null, false);
        }
      });
    } catch (err) {
      done(err);
    }
  }),
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, all this is part of the &lt;code&gt;passport.js&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;I realize this is a lot of code to take in. If you’d like to see just the code for Passport and the routes with Passport authentication, I created a few gists &lt;strong&gt;&lt;a href=&quot;https://gist.github.com/paigen11/c72c8c20da9cd440f45025a1b05e5e58&quot;&gt;here&lt;/a&gt;&lt;/strong&gt; with the code.&lt;/p&gt;
&lt;p&gt;I’ll walk through the two types of Passport implementation happening here: &lt;strong&gt;&lt;a href=&quot;https://www.passportjs.org/packages/passport-local/&quot;&gt;passport-local&lt;/a&gt;&lt;/strong&gt; for the &lt;code&gt;register&lt;/code&gt; and &lt;code&gt;login&lt;/code&gt; methods and &lt;strong&gt;&lt;a href=&quot;https://www.passportjs.org/packages/passport-jwt/&quot;&gt;passport-jwt&lt;/a&gt;&lt;/strong&gt; for the &lt;code&gt;jwt&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;passport-local&lt;/code&gt; uses a username and password, and &lt;code&gt;passport-jwt&lt;/code&gt; uses a JWT payload to verify the user is legit.&lt;/p&gt;
&lt;p&gt;Like I said earlier, the documentation for both using just Express.js is fairly good, but the trick comes in combining it with the MySQL database and the information passed from the React client on the frontend.&lt;/p&gt;
&lt;p&gt;Once the &lt;code&gt;passport-local&lt;/code&gt; strategy has been passed a username and password (which I verify that both inputs are at least filled on the client side before ever calling back to the server), the first check I do on the backend is with &lt;a href=&quot;https://sequelize.org/&quot;&gt;Sequelize&lt;/a&gt;, my SQL ORM (like Mongoose for MongoDB), to determine if that username exists in the database. If it returns &lt;code&gt;null&lt;/code&gt;, the authentication fails (no user in the db matches), and typically, a &lt;code&gt;401 Unauthorized&lt;/code&gt; HTTP status would be thrown back from the server to the client with no further information.&lt;/p&gt;
&lt;h3&gt;Passport.js Gotcha #1: Info in Error Handling&lt;/h3&gt;
&lt;p&gt;This type of error handling, to me, was the most frustrating thing about Passport. The lack of information to let a user (or myself) know what the actual error was beyond &lt;code&gt;401 Unauthorized&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But there’s a better solution that requires a little extra work, with &lt;strong&gt;custom callbacks&lt;/strong&gt;. I’ll go into more detail about the callback soon, but for now, you can see if there’s some sort of error, instead of returning a &lt;code&gt;return done(null, user);&lt;/code&gt;, Passport can pass back &lt;code&gt;return done(null, false, { message: &apos;bad username or passwords don&apos;t match&apos; })&lt;/code&gt;;.&lt;/p&gt;
&lt;p&gt;This message can then be passed back from the server to the client, actually telling the user what the problem is (which is what I wanted for this app). If you prefer just to tell the user their authentication failed, but not disclose why, that’s cool too. Your choice, but I want to show how error messaging can be done.&lt;/p&gt;
&lt;p&gt;The rest of the &lt;code&gt;passport-local&lt;/code&gt; strategy is pretty self-explanatory, on &lt;code&gt;register&lt;/code&gt; the user’s password is hashed and salted with the encryption package &lt;strong&gt;&lt;a href=&quot;https://github.com/kelektiv/node.bcrypt.js&quot;&gt;&lt;code&gt;bcrypt&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, and then when the &lt;code&gt;login&lt;/code&gt; method is invoked, it hashes the newly entered password and checks the passwords with bcrypt’s &lt;code&gt;compare&lt;/code&gt; function before returning either a positive or negative on the verification.&lt;/p&gt;
&lt;p&gt;Now that brings me to the &lt;code&gt;passport-jwt&lt;/code&gt; strategy, which is named &lt;code&gt;jwt&lt;/code&gt;. This is the authentication that’s called on the protected routes in the application: &lt;code&gt;findUsers&lt;/code&gt;, &lt;code&gt;updateUser&lt;/code&gt;, &lt;code&gt;deleteUser&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For the jwt strategy, the JWT is passed back from the client with each call to the server (I passed mine in an authorization header with the key: &lt;code&gt;JWT&lt;/code&gt;), which is extracted and then decoded using the secret (which is stored in another file, but should really be an environment variable known only to the system).&lt;/p&gt;
&lt;p&gt;Once the JWT payload is decrypted, the ID (which for me is the username) can be searched for in the database just like the &lt;code&gt;passport-local&lt;/code&gt; strategy does, and either returned with &lt;code&gt;done(null, user);&lt;/code&gt;, if the user is found or with &lt;code&gt;done(null, false);&lt;/code&gt; if it’s not (which should almost never happen because the JWT includes the username in its encrypted form, so unless that’s somehow been tampered with or the db has been, it should be able to find the user).&lt;/p&gt;
&lt;h3&gt;Passport.js Gotcha #2: Passport-Local Wants Return, Passport-JWT Does Not&lt;/h3&gt;
&lt;p&gt;This brings me to my second gotcha which tripped me up for a good bit of time; not all passport strategies require the same resolution.&lt;/p&gt;
&lt;p&gt;If you’re looking closely, you’ll see the &lt;code&gt;passport-local&lt;/code&gt; strategies both have &lt;code&gt;return done(null, user);&lt;/code&gt; but the &lt;code&gt;passport-jwt&lt;/code&gt; strategy has &lt;code&gt;done (null, user);&lt;/code&gt;. See the difference? It’s minuscule, but having (or removing that &lt;code&gt;return&lt;/code&gt;), is the difference between that user data being passed back from the middleware to the server or not.&lt;/p&gt;
&lt;p&gt;And it halted my progress for a good few hours, before the kindness of Stack Overflow helped me work through the issue (it’s the first time I’ve actually had to ask SO for an answer I couldn’t find already, but it was well worth it). So be aware of when to &lt;code&gt;return&lt;/code&gt; or not.&lt;/p&gt;
&lt;p&gt;Ok, so I’ve walked through the two Passport strategies and the three methods I’m using for middleware authentication in my program, now on to after the authentication on the server.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;register.js&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;The next step is how to implement these newly minted methods inside of the various routes. Here’s the &lt;code&gt;registerUser&lt;/code&gt; route.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/registerUser.js&quot;&gt;&lt;code&gt;registerUser.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import passport from &apos;passport&apos;;
import User from &apos;../sequelize&apos;;

module.exports = app =&amp;gt; {
  app.post(&apos;/registerUser&apos;, (req, res, next) =&amp;gt; {
    passport.authenticate(&apos;register&apos;, (err, user, info) =&amp;gt; {
      if (err) {
        console.error(err);
      }
      if (info !== undefined) {
        console.error(info.message);
        res.status(403).send(info.message);
      } else {
        req.logIn(user, error =&amp;gt; {
          const data = {
            first_name: req.body.first_name,
            last_name: req.body.last_name,
            email: req.body.email,
            username: user.username,
          };
          User.findOne({
            where: {
              username: data.username,
            },
          }).then(user =&amp;gt; {
            user
              .update({
                first_name: data.first_name,
                last_name: data.last_name,
                email: data.email,
              })
              .then(() =&amp;gt; {
                console.log(&apos;user created in db&apos;);
                res.status(200).send({ message: &apos;user created&apos; });
              });
          });
        });
      }
    })(req, res, next);
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this implementation of Passport looks a little different than most examples out there, and it’s because I’m using the custom callback version of Passport, which requires a closure call. I’m using this so that the error message that’s passed back if Passport’s authentication fails can be sent from the server to the client instead of the obscure &lt;code&gt;401 Unauthorized&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because this is being implemented as a callback (which is why you see &lt;code&gt;(req, res, next)&lt;/code&gt; not once, but twice in these scripts; it gives me access to the &lt;code&gt;(err, user, info)&lt;/code&gt; from the Passport middleware.&lt;/p&gt;
&lt;p&gt;The info is what I’m interested in — that’s the message being sent back, so if the info is anything besides &lt;code&gt;null&lt;/code&gt;, that means the authentication failed and I can then send the message to the client to let them know why.&lt;/p&gt;
&lt;h3&gt;Passport.js Gotcha #3: Don&apos;t Forget &lt;code&gt;req.logIn()&lt;/code&gt; in Your Custom Callback&lt;/h3&gt;
&lt;p&gt;Now, I’m to the third Passport gotcha, in order to make the closures and custom callbacks work with &lt;code&gt;passport-local&lt;/code&gt;, the little method &lt;strong&gt;&lt;a href=&quot;https://www.passportjs.org/concepts/authentication/login/&quot;&gt;&lt;code&gt;req.logIn()&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; must be called before the &lt;code&gt;user&lt;/code&gt; data is handled if it comes back successfully from the middleware.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is documented in the &lt;a href=&quot;https://www.passportjs.org/concepts/authentication/login/&quot;&gt;Passport documentation&lt;/a&gt;, but it’s importance is not stressed as much as I would like (and I missed it the first few times trying to get custom callbacks to work), which is why I highlight it now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It must happen, and once that’s done, I’m able to take the extra inputs from the client side for registering a user, find that same user created in the database during the &lt;code&gt;passport-local&lt;/code&gt; &lt;code&gt;register&lt;/code&gt; call, and update the user file with the extra info. I could have passed this extra data through to the middleware as well, but I want Passport to only handle authentication, not user creation as well. Modularization, remember.&lt;/p&gt;
&lt;p&gt;Plus, if the authentication were to be split out into a separate service with a separate database of just encrypted usernames and passwords, this would make it easier to do so, then use the username or ID to find and update the corresponding user record in this registration service.&lt;/p&gt;
&lt;p&gt;Once all that’s been successfully taken care of, a &lt;code&gt;200&lt;/code&gt; HTTP status and success message are sent back to the client.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;loginUser.js&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;Seeing the &lt;code&gt;loginUser&lt;/code&gt; route now should make more sense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/loginUser.js&quot;&gt;&lt;code&gt;loginUser.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import jwt from &apos;jsonwebtoken&apos;;
import passport from &apos;passport&apos;;
import jwtSecret from &apos;../config/jwtConfig&apos;;
import User from &apos;../sequelize&apos;;

module.exports = app =&amp;gt; {
  app.post(&apos;/loginUser&apos;, (req, res, next) =&amp;gt; {
    passport.authenticate(&apos;login&apos;, (err, users, info) =&amp;gt; {
      if (err) {
        console.error(`error ${err}`);
      }
      if (info !== undefined) {
        console.error(info.message);
        if (info.message === &apos;bad username&apos;) {
          res.status(401).send(info.message);
        } else {
          res.status(403).send(info.message);
        }
      } else {
        req.logIn(users, () =&amp;gt; {
          User.findOne({
            where: {
              username: req.body.username,
            },
          }).then(user =&amp;gt; {
            const token = jwt.sign({ id: user.id }, jwtSecret.secret, {
              expiresIn: 60 * 60,
            });
            res.status(200).send({
              auth: true,
              token,
              message: &apos;user found &amp;amp; logged in&apos;,
            });
          });
        });
      }
    })(req, res, next);
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same style of custom callbacks and closures are used, the biggest difference is that once the user is successfully verified and located in the database, the JWT token is generated using the &lt;code&gt;jwt.sign();&lt;/code&gt; function, which sets the username as the ID passed in the JWT, and encrypted by the secret I set earlier.&lt;/p&gt;
&lt;p&gt;Once again, if all this works successfully, a &lt;code&gt;200&lt;/code&gt; HTTP status is sent with a boolean I named &lt;code&gt;auth&lt;/code&gt; set to true for the client side, the newly generated token and a short login success message.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;findUsers.js&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;And last, but not least, here’s the &lt;code&gt;findUsers&lt;/code&gt; route. I used the same &lt;code&gt;passport-jwt&lt;/code&gt; authentication for the &lt;code&gt;updateUser&lt;/code&gt; and &lt;code&gt;deleteUser&lt;/code&gt; routes, so I’ll just show this one as an example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/master/api/routes/findUsers.js&quot;&gt;&lt;code&gt;findUsers.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import passport from &apos;passport&apos;;
import User from &apos;../sequelize&apos;;

module.exports = (app) =&amp;gt; {
  app.get(&apos;/findUser&apos;, (req, res, next) =&amp;gt; {
    passport.authenticate(&apos;jwt&apos;, { session: false }, (err, user, info) =&amp;gt; {
      if (err) {
        console.log(err);
      }
      if (info !== undefined) {
        console.log(info.message);
        res.status(401).send(info.message);
      } else if (user.username === req.query.username) {
        User.findOne({
          where: {
            username: req.query.username,
          },
        }).then((userInfo) =&amp;gt; {
          if (userInfo != null) {
            console.log(&apos;user found in db from findUsers&apos;);
            res.status(200).send({
              auth: true,
              first_name: userInfo.first_name,
              last_name: userInfo.last_name,
              email: userInfo.email,
              username: userInfo.username,
              password: userInfo.password,
              message: &apos;user found in db&apos;,
            });
          } else {
            console.error(&apos;no user exists in db with that username&apos;);
            res.status(401).send(&apos;no user exists in db with that username&apos;);
          }
        });
      } else {
        console.error(&apos;jwt id and username do not match&apos;);
        res.status(403).send(&apos;username and jwt token do not match&apos;);
      }
    })(req, res, next);
  });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used custom callbacks for all my Passport authenticated routes (I appreciate good, clear error handling), so this code style should look routine by now.&lt;/p&gt;
&lt;p&gt;This time, when &lt;code&gt;passport.authenticate()&lt;/code&gt; is called, I implement the JWT strategy defined in the &lt;code&gt;passport.js&lt;/code&gt; file. The same &lt;code&gt;(err, user, info)&lt;/code&gt; gets passed back from the middleware, but there’s no call from &lt;code&gt;req.logIn()&lt;/code&gt; this time.&lt;/p&gt;
&lt;p&gt;Instead, I just return the &lt;code&gt;user&lt;/code&gt; object found during the authentication and pass all the required fields to the client along with the &lt;code&gt;auth&lt;/code&gt; boolean and success message. The JWT token is still stored in local storage on the client side so there’s no need to regenerate or pass it to the client again as well. Which brings me to my final Passport gotcha.&lt;/p&gt;
&lt;h3&gt;Passport.js Gotcha #4: Passing Authorization Headers Correctly&lt;/h3&gt;
&lt;p&gt;This one’s not exactly a Passport-specific gotcha, but it is yet another thing that tripped me up.&lt;/p&gt;
&lt;p&gt;As I said, I pieced together my (now much more whole) understanding of JWT and Passport from a bunch of other tutorials and documentation, and one of those tutorials led me astray. It had me passing the JWT back to the client in something besides true authorization headers, which is the way that I chose to have my &lt;code&gt;passport-jwt&lt;/code&gt; strategy extract the JWT payload from the client request.&lt;/p&gt;
&lt;p&gt;For this reason, I wanted to touch briefly on one piece of the frontend code, where I pass back the token in the proper format, so you don’t have to waste the time debugging like I did.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport/blob/8d94f0289ec97d86683049b1dc06efa37f95f474/client/src/containers/Profile.js&quot;&gt;&lt;code&gt;Profile.js&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; async componentDidMount() {
    const accessString = localStorage.getItem(&apos;JWT&apos;);
    const {
      match: {
        params: { username },
      },
    } = this.props;

    if (accessString == null) {
      this.setState({
        isLoading: false,
        error: true,
      });
    } else {
      try {
        const response = await axios.get(&apos;http://localhost:3003/findUser&apos;, {
          params: {
            username,
          },
          headers: { Authorization: `JWT ${accessString}` },
        });
        this.setState({
          first_name: response.data.first_name,
          last_name: response.data.last_name,
          email: response.data.email,
          username: response.data.username,
          password: response.data.password,
          isLoading: false,
          error: false,
        });
      } catch (error) {
        console.error(error.response.data);
        this.setState({
          error: true,
        });
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m using the popular promise-based HTTP client &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/axios&quot;&gt;Axios&lt;/a&gt;&lt;/strong&gt; to make my server calls, but what you really need to notice is the &lt;code&gt;headers&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;Before the call to the server happens, I extract the JWT from local storage using &lt;code&gt;localStorage.getItem(&apos;JWT&apos;)&lt;/code&gt; (the key I set with the JWT value when I passed the token forward from the &lt;code&gt;loginUser()&lt;/code&gt; route on the server side), and then I set it using &lt;code&gt;headers: { Authorization: &lt;/code&gt;JWT ${accessString}&lt;code&gt; }&lt;/code&gt; and a little ES6 string interpolation. That way, if my authorization headers had more than one value to parse out, it would still be easy for &lt;code&gt;passport-jwt&lt;/code&gt; to extract the correct JWT payload info by finding the string associated with &quot;JWT&quot;.&lt;/p&gt;
&lt;p&gt;And that’s it, I just wanted to cover it because it blocked me for a while and only through API testing with &lt;strong&gt;&lt;a href=&quot;https://insomnia.rest/&quot;&gt;Insomnia&lt;/a&gt;&lt;/strong&gt;, could I confirm my JWT token was actually working, and suss out that I was passing authorization headers from the client side incorrectly.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I know I wrote a lot (and provided a bunch of code snippets and gists), but authentication is not a simple concept. Nor is it truly possible to really make an app so secure no one will ever be able to hack it. But if you take precautions like JWT and Passport.js authentication middleware, your Node.js app should have a better chance to withstand people with malicious intent.&lt;/p&gt;
&lt;p&gt;Just be sure to look out for the gotchas I highlighted around Passport — and you’ll be on your way to a more secure site.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this proves helpful and gives you a better understanding of implementing Passport authentication and using JSON web tokens.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.passportjs.org/&quot;&gt;Passport.js&lt;/a&gt; website&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jwt.io/&quot;&gt;JSON Web Tokens&lt;/a&gt; website&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mysql-registration-passport&quot;&gt;MERN App with Passport &amp;amp; JWT repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/paigen11/c72c8c20da9cd440f45025a1b05e5e58&quot;&gt;Gists&lt;/a&gt; of Passport implementation with routes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/axios&quot;&gt;Axios&lt;/a&gt; HTTP library&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>express</category><category>javascript</category><category>jwt</category><category>react</category><category>nodejs</category></item><item><title>Postman vs. Insomnia: Comparing the API Testing Tools</title><link>https://www.paigeniedringhaus.com/blog/postman-vs-insomnia-comparing-the-api-testing-tools/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/postman-vs-insomnia-comparing-the-api-testing-tools/</guid><description>The pros and cons of each testing tool, so you can find the best for your needs.</description><pubDate>Sat, 01 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/postman-vs-insomnia/postman-insomnia-hero.png&quot; alt=&quot;Postman logo vs Insomnia logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Are you familiar with API endpoint testing? If you’re not, let me give you a quick definition before we go any further.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;API testing is a type of &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_testing&quot;&gt;software testing&lt;/a&gt; that involves testing &lt;a href=&quot;https://en.wikipedia.org/wiki/Application_programming_interface&quot;&gt;application programming interfaces&lt;/a&gt; (APIs) directly and as part of &lt;a href=&quot;https://en.wikipedia.org/wiki/Integration_testing&quot;&gt;integration testing&lt;/a&gt; to determine if they meet expectations for functionality, reliability, performance, and security.&lt;/p&gt;
&lt;p&gt;— Wikipedia, API testing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;API endpoint testing is one of the most important things we do as web developers. If the routes to reach our data are incorrect, the required parameters are not included, the authorization is missing, or a host of other things aren’t correctly hooked up, your app doesn’t work. If your app doesn’t work, your customers can’t use it. If your customers can’t use it, it’s going to be a really bad day for you, your team, your boss, and so on and so forth.&lt;/p&gt;
&lt;p&gt;Which is why we have things like API testing tools. These tools allow us, as web developers, to test that when we pass a specific set of data (or not) to our application it will return the response we expect. It’s a pretty simple idea, but it makes our lives (and development cycles) so much easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This will NOT be a blog post about how to use Postman or Insomnia (there’s plenty of those already, including the documentation on their own websites). &lt;strong&gt;This will be a comparison of the features the two offer, to help you make a better decision of which to use to suit your dev team’s needs.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;API Testing Tools Benefits&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/postman-vs-insomnia/api-testing.jpeg&quot; alt=&quot;API testing diagram&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Here’s some of the biggest benefits to using an API testing tool, as briefly mentioned above.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quicker setup and testing of endpoints (you don’t have to go through the whole user flow to set up data and then execute the commands to change the data),&lt;/li&gt;
&lt;li&gt;Less command line interaction,&lt;/li&gt;
&lt;li&gt;Multiple ways to set up authorization depending on which type you’re using,&lt;/li&gt;
&lt;li&gt;Nicer formatting of code being sent and received,&lt;/li&gt;
&lt;li&gt;Easier performance and reliability testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Contenders: Postman &amp;amp; Insomnia&lt;/h2&gt;
&lt;p&gt;There’s two popular API testing tools I’ll be talking about today. &lt;strong&gt;&lt;a href=&quot;https://www.getpostman.com/&quot;&gt;Postman&lt;/a&gt;&lt;/strong&gt;, a suite of tools which bills its ecosystem as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“the Only Complete API Development Environment” — Postman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And &lt;strong&gt;&lt;a href=&quot;https://insomnia.rest/&quot;&gt;Insomnia&lt;/a&gt;&lt;/strong&gt;, a REST client which claims you can&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“debug APIs like a human, not a robot” — Insomnia&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So without further ado, let’s start by seeing what functionalities they share.&lt;/p&gt;
&lt;h3&gt;What They Both Offer&lt;/h3&gt;
&lt;p&gt;Insomnia and Postman both share a lot of benefits that are extremely helpful to developers on front-end teams, back-end teams and full-stack teams.&lt;/p&gt;
&lt;p&gt;Among other things I’m sure I’m overlooking, both boast:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A free version of their software for users (upgradeable to more feature-rich paid versions at any point in time),&lt;/li&gt;
&lt;li&gt;Allowing for multiple workspaces (e.g. development, acceptance, prod, etc.),&lt;/li&gt;
&lt;li&gt;The ability to set environment and static local variables that get updated with each call to an endpoint (sometimes referred to as request chaining),&lt;/li&gt;
&lt;li&gt;Allowing for imports and exports of test data for easy sharing between team members,&lt;/li&gt;
&lt;li&gt;The ability to save calls and organize them into folders or collections,&lt;/li&gt;
&lt;li&gt;GraphQL integration and testing options,&lt;/li&gt;
&lt;li&gt;Multiple ways to configure authorizations (OAuth, bearer tokens, Basic, HAWK, etc.) and generate / manage cookies,&lt;/li&gt;
&lt;li&gt;And both have light and dark color schemes, (I know it’s not a big deal, but it’s worth noting. I really prefer developing in a dark IDE to a stark white one).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s a good bit of stuff (and I’ll tell you, I’ve used the free versions of both Postman and Insomnia for enterprise level application development, and my teams and I have not felt the need to upgrade to a paid version of either, for what it’s worth).&lt;/p&gt;
&lt;p&gt;Ok, now on to some of the unique offerings of both tools.&lt;/p&gt;
&lt;h3&gt;What’s Unique About Postman&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/postman-vs-insomnia/postman.png&quot; alt=&quot;Postman logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Postman appears to have a much more mature set of products and features when you start to really dive into its &lt;strong&gt;&lt;a href=&quot;https://www.getpostman.com/docs/v6/&quot;&gt;documentation&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here’s some of the things that set Postman apart from other API testing tools.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API documentation (Postman will generate and host browser-based API documentation in real-time),&lt;/li&gt;
&lt;li&gt;Collection runs (running a group of requests as a series against a corresponding environment — this is super helpful for automated testing, and I love the name of their collection runner: Newman — get it? Newman was the postman on Seinfeld… I love the sense of humor there),&lt;/li&gt;
&lt;li&gt;Monitoring where Postman will periodically run a collection to check for its performance and response,&lt;/li&gt;
&lt;li&gt;Tests written in plain JavaScript that will verify the response object, time, etc. from the endpoint,&lt;/li&gt;
&lt;li&gt;And mock servers for teams to simulate each endpoint and its corresponding response in a Postman Collection. Developers can view potential responses, without spinning up a back end, and team members can be aligned on expectations during the earliest phases of API development.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pretty impressive, right?&lt;/p&gt;
&lt;h3&gt;What’s Unique About Insomnia&lt;/h3&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/postman-vs-insomnia/insomnia.png&quot; alt=&quot;Insomnia logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Insomnia, in its defense, has some cool things it offers that Postman does not.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&apos;s open source.&lt;/li&gt;
&lt;li&gt;Template tags (similar to environment variables but they perform operations on things like strings, timestamps, etc.),&lt;/li&gt;
&lt;li&gt;The ability to create new plugins for Insomnia and its user community,&lt;/li&gt;
&lt;li&gt;Client certificate assignments to workspaces and SSL validation (or the disabling of it),&lt;/li&gt;
&lt;li&gt;Code snippet generation in 12 different languages (handy if you want to CURL the command from the command line or drop it in to your actual code base),&lt;/li&gt;
&lt;li&gt;A very thorough documentation area where things like instructions, code snippets and even test data can be added to specific calls or collections,&lt;/li&gt;
&lt;li&gt;Viewing response beyond JSON and XML (with Insomnia you can see HTML pages, images, SVGs, audio files and even PDF Documents).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, useful, handy things to have access to when developing APIs.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, I have to say Postman comes out as the current leader in terms of API testing tools, in my mind. It’s more mature and full featured than Insomnia, offering a lot of really excellent benefits to developers, even in its free tier.&lt;/p&gt;
&lt;p&gt;For my teams, who practice fully automated CI/CD testing and deployments, having a test collection runner like Postman offers is a big selling point, and if you’re fully dedicated to supporting an API, having generated, real-time documentation could also be a very nice to have.&lt;/p&gt;
&lt;p&gt;That being said, if Insomnia incorporates a few of the benefits of Postman as it continues to develop and improve, there’s no reason it couldn’t continue to be a very strong competitor in the API testing world.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this proves helpful and gives you a better understanding of a couple of the major options out there for testing.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/API_testing&quot;&gt;API Testing, Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.getpostman.com/&quot;&gt;Postman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://insomnia.rest/&quot;&gt;Insomnia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>postman</category><category>insomnia</category><category>api</category><category>testing</category></item><item><title>Using Docker &amp; Docker Compose to Improve Your Full Stack App Development</title><link>https://www.paigeniedringhaus.com/blog/using-docker-docker-compose-to-improve-your-full-stack-app-development/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/using-docker-docker-compose-to-improve-your-full-stack-app-development/</guid><description>The hardest part of a new project can be getting all the pieces running, but it doesn&apos;t have to be.</description><pubDate>Fri, 17 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-and-docker-compose/developers.jpeg&quot; alt=&quot;Group of developers sitting around laptops&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I don’t know about you, but for me, oftentimes the hardest part of a new project is getting all the necessary pieces up and running. The databases, the backend servers, and of course, the frontend UI — it’s a lot to keep track of, manage dependencies of, monitor the health of, prevent port collisions of, and make sure each of the components can connect to the others to make the app work from start to finish.&lt;/p&gt;
&lt;p&gt;And don’t get me started on if you’re developing with a team of people, and you’re all connected to the same database. Let’s just say, it can be a recipe for a lot of headaches and the oft heard phrase “Did someone blow away the database again? The &amp;lt;insert data of your choice&amp;gt; I was testing with is gone!&quot; It’s not pretty, and it’s definitely not fun when the data gets out of sync or flat out deleted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today, I&apos;ll show you how containerized development with Docker can make everyone&apos;s local development experience better.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The Solution? Containerized Development Environments&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-and-docker-compose/moby-dock.jpeg&quot; alt=&quot;Docker mascot, Moby Dock&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I ❤️ the Docker mascot, Moby Dock. He’s just so darn cute.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I’m going to radically improve how you develop — at least locally, and possibly in your lower life cycles and production environments as well. How? With the help of our trusty &lt;code&gt;docker-compose.yml&lt;/code&gt; file. If you’re not familiar with Docker, I recommend you check out two of my previous blog posts covering the &lt;strong&gt;&lt;a href=&quot;./docker-101-fundamentals-the-dockerfile&quot;&gt;basics of Docker&lt;/a&gt;&lt;/strong&gt; and one of Docker’s most useful features, &lt;strong&gt;&lt;a href=&quot;./docker-102-docker-compose&quot;&gt;Docker Compose&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you are familiar with Docker already, please read on. You know Docker, you’re aware of the containerized nature of it, and you may even have used the power of containers or whole containerized ecosystems courtesy of Docker Compose.&lt;/p&gt;
&lt;p&gt;But have you thought about how it might make your localized application development easier? Think about it: using a &lt;code&gt;docker-compose.yml&lt;/code&gt; to control your dev environment solves the problems I mentioned above.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All the services listed in the &lt;code&gt;docker-compose.yml&lt;/code&gt; can be started up together with just one command,&lt;/li&gt;
&lt;li&gt;There’s no chance of port collisions (at least in the internal Docker environment) even if applications start up on the same port,&lt;/li&gt;
&lt;li&gt;Each of the services is aware of, and able to connect to, the other services with out issue,&lt;/li&gt;
&lt;li&gt;There’s less of a chance of the “It works on my machine” syndrome, since every container is using the exact same image with the exact same dependencies,&lt;/li&gt;
&lt;li&gt;And best of all each individual Docker environment can have its own databases, that no one else can access (and subsequently ruin the data of).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Plus, it’s super simple to do. Intrigued yet?&lt;/p&gt;
&lt;h2&gt;How To Dockerize Applications&lt;/h2&gt;
&lt;p&gt;I’ll be demonstrating the ease of &quot;dockerizing&quot; an application with a full stack JavaScript application. This is a MERN application, except replace the MongoDB with a MySQL database.&lt;/p&gt;
&lt;p&gt;If you want to see my full application, the code is available &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mySqlRegistration&quot;&gt;here in Github&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here’s a high level look at the file structure of this particular application. Since I’m demonstrating with a relatively small user registration app, I’m keeping the server and client in the same repo, but it would be very easy to break them up into multiple separate projects and knit them together with the help of &lt;code&gt;docker-compose.yml&lt;/code&gt;s.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Side note:&lt;/strong&gt; If these were to be two (or more) separate services, I would need to keep a &lt;code&gt;docker-compose.yml&lt;/code&gt; in both repos so each could be spun up for local development.&lt;/p&gt;
&lt;p&gt;The service being developed would build a new image each time &lt;code&gt;docker-compose up&lt;/code&gt; is invoked, and it would have access to the necessary other service’s Docker image stored in Docker Hub (or wherever you choose to store images) with the tag of the version I wanted in the &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For production, there’d also be a third &lt;code&gt;docker-compose-prod.yml&lt;/code&gt; which would only use images that were tested and approved. But that’s outside the scope of this article.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Back to the project file structure.&lt;/p&gt;
&lt;h3&gt;App File Structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;root/
├── api/ 
├── client/ 
├── docker/ 
├── docker-compose.yml 
├── Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Obviously, there’s plenty of files contained within each one of these directories, but for simplicity’s sake I’m just showing the main file structure.&lt;/p&gt;
&lt;p&gt;Even though both the &lt;code&gt;client/&lt;/code&gt; and &lt;code&gt;api/&lt;/code&gt; folder are contained within the same repo, I built them with micro services and modularity in mind. If one piece becomes a bottleneck and needs a second instance, or the app grows too large and needs to be split apart, it’s possible to do so without too much refactoring. To achieve this modularity, both my API and client applications have their own &lt;code&gt;package.json&lt;/code&gt; files with the dependencies each app needs to run.&lt;/p&gt;
&lt;p&gt;The nice thing is, since this is currently one application and both apps are JavaScript, I can have one &lt;code&gt;Dockerfile&lt;/code&gt; that works for both.&lt;/p&gt;
&lt;h3&gt;The Dockerfile&lt;/h3&gt;
&lt;p&gt;Here’s what the &lt;code&gt;Dockerfile&lt;/code&gt; looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// download a base version of node from Docker Hub
FROM node:9

// create the working directory for the application called /app that will be the root
WORKDIR /app

// npm install the dependencies and run the start script from each package.json
CMD ls -ltr &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s all there is to it for this &lt;code&gt;Dockerfile&lt;/code&gt;: just those three commands. The &lt;code&gt;docker-compose.yml&lt;/code&gt; has a little bit more to it, but it’s still easy to follow, when it’s broken down.&lt;/p&gt;
&lt;h3&gt;The Docker-Compose.yml&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3.1&apos;

services:
  client:
    build: .
    volumes:
      - &quot;./client:/app&quot;
    ports:
      - &quot;3031:3000&quot;
    depends_on:
      - api

  api:
    build: .
    volumes:
      - &quot;./api:/app&quot;
    ports:
      - &quot;3003:3000&quot;
    depends_on:
      - db

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASE: users
      MYSQL_USER: test
      MYSQL_PASSWORD: test1234
    ports:
      - &quot;3307:3306&quot;
    volumes:
      - ./docker/data/db:/var/lib/mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;I would like to note there’s a newer version of MySQL available on Docker Hub, but I couldn’t get it to work properly with Docker Compose, so I would recommend going with the mysql:5.7 version until further notice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the code snippet above, you can see my two services: the &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;client&lt;/code&gt; , as well as the database (the first mention I’ve made of it thus far, and one of my favorite things about Docker Compose).&lt;/p&gt;
&lt;p&gt;To explain what’s happening, both the client and API services are using the same &lt;code&gt;Dockerfile&lt;/code&gt;, which is located at the root of the project (earning them both the &lt;code&gt;build: .&lt;/code&gt; build path. Likewise, each folder is mounted inside of the working directory we specified in the Dockerfile with the volumes: &lt;code&gt;./&amp;lt;client or api directory&amp;gt;:/app&lt;/code&gt;. I exposed a port for each service to make debugging of individual services easier, but it’d be perfectly fine to only expose a port to the application through the UI. And finally, the &lt;code&gt;depends_on&lt;/code&gt; makes each piece of the app wait until all the parts have started up.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;client&lt;/code&gt; depends on the &lt;code&gt;api&lt;/code&gt; starting, the &lt;code&gt;api&lt;/code&gt; depends on the &lt;code&gt;database&lt;/code&gt; starting, and once all the credentials are supplied to the database and the image is pulled from &lt;a href=&quot;https://hub.docker.com/_/mysql/&quot;&gt;Docker Hub&lt;/a&gt;, it can start up. I opened a port on the database so I could connect &lt;a href=&quot;https://www.sequelpro.com/&quot;&gt;Sequel Pro&lt;/a&gt; to my database and see the user objects as they’re made and updated, as well. Once again, this makes debugging as I develop the application easier.&lt;/p&gt;
&lt;p&gt;The very last line of the database about &lt;code&gt;volumes&lt;/code&gt;, is a special line that deserves attention. This is how data is persisted for the application. It’s only persisted locally to the machine the Docker ecosystem is running on, but that’s usually all you need for development. This way, if you’re using &lt;a href=&quot;https://flywaydb.org/&quot;&gt;Flyway&lt;/a&gt; or &lt;a href=&quot;https://www.liquibase.org/&quot;&gt;Liquibase&lt;/a&gt; or another SQL runner to create the tables and load data into them and you then change that data, to test the app’s functionality, the changes can be saved so that when you restart the app, the data is the way you left it. It’s really awesome.&lt;/p&gt;
&lt;p&gt;Ok, so the &lt;code&gt;Dockerfile&lt;/code&gt; has been covered, the &lt;code&gt;docker-compose.yml&lt;/code&gt; has been explained, and the database image being pulled from Docker Hub has been noted. We’re about ready to roll.&lt;/p&gt;
&lt;h2&gt;Start the App With One Line&lt;/h2&gt;
&lt;p&gt;Now it’s time to start this application up. If it’s your first time developing this application locally, type docker-compose build in the command line. This will build your two images for the client and API applications — the MySQL database comes as an image straight from Docker Hub, so there’s no need to build that image locally. Here’s what you’ll see in the terminal.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-and-docker-compose/docker-compose-output.png&quot; alt=&quot;Terminal output in the console from Docker Compose&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;You can see the db is skipped and the API and the client are both built using the Dockerfile at the project’s root.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Once the images are done building, type &lt;code&gt;docker-compose up&lt;/code&gt;. You should see a message in the terminal of all the services starting up and then lots of code logging as each piece fires itself up and connects. And you should be good to go. That’s it. Up and running. You’re done. Commence development.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-and-docker-compose/docker-compose-up.png&quot; alt=&quot;Terminal output in the console for Docker Compose up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is what you’ll see right after writing &lt;code&gt;docker-compose up&lt;/code&gt;. Once all the services register done, they’ll try to start and connect and you should be good to start developing.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Whenever you want to stop your app, you can just type &lt;code&gt;docker-compose down&lt;/code&gt; into the terminal, and the services will gracefully shut down. And the data will be persisted locally, so when you type docker-compose up to start the applications back up, your data will still be there.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-and-docker-compose/docker-compose-down.png&quot; alt=&quot;Terminal output in the console for Docker Compose down&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;What you see when you stop the services with &lt;code&gt;docker-compose down&lt;/code&gt;.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Docker and Docker Compose can make web development a heck of a lot easier for you. You can create fully functional, isolated development environments complete with their own databases and data with very little effort on your part, speeding up development time and reducing or avoiding the problems that typically arise as projects are configured and built by teams. If you haven’t considered &quot;dockerizing&quot; your development process yet, I’d highly recommend looking into it.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this proves helpful and makes your own local development easier for everyone on your development team.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/mySqlRegistration&quot;&gt;Github Repo of Dockerized MERN Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/what-docker&quot;&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/compose/overview/&quot;&gt;Docker Compose documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/_/mysql/&quot;&gt;Docker Hub MySQL Library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>docker</category><category>javascript</category><category>sql</category><category>express</category><category>nodejs</category></item><item><title>Sequelize: Like Mongoose but for SQL</title><link>https://www.paigeniedringhaus.com/blog/sequelize-like-mongoose-but-for-sql/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/sequelize-like-mongoose-but-for-sql/</guid><description>The ORM for SQL databases with Node.js</description><pubDate>Sat, 04 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/sequelize-mongoose-for-sql/sequelize.png&quot; alt=&quot;Sequelize logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Everyone who&apos;s ever built a MEAN or MERN stack app is probably familiar with &lt;strong&gt;&lt;a href=&quot;https://mongoosejs.com/&quot;&gt;Mongoose&lt;/a&gt;&lt;/strong&gt;, the helpful object data modeling library that makes working with a MongoDB much, much easier. And since this application stack is so popular, there&apos;s about a thousand tutorials (some much better than others) illustrating how to use MongoDB, Express, React (or Angular) and Node.js together.&lt;/p&gt;
&lt;p&gt;Imagine my surprise though, when I decided to build a simple full stack app using MySQL (or SQLite or PostgreSQL or really any type of SQL database), and found almost nothing that made much sense on how to do so using Express and Node. Really? Nothing recent? Nothing with a deliberate, modularized architecture? No one seemed to have a good way of doing this - nothing short of actual SQL queries written out in the &lt;code&gt;server.js&lt;/code&gt; file to perform create, read, update, and delete (CRUD) operations on the database.&lt;/p&gt;
&lt;p&gt;Then, I found &lt;strong&gt;&lt;a href=&quot;https://sequelize.org/&quot;&gt;Sequelize&lt;/a&gt;&lt;/strong&gt;, and everything changed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I wanted to share what I learned here, in hopes of saving some other people from the masses of outdated tutorials out there, unaware of how much easier Sequelize can make implementing a SQL database into their own Node apps.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;What is Sequelize?&lt;/h2&gt;
&lt;p&gt;Sequelize&apos;s home page best sums up what exactly it is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sequelize is a promise-based ORM for Node.js v4 and up. It supports the dialects PostgreSQL, MySQL, SQLite and MSSQL and features solid transaction support, relations, read replication and more.  -  &lt;em&gt;Sequelize&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is the easiest and most straightforward tool I&apos;ve found for working with databases in SQL inside of a JavaScript application. There are other options that offer similar functionality. &lt;strong&gt;&lt;a href=&quot;https://knexjs.org/&quot;&gt;Knex.js&lt;/a&gt;&lt;/strong&gt; is one that comes to mind, but after comparing their GitHub stats, I chose to move forward with Sequelize.&lt;/p&gt;
&lt;h3&gt;Why Sequelize in particular?&lt;/h3&gt;
&lt;p&gt;Here&apos;s some stats that helped me make my decision:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sequelize has over &lt;strong&gt;8,000 commits&lt;/strong&gt; (Knex has just under 2,000),&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;375 releases&lt;/strong&gt; (Knex has 119),&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;694 contributors&lt;/strong&gt; (Knex has 237),&lt;/li&gt;
&lt;li&gt;It recently released the &lt;strong&gt;beta version 5&lt;/strong&gt; (Knex is on v0.15),&lt;/li&gt;
&lt;li&gt;And it has a &lt;strong&gt;CLI, TypeScript and GraphQL integration&lt;/strong&gt; (Knex does not),&lt;/li&gt;
&lt;li&gt;Plus &lt;strong&gt;883,000 downloads per month&lt;/strong&gt; from NPM (Knex has just under 600,000 per month).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In almost every way (by the numbers), Sequelize is superior to Knex, so I decided to go with what seems to be a very stable, well documented, long maintained and frequently updated library.&lt;/p&gt;
&lt;p&gt;I will say that Knex offers native Oracle and Amazon Redshift support, but since I wasn&apos;t looking to use an Oracle DB, this wasn&apos;t a major selling point for me.&lt;/p&gt;
&lt;h3&gt;Sequelize compared to Mongoose&lt;/h3&gt;
&lt;p&gt;So, when you use Sequelize, you get a lot of the same types of benefits Mongoose offers to MongoDB users plus some bonuses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The ability to connect with very little code changes to multiple &lt;strong&gt;different types of SQL databases&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object models&lt;/strong&gt; (similar to Mongoose schemas) which are typed, mapped to tables and can be required,&lt;/li&gt;
&lt;li&gt;Basic and more advanced &lt;strong&gt;querying options&lt;/strong&gt; like &lt;code&gt;findAll/findOne&lt;/code&gt;, &lt;code&gt;destroy&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, etc. plus things like pagination, nested objects, and associations,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connection pooling&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raw queries&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;And more I don&apos;t have time to cover.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href=&quot;https://sequelize.org/v6/&quot;&gt;documentation&lt;/a&gt;&lt;/strong&gt; is very thorough and shows just how much Sequelize can offer over having to manage it all yourself.&lt;/p&gt;
&lt;p&gt;I&apos;d also like to note that by using Sequelize you can save yourself the trouble of having to rewrite SQL queries to fit the slight variations in database dialects  -  your &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;create&lt;/code&gt; statements need no modifications to work regardless of which type of DB you&apos;re connecting to. I don&apos;t know about you, but I&apos;m a big fan of less effort on my end.&lt;/p&gt;
&lt;p&gt;Sequelize also uses promises via &lt;strong&gt;&lt;a href=&quot;http://bluebirdjs.com/docs/getting-started.html&quot;&gt;Bluebird&lt;/a&gt;&lt;/strong&gt; to control its async control flow. All this means is that when you query the database via Sequelize, it will return a promise like this one.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User.findOne().then(user =&amp;gt; {   
    console.log(user.get(&apos;firstName&apos;)); 
});

// returns user object&apos;s first name, like &apos;John&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also means that Sequelize works well with the ES6 &lt;code&gt;async/await&lt;/code&gt; functionality like so.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user = await User.findOne();  

console.log(user.get(&apos;firstName&apos;));

// also returns user object&apos;s first name, like &apos;John&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;How to implement Sequelize in Express.js&lt;/h2&gt;
&lt;p&gt;Great, so now you can see some of the reasons to use Sequelize, how do you use it in your project?&lt;/p&gt;
&lt;p&gt;This is always my biggest question whenever I see samples or tutorials. How do I use it? And how do I organize my files and my program structure so it&apos;s easy to swap pieces of functionality in and out with minimal modifications on my part?&lt;/p&gt;
&lt;p&gt;Here&apos;s the source file structure I came up with (including just server (API) folders). It&apos;s pretty simple because the project I was trying to do wasn&apos;t particularly complex. But it offers enough organization to make adding CRUD functionality through the routes folder easy and defining one or more database models is as well thanks to the models folder.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root/
├── api/ 
| ├── server.js 
| ├── sequelize.js 
| ├── package.json
| ├── models/ 
| | ├── user.js
| ├── routes/ 
| | ├── deleteUser.js 
| | ├── findUser.js 
| | ├── loginUser.js 
| | ├── registerUser.js
| | ├── updateUser.js
| ├── data/ (optional depending on storage choice - like SQLite) 
| | ├── db/ 
| | | ├── storage.sqlite
| ├── node-modules/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, now that you see the file structure, let me show you what your files will contain. I&apos;ll start with the &lt;strong&gt;&lt;code&gt;user.js&lt;/code&gt;&lt;/strong&gt; file because it gets imported into the &lt;strong&gt;&lt;code&gt;sequlize.js&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;routes &lt;/code&gt;&lt;/strong&gt; files.&lt;/p&gt;
&lt;h3&gt;Define the models&lt;/h3&gt;
&lt;p&gt;Below is the code for a user model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;user.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = (sequelize, type) =&amp;gt; {
  return sequelize.define(&apos;user&apos;, {
    id: {
      type: type.INTEGER,
      primaryKey: true,
      autoIncrement: true
    },
    first_name: type.STRING,
    last_name: type.STRING,
    email: type.STRING,
    username: {
      type: type.STRING,
      allowNull: false
    }, 
    password: {
      type: type: STRING,
      allowNull: false
    }
  })
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since I was building a &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mySqlRegistration&quot;&gt;user registration application&lt;/a&gt;&lt;/strong&gt;, my user model file was very straightforward. Just an ID that&apos;s been set as the primary key and will auto increment, a first name, last name, email, username and password (both of which are required). It&apos;s pretty easy to follow.&lt;/p&gt;
&lt;h3&gt;Set up the database connection(s)&lt;/h3&gt;
&lt;p&gt;Next up is the &lt;strong&gt;&lt;code&gt;sequelize.js&lt;/code&gt;&lt;/strong&gt; file, this is where I kept the majority of my database setup to make it easy to switch out databases if you ever wanted to migrate from say a MySQL DB to a SQLite DB. Here&apos;s what a MySQL connection looked like:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sequelize.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import Sequelize from &apos;sequelize&apos;;
import UserModel from &apos;./modes/user&apos;;

const sequelize = new Sequelize(&apos;dbname&apos;, &apos;admin&apos;, &apos;password&apos;, {
  host: &apos;db&apos;,
  dialect: &apos;mysql&apos;
});

const User = UserModel(sequelize, Sequelize);

sequelize.sync()
  .then(() =&amp;gt; {
    console.log(&apos;Users db and user table have been created&apos;);
  });

module.exports = User;  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, first, I initiate the connection to the MySQL database with the &lt;code&gt;sequelize&lt;/code&gt; variable, giving it a database name, username, password, and then specifying the host and dialect. That&apos;s all there is to it.&lt;/p&gt;
&lt;p&gt;Then I added the &lt;code&gt;user&lt;/code&gt; model defined earlier, and the &lt;code&gt;sequelize.sync()&lt;/code&gt; function syncs all defined models to the database. In this way, it creates the database and tables based on the information you&apos;ve given it and models you&apos;ve passed to it.&lt;/p&gt;
&lt;p&gt;Finally, I export the &lt;code&gt;User&lt;/code&gt; constant that I defined earlier, for use in other parts of the project, like the routes.&lt;/p&gt;
&lt;p&gt;Here&apos;s another example of a SQLite connection so you can see the differences:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sqliteSequelize.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import Sequelize from &apos;sequelize&apos;;
import UserModel from &apos;./modes/user&apos;;

const sequelizeSqlite = new Sequelize(&apos;dbname&apos;, &apos;admin&apos;, &apos;password&apos;, {
  host: &apos;sqlite&apos;,
  dialect: &apos;data/db/storage.sqlite&apos;
});

const UserSqlite = UserModel(sequelizeSqlite, Sequelize);

sequelizeSqlite.sync()
  .then(() =&amp;gt; {
    console.log(&apos;Users db and user table have been created with Sqlite&apos;);
  });

module.exports = UserSqlite;  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A simple connection to a SQLite database with storage persisted within the project itself.&lt;/p&gt;
&lt;p&gt;Besides the slight changes to the database set up, everything else in the file, stays the same.&lt;/p&gt;
&lt;h3&gt;Define the routes&lt;/h3&gt;
&lt;p&gt;Ok, I&apos;m almost done with setting this up.&lt;/p&gt;
&lt;p&gt;To keep the code modular (and make it easier for me to add or subtract functionality from the application), I added each piece of the CRUD functionality to the database as a separate file. You could add them all in the same file and keep it divided up by model, or whatever is easiest for you to keep things organized.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example of my user registration route (the create functionality). I added in password hashing through the use of &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/bcrypt&quot;&gt;&lt;code&gt;bcrypt&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, but that&apos;s not important right now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;registerUser.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import User from &apos;../sequelize&apos;;
import bcrypt from &apos;bcrypt&apos;;

const BCRYPT_SALT_ROUNDS = 12;

module.exports = (app) =&amp;gt; {
  app.post(&apos;/registerUser&apos;, (req, res) =&amp;gt; {
    const data = {
      fist_name: req.body.first_name,
      last_name: req.body.last_name,
      email: req.body.email,
      username: req.body.username,
      password: req.body.password
    };

    if(data.password === &apos;&apos; || data.username === &apos;&apos;){
      res.json(&apos;username and password required&apos;);
    }
    User.findOne({
      where: {
        username: data.username
      }
    })
    .then(user =&amp;gt; {
      if (user !== null) {
        console.log(&apos;username already taken&apos;);
        res.json(&apos;username already taken&apos;);
      } else {
        bcrypt.hash(data.password, BCRYPT_SALT_ROUNDS)
        .then((hashedPassword) =&amp;gt; {
          User.create({
            first_name: data.first_name,
            last_name: data.last_name,
            email: data.email,
            username: data.username,
            password: hashedPassword
          })
        })
        .then(() =&amp;gt; {
          console.log(&apos;user created&apos;);
          res.json(&apos;user created&apos;);
        })
      }
    })
    .catch(err =&amp;gt; {
      console.log(&apos;problem communicating with db&apos;);
      res.status(500).json(err);
    })
  })
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see from the code above, the User model is imported from the &lt;code&gt;sequelize.js&lt;/code&gt; file, the user input data is passed from the client side of the app through the &lt;code&gt;req.body.xyz&lt;/code&gt; fields, and then I do a number of checks to the database with the help of Sequelize before adding a new user.&lt;/p&gt;
&lt;p&gt;The first check is when I check to make sure the user supplied both a username and password (as required by the model), if they&apos;re not both there, the server sends back the error message &lt;code&gt;&apos;username and password required&apos;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After that check, I query the database to see if that username is already taken, if it is, once again the server sends &lt;code&gt;&apos;username is already taken&apos;&lt;/code&gt; back to the client.&lt;/p&gt;
&lt;p&gt;If it passes that check, the password is hashed and the user info is saved to the database. Once it&apos;s successfully saved it sends back a success message to the client &lt;code&gt;&apos;user created&apos;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And the whole creation operation is wrapped so in case there&apos;s a problem communicating with the server (it&apos;s down, there&apos;s network issues, etc.), it can still send a message to the client letting it know there was a problem.&lt;/p&gt;
&lt;h3&gt;Add the routes to the server&lt;/h3&gt;
&lt;p&gt;Now I&apos;m ready to add these routes to the server. This is easiest part of all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import express from &apos;express&apos;;
import Cors from &apos;cors&apos;;
import bodyParser from &apos;body-parser&apos;;
import logger from &apos;morgan&apos;;

const app = express();

app.use(Cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(logger(&apos;dev&apos;));

require(&apos;./routes/loginUser&apos;)(app);
require(&apos;./routes/registerUser&apos;)(app);
require(&apos;./routes/findUsers&apos;)(app);
require(&apos;./routes/deleteUser&apos;)(app);
require(&apos;./routes/updateUser&apos;)(app);

app.listen(API_PORT, () =&amp;gt; console.log(`Listening on port ${API_PORT}`));

module.exports = app;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All you have to do to make this work, is require the routes in your &lt;code&gt;server.js&lt;/code&gt; file like I did, and have them take in your Express application, and you&apos;re set. It doesn&apos;t get much simpler than that.&lt;/p&gt;
&lt;p&gt;Now, you should be able to use Sequelize to your heart&apos;s content with any kind of SQL database in your Node.js, Express project.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to see a full MERN stack example using Sequelize, you can see my repo &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/mySqlRegistration&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;. From the master branch you can run &lt;strong&gt;&lt;code&gt;docker-compose build&lt;/code&gt;&lt;/strong&gt;, followed by &lt;strong&gt;&lt;code&gt;docker-compose up&lt;/code&gt;&lt;/strong&gt;, and from the &lt;code&gt;sqlite&lt;/code&gt; feature branch you can start both the client and server files individually with &lt;strong&gt;&lt;code&gt;npm start&lt;/code&gt;&lt;/strong&gt; from the &lt;code&gt;api/&lt;/code&gt; and &lt;code&gt;client/&lt;/code&gt; folders.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Sequelize brings order and flexibility to using SQL databases in JavaScript applications. It reduces the need to write raw queries, manage connections, guard against harmful SQL attacks, and more. And with some fairly basic setup, you too, can use Sequelize in your own JS projects - and hopefully speed up your development time. I will definitely continue to use this tool going forward.&lt;/p&gt;
&lt;p&gt;Check back in a few weeks — I’ll be writing more about JavaScript, React, IoT, or something else related to web development.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this proves helpful in your future database-driven projects.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://mongoosejs.com/&quot;&gt;MongooseJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.sequelizejs.com/&quot;&gt;Sequelize&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://knexjs.org/&quot;&gt;Knex.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/bcrypt&quot;&gt;bcrypt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub repo of &lt;a href=&quot;https://github.com/paigen11/mySqlRegistration&quot;&gt;MERN app using Sequelize&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>nodejs</category><category>javascript</category><category>sql</category><category>sequelize</category><category>express</category></item><item><title>Jib: Getting Expert Docker Results Without Any Knowledge of Docker</title><link>https://www.paigeniedringhaus.com/blog/jib-getting-expert-docker-results-without-any-knowledge-of-docker/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/jib-getting-expert-docker-results-without-any-knowledge-of-docker/</guid><description>All of the containerization benefits, none of the complexity.</description><pubDate>Wed, 18 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/jib-docker/google-jib.png&quot; alt=&quot;Google Jib logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Well have I got some news for you. If you’ve been following my latest blog posts, I’ve been talking a good deal about &lt;a href=&quot;https://www.docker.com/what-docker&quot;&gt;Docker&lt;/a&gt;, the amazing containerization platform making it easier than ever to develop and deploy web applications. The &lt;strong&gt;&lt;a href=&quot;./docker-101-fundamentals-the-dockerfile&quot;&gt;first post&lt;/a&gt;&lt;/strong&gt; covered the Docker basics and the Docker CLI. The &lt;strong&gt;&lt;a href=&quot;./docker-102-docker-compose&quot;&gt;second&lt;/a&gt;&lt;/strong&gt; , introduced Docker Compose, Docker’s more sophisticated, easier (in my opinion) to use, multi-service option.&lt;/p&gt;
&lt;p&gt;Docker is a very powerful tool when used correctly, but it takes a minute to get your head around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The commands,&lt;/li&gt;
&lt;li&gt;The file structure,&lt;/li&gt;
&lt;li&gt;The whole containerization concept, itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s not easy if you’ve not used it before, there’s a definite learning curve. But Google, ever the leader in technology, has just released a game changer…&lt;/p&gt;
&lt;h2&gt;Meet Jib&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/GoogleContainerTools/jib&quot;&gt;Jib&lt;/a&gt;&lt;/strong&gt;, is a brand new, just released, Google Container Tools-based, Java plugin that will containerize your application.&lt;/p&gt;
&lt;p&gt;Put simply:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Jib builds Docker and &lt;strong&gt;&lt;a href=&quot;https://github.com/opencontainers/image-spec&quot;&gt;OCI&lt;/a&gt;&lt;/strong&gt; images for your Java applications and is available as plugins for &lt;strong&gt;&lt;a href=&quot;https://github.com/GoogleContainerTools/jib/blob/master/jib-maven-plugin&quot;&gt;Maven&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://github.com/GoogleContainerTools/jib/blob/master/jib-gradle-plugin&quot;&gt;Gradle&lt;/a&gt;&lt;/strong&gt;. — Jib, Github&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What this means for us is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;Dockerfile&lt;/code&gt; setup,&lt;/li&gt;
&lt;li&gt;No customized scripting for Maven or Gradle,&lt;/li&gt;
&lt;li&gt;Out of the box Docker image generation and publication.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically, no Docker complexity, but all of the Docker benefits.&lt;/p&gt;
&lt;p&gt;How? A plugin, a very simple plugin in your project. I’ll show you just how simple below.&lt;/p&gt;
&lt;h2&gt;Implementing Jib in Gradle&lt;/h2&gt;
&lt;p&gt;There are both Maven and Gradle plugins for Jib. I’ll be using Gradle because that’s what I’m most familiar with.&lt;/p&gt;
&lt;p&gt;We begin with the build.gradle file. First and foremost, make sure you’re working with Gradle 4.6 or later — this is required for Jib.&lt;/p&gt;
&lt;p&gt;Next, the changes to the file. Inside of the &lt;code&gt;build.gradle&lt;/code&gt;, in your plugins section, add this line.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;plugins {
  id &apos;com.google.cloud.tools.jib&apos; version &apos;0.9.6&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, it really is that easy to generate a Docker image now.&lt;/p&gt;
&lt;p&gt;And that’s it. You’re done with the changes needed in your Java application.&lt;/p&gt;
&lt;p&gt;Now, from the command line run the Gradle task &lt;code&gt;./gradlew jibDockerBuild&lt;/code&gt;. This will generate your local Docker image and give you its image name and version.&lt;/p&gt;
&lt;p&gt;Ok, final step, the Docker run command in the terminal: &lt;code&gt;docker run -p &amp;lt;host port: Docker app port&amp;gt; &amp;lt;image name: version&amp;gt;&lt;/code&gt;. And with this your application should start up.&lt;/p&gt;
&lt;p&gt;I made a sample Java application and stored it in Github &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/jib-docker-example&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;, so you can see just how simple this really is.&lt;/p&gt;
&lt;p&gt;I also left the Dockerfile in there, so you can see what used to be necessary to run Docker. Keep in mind, this project is only set up for building and running local images, if you want to push to Docker hub, see the Jib official documentation (and check back, I may do a follow up post on it).&lt;/p&gt;
&lt;p&gt;For my project, you’d run the same &lt;code&gt;./gradlew jibDockerBuild&lt;/code&gt;, then this Docker run command: &lt;code&gt;docker run -p 8080:8080 java-example:1.0.0-SNAPSHOT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/jib-docker/google-jib-1.png&quot; alt=&quot;Sample Dockerized Java app started courtesy of Jib&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is what you’ll see when you go to http://localhost:8080 in your browser.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Before Jib, I needed an entirely separate Dockerfile instructing how to build my application to make magic like this happen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM openjdk:8-jdk-alpine

# create the directory for where Tomcat creates its working directories
VOLUME /tmp

# copy the project JAR file to the container renamed as &apos;app.jar&apos;
COPY build/libs /app

# execute that JAR in the entry point below
# java -Djava.security.egd=file:/dev/./urandom -jar /app/java-example.jar
ENTRYPOINT [&quot;java&quot;, &quot;-Djava.security.egd=file:/dev/./urandom&quot;, &quot;-jar&quot;, &quot;/app/java-example.jar&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look at this. And this is a simple, simple Java application. These Dockerfiles can (and usually are) much bigger and more complex.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks to Jib, &lt;code&gt;Dockerfiles&lt;/code&gt; can be a thing of the past — at least, for your Java applications. Another bonus is that if you have a &lt;code&gt;docker-compose.yml&lt;/code&gt; file in your project, that can still be used in tandem with Jib.&lt;/p&gt;
&lt;p&gt;Personally, I can’t wait to start dropping this one-liner into all of my team’s Spring Boot applications. With it, we can get the power and flexibility of a Docker container with none of the setup and necessary knowledge about Docker.&lt;/p&gt;
&lt;p&gt;Even if you’re not a Docker expert, with Jib you can still reap the benefits, and look like a rockstar in the process. Enjoy!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/what-docker&quot;&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleContainerTools/jib&quot;&gt;Jib, Github repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin&quot;&gt;Jib, Gradle Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Jib Docker &lt;a href=&quot;https://github.com/paigen11/jib-docker-example&quot;&gt;Example Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>docker</category><category>java</category><category>jib</category><category>devops</category></item><item><title>Docker 102: Docker-Compose</title><link>https://www.paigeniedringhaus.com/blog/docker-102-docker-compose/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/docker-102-docker-compose/</guid><description>The recipe card for getting all your Dockerized apps to work together seamlessly.</description><pubDate>Sat, 07 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-2.png&quot; alt=&quot;Docker mascot Moby Dock holding Docker containers&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If you’re not familiar with Docker, the containerization platform, you may want to read my &lt;strong&gt;&lt;a href=&quot;./docker-101-fundamentals-the-dockerfile&quot;&gt;first blog&lt;/a&gt;&lt;/strong&gt;, to get an overview of what it is and what happens under the hood before embarking on the quest to understand Docker-Compose.&lt;/p&gt;
&lt;p&gt;If you do know about Docker, read on, and I’ll attempt to show you the power and benefits a single &lt;code&gt;docker-compose.yml&lt;/code&gt; can offer over the original &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Which segues nicely to the first point I’ll cover: why use Docker Compose instead of the Docker CLI commands?&lt;/p&gt;
&lt;h2&gt;Why Docker Compose?&lt;/h2&gt;
&lt;p&gt;Docker Compose offers a number of benefits over the Docker CLI in all stages of development. Here, I’ll give you some details of where it can best be utilized in each stage.&lt;/p&gt;
&lt;h3&gt;Lower Life Cycles&lt;/h3&gt;
&lt;p&gt;For lower life cycle environments, Docker Compose is able to quickly, easily simulate production environments.&lt;/p&gt;
&lt;p&gt;It can spin up all the microservices (and databases) that make an application run, and it can seamlessly connect them to each other inside of their isolated Docker environment with very little effort on the developers’ part. There’s no need to even specify different ports internally to avoid collisions — it’s extremely easy to get the whole system running in one fell swoop.&lt;/p&gt;
&lt;p&gt;And then there’s testing. Docker excels at many types of application testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Destructive testing&lt;/li&gt;
&lt;li&gt;Performance testing&lt;/li&gt;
&lt;li&gt;Integration testing&lt;/li&gt;
&lt;li&gt;End-to-end testing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Docker performs so well for testing because it creates its own isolated environment, spins up its own databases, sets up the data if directed to do so, and when it’s done running tests and manipulating the data, it can shut down and start back up again with the original data in the same pristine condition as before. How handy is that as your multiple devs are working on different features and submitting PRs only after there’s been a clean run of end to end tests?&lt;/p&gt;
&lt;h3&gt;Production&lt;/h3&gt;
&lt;p&gt;If you’re lucky enough to be able to use Docker containers in production, then a single &lt;code&gt;docker-compose.yml&lt;/code&gt; file can deploy a complete system that runs exactly as it was tested in lower life cycle environments. This can happen because exactly the same steps done in development can be done in production with Docker Compose, it’s awesome and helps eliminate some of the trepidation deployments always cause that something might go wrong.&lt;/p&gt;
&lt;h3&gt;Docker Swarm Testing&lt;/h3&gt;
&lt;p&gt;Docker Compose makes Docker Swarm testing before deployment easier. Docker Swarm is beyond the scope of this post, so just know this is the way to test the swarm.&lt;/p&gt;
&lt;p&gt;Finally, in my humble opinion, a &lt;code&gt;docker-compose.yml&lt;/code&gt; file is easier to read, understand and implement than the Docker CLI. This is purely my opinion, though.&lt;/p&gt;
&lt;p&gt;So now that I’ve given you a reason for wanting to use Docker Compose, the next question is: what does a &lt;code&gt;docker-compose.yml&lt;/code&gt; look like? And how do I write one? Read on.&lt;/p&gt;
&lt;h2&gt;What is Docker Compose?&lt;/h2&gt;
&lt;p&gt;Essentially, what Docker Compose is, is a recipe card — it’s a recipe of services that make up an application and the &lt;code&gt;docker-compose.yml&lt;/code&gt; dictates how the services are mixed together.&lt;/p&gt;
&lt;p&gt;In more technical terms:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Docker-Compose defines a complete system where services can communicate with each other on an isolated network, interacting with external resources as defined by the user.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Docker Compose is built on top of the Docker Engine, the very same engine that runs the Dockerfiles and Docker CLI, but the most important aspect to keep in mind about Compose is to think of it like a recipe.&lt;/p&gt;
&lt;p&gt;The image below illustrates it pretty well.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-compose-environment.png&quot; alt=&quot;Docker-compose environment&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This is what a Docker Compose environment looks like when running. &lt;strong&gt;Application A&lt;/strong&gt; is a backend microservice that can freely communicate with App B and App C but that is all, it cannot communicate with the host in the outside world at all. This is because of how its &lt;code&gt;docker-compose.yml&lt;/code&gt; is set up, I’ll show that next.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Application B&lt;/strong&gt; is a database, it has been structured in the &lt;code&gt;docker-compose.yml&lt;/code&gt; with an externally mounted volume &lt;code&gt;volumes: — opt/app:/opt/appB/app&lt;/code&gt; that allows it to write a persistent data layer to the outside world. With this data layer in the application, even if the entire Docker environment is destroyed for some reason, when it’s brought back up, the database will see the data written to it before, and replace it so you can begin where you were before.&lt;/p&gt;
&lt;p&gt;Finally, &lt;strong&gt;Application C&lt;/strong&gt; is the user interface portion of the app. Also, due to the &lt;code&gt;docker-compose.yml&lt;/code&gt;, this application can talk to the host machine on a port that’s been exposed: &lt;code&gt;ports=&quot;8080:8080&quot;&lt;/code&gt;. This means, a user can open up http://localhost:8080 on their machine and access the running application.&lt;/p&gt;
&lt;p&gt;It&apos;s is a pretty simple representation of the environment, but it can be that simple, or it can be much more complex depending on your needs. Now, let’s look at what a Docker Compose YAML file looks like and go through some of the nuances that can come with it.&lt;/p&gt;
&lt;h2&gt;How to Docker Compose?&lt;/h2&gt;
&lt;p&gt;The last big question is: how to write a &lt;code&gt;docker-compose.yml&lt;/code&gt;, and it’s actually very easy and follows a standard formula.&lt;/p&gt;
&lt;p&gt;Here is a template of what any &lt;code&gt;docker-compose.yml&lt;/code&gt; will look like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample Docker Compose Template&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &quot;2&quot;

  services:
    &amp;lt;name_of_service&amp;gt;:
      build: &amp;lt;path_to_dockerfile&amp;gt;
      # OR
      image: &amp;lt;name_of_image&amp;gt;
      environment: 
        - &quot;java_home:/user/bin/default&quot;
        - &quot;app_dir:/opt/app&quot;
      ports:
        - &quot;80:80&quot;
        - &quot;8000:8000&quot;
        - &quot;443:443&quot;
      volumes:
        - ./:/opt/app  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every docker-compose file will start with a minimum of &lt;code&gt;version: &quot;2&quot;&lt;/code&gt;, if you’re doing a Docker Swarm file it will need  &lt;code&gt;version: &quot;3&quot;&lt;/code&gt;, but for a single &lt;code&gt;docker-compose.yml&lt;/code&gt;, you’ll need v2.&lt;/p&gt;
&lt;p&gt;Next, you will list all your services (each app running in the &lt;code&gt;docker-compose&lt;/code&gt; will have its own name, and you’ll need to provide &lt;em&gt;&lt;strong&gt;either&lt;/strong&gt;&lt;/em&gt; a &lt;code&gt;build&lt;/code&gt; or an &lt;code&gt;image&lt;/code&gt; from the Docker registry. You &lt;em&gt;&lt;strong&gt;cannot&lt;/strong&gt;&lt;/em&gt; have both.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A custom Docker image will be built based on the Dockerfile provided by the build path OR&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/&quot;&gt;Docker Hub&lt;/a&gt; will supply all the necessary commands and setup to make the image build and run successfully.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Underneath that, environment variables are set, ports are exposed, and external volumes are mounted. All these same things could be done with the Docker CLI, but this is a cleaner, easier to read file that doesn’t require remembering (and correctly typing) them all when executing commands in the terminal.&lt;/p&gt;
&lt;p&gt;Here is what a sample &lt;code&gt;docker-compose.yml&lt;/code&gt; could look like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample Docker Compose Yaml&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &quot;2&quot;

  services:
    appA:
      build: ./Dockerfile
      ports:
        - &quot;80:80&quot;
    appB:
      image: mongodb
      volumes:
        - ./data:&amp;lt;wherever&amp;gt;
    appC:
      build: ./Dockerfile
      instances: 2
      environment:
        - config: backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;code&gt;docker-compose.yml&lt;/code&gt; begins with &lt;code&gt;version: &quot;2&quot;&lt;/code&gt; (as required for Docker Compose), and then we have three services listed below: &lt;code&gt;appA&lt;/code&gt;, &lt;code&gt;appB&lt;/code&gt;, &lt;code&gt;appC&lt;/code&gt;. Since &lt;code&gt;appA&lt;/code&gt; is the UI that is built from a custom &lt;code&gt;Dockerfile&lt;/code&gt; and needs to be exposed to the host machine, it has a &lt;code&gt;build:&lt;/code&gt; path to said &lt;code&gt;Dockerfile&lt;/code&gt; and a &lt;code&gt;ports:&lt;/code&gt; that maps the internally running port of the UI, port 80 to the same port on the host machine, also 80.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;appB&lt;/code&gt; is a Mongo database, so it can be pulled down from the Docker registry when it’s time to start up the application. There’s no build to be done ahead of time, nothing but declaring the image, and for data persistence adding a &lt;code&gt;volumes:&lt;/code&gt; specification of where database data can be persisted to the host machine and it’s good to go.&lt;/p&gt;
&lt;p&gt;And &lt;code&gt;appC&lt;/code&gt; is also a custom Docker image, so it has a build: path to its own Dockerfile, an &lt;code&gt;environment:&lt;/code&gt; variable specifying a configuration file for the backend, and not one but two &lt;code&gt;instances:&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This application in particular can have two instances because it is not being exposed in any way to the host machine. If a port was being opened (or it was some type of database), it would only be able to have one instance to avoid port collisions on the host or to avoid writing to two separate databases within the Docker environment.&lt;/p&gt;
&lt;p&gt;But since this is purely a backend service, it can have as many instances as necessary (good for load balancing heavy volumes of traffic), and all of them can run as separate containers within the Docker environment and communicate with each other as needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I recommend reading the &lt;a href=&quot;https://docs.docker.com/compose/overview/&quot;&gt;Docker Compose documentation&lt;/a&gt; for more examples and descriptions of all the things you can do with within a &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ok, the &lt;code&gt;docker-compose.yml&lt;/code&gt; has been written, let’s look at the Docker Compose commands needed to get this system up and running. Don’t worry, they’re not very complicated.&lt;/p&gt;
&lt;h2&gt;Docker Compose Commands&lt;/h2&gt;
&lt;p&gt;Before I go any further, I must issue the following disclaimer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER: For the purposes of this blog post, it will be assumed all docker-compose commands will be executed in the same directory as the &lt;code&gt;docker-compose.yml&lt;/code&gt;. Yes, it is possible to execute the commands from different levels of the directory, but that is outside of the scope of this blog.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that that’s been made clear, we can continue. There’s just a handful of Docker commands you’ll need to type in to the terminal to get these magical files to do their thing. And after I’ve described them, I’ve provided another handy graphic that illustrates the three different phases a Docker Compose environment can exist in.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose ps&lt;/code&gt; — lists all the services in a network. This is especially helpful when troubleshooting a service as it will give you the container ID and you can then run &lt;code&gt;docker -it exec &amp;lt;ID&amp;gt; bash&lt;/code&gt; to enter the container and debug as needed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose build&lt;/code&gt; — generates any needed images from custom Dockerfiles. It will not pull images from the Docker hub, only generate custom images.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose up&lt;/code&gt; — brings up the network for the services to run in&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose stop&lt;/code&gt; — stops the network and saves the state of all the services&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose start&lt;/code&gt; — restarts the services and brings them back up with the state they had when they were stopped&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose down&lt;/code&gt; — burns the entire Docker network with fire. The network and all the services contained within are totally destroyed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-compose-environment-2.png&quot; alt=&quot;Docker-compose environment and states&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Here’s the various states the Docker Compose environment exists in, depending on what commands you’ve run.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker-compose build&lt;/code&gt; and &lt;code&gt;docker-compose down&lt;/code&gt; mean the Docker environment &lt;em&gt;&lt;strong&gt;is not&lt;/strong&gt;&lt;/em&gt; running, and the network &lt;em&gt;&lt;strong&gt;does not&lt;/strong&gt;&lt;/em&gt; exist.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker-compose up&lt;/code&gt; and &lt;code&gt;docker-compose start&lt;/code&gt; means the Docker environment &lt;em&gt;&lt;strong&gt;is&lt;/strong&gt;&lt;/em&gt; running, and the network &lt;em&gt;&lt;strong&gt;does&lt;/strong&gt;&lt;/em&gt; exist.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker-compose stop&lt;/code&gt; means the Docker environment &lt;em&gt;&lt;strong&gt;is not&lt;/strong&gt;&lt;/em&gt; running, but the network still &lt;em&gt;&lt;strong&gt;does&lt;/strong&gt;&lt;/em&gt; exist.&lt;/p&gt;
&lt;p&gt;That’s it. All the commands you’ll need with your &lt;code&gt;docker-compose.yml&lt;/code&gt; to build and run all your connected microservices.&lt;/p&gt;
&lt;h2&gt;Docker Compose Examples&lt;/h2&gt;
&lt;p&gt;If you’d like to see some examples of how Docker Compose can be structured, you can download a repo I put together &lt;strong&gt;&lt;a href=&quot;https://github.com/paigen11/docker-compose-example&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Each sample has a &lt;code&gt;README.md&lt;/code&gt; that illustrates how to run it, and it illustrates the flexibility afforded with Docker Compose.&lt;/p&gt;
&lt;h3&gt;Example 1: Node.js and Java - Dockerfiles&lt;/h3&gt;
&lt;p&gt;The first example features one Node.js and one Spring Boot Java application, both of which have Dockerfiles but no &lt;code&gt;docker-compose.yml&lt;/code&gt;, and it has basic Docker CLI commands to run them on ports 3003 and 3004, respectively.&lt;/p&gt;
&lt;p&gt;This is to show that the very same instructions the &lt;code&gt;docker-compose.yml&lt;/code&gt; contains can be done from the command line, but it takes more effort on the user’s part to get them running. Also, neither service is aware of the other one, the way they would when connected by a &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-nodejs-1.png&quot; alt=&quot;Dockerfile run Node.js application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Node.js Docker example: running on port 3003&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-java-1.png&quot; alt=&quot;Dockerfile run Java application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Java Spring Boot Docker example: running on port 3004 and displaying its hostname
&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Example 2: Node.js and Java - Docker Compose&lt;/h3&gt;
&lt;p&gt;The second example deploys the same two applications, but uses a single &lt;code&gt;docker-compose.yml&lt;/code&gt; file to do so. This time, the Java app runs on 3001 and the Node app runs on 3002.&lt;/p&gt;
&lt;p&gt;If you wanted to, you could have example 1 and example 2 all running at the same time since none of them share host port numbers.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-nodejs-2.png&quot; alt=&quot;Docker-compose run Node.js application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Node.js docker-compose example: running on port 3002.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-java-2.png&quot; alt=&quot;Docker-compose run Java application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Java Spring Boot docker-compose example: running on port 3001 and displaying a different hostname.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Example 3: Node.js and Java - Nginx&lt;/h3&gt;
&lt;p&gt;Example 3 takes things up a notch by using a simple &lt;a href=&quot;https://www.nginx.com/&quot;&gt;Nginx&lt;/a&gt; frontend to route requests through to either the Java or the Node service running in its network.&lt;/p&gt;
&lt;p&gt;Nginx is outside the scope of this blog, but for our purposes it’s working as a proxy and depending on what route is passed to it, it will either serve up one app or the other.&lt;/p&gt;
&lt;p&gt;This means there’s only one port exposed to the outside world (80 is the default port for Nginx, so that’s what I’m using), but both applications inside the Docker environment can be accessed, no ports for those services necessary. See the screenshots below to help clarify it a bit.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-nodejs-3.png&quot; alt=&quot;Nginx-run Node.js application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Look closely at the URL, it’s just http://localhost/node/, and it routes to the Node.js example.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-java-3.png&quot; alt=&quot;Nginx-run Java application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Likewise, the same port with the /java/ route, routes to the Java example.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Example 4: Node.js and Java - Dockerfiles and Docker Compose&lt;/h3&gt;
&lt;p&gt;This is my favorite example by far, because it really helps illustrate the power of Docker Compose.&lt;/p&gt;
&lt;p&gt;At the root level of the example directory, this particular &lt;code&gt;docker-compose.yml&lt;/code&gt; accesses all the Java and Node.js examples at one time, builds their images from their individual &lt;code&gt;Dockerfiles&lt;/code&gt; and spins all six of them up plus two more applications bearing image tags of &lt;code&gt;latest&lt;/code&gt;. All of these containers are accessed through a single Nginx proxy as well.&lt;/p&gt;
&lt;p&gt;It’s really, really cool and an example of how you could use versioning for &lt;a href=&quot;https://docs.cloudfoundry.org/devguide/deploy-apps/blue-green.html&quot;&gt;blue-green production deployments&lt;/a&gt;, &lt;a href=&quot;https://octopus.com/docs/deployment-patterns/canary-deployments&quot;&gt;canary deployments&lt;/a&gt;, or even as a way to support multiple versions of the same application if different outside teams are dependent on a certain version for functionality.&lt;/p&gt;
&lt;p&gt;Here’s just a couple examples of the versioned routes — pay attention to the URLs.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-nodejs-4-1.png&quot; alt=&quot;Dockerfile and docker-compose run Node.js application, example 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example 3 of the app, served up on the v3 route.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-nodejs-4-2.png&quot; alt=&quot;Dockerfile and docker-compose run Node.js application, example 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example 1 on the v1 route.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-102/docker-nodejs-4-3.png&quot; alt=&quot;Dockerfile and docker-compose run Node.js application, example 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;And example 1 again, but this time on the latest route tag. Nice.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;And that is Docker Compose in brief. Imagine writing a &quot;recipe&quot; of all the services that make up a single application, databases included, and Docker handles the rest.&lt;/p&gt;
&lt;p&gt;Ports won&apos;t collide, container services can talk to one another, and it&apos;s all written down in an easy-to-read file that can be deployed in upper and lower lifecycles. It&apos;s really powerful.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope you’ll have the chance to use Docker Compose in your own development like I do.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/what-docker&quot;&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/compose/overview/&quot;&gt;Docker Compose Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/&quot;&gt;Docker Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/docker-compose-example&quot;&gt;Docker Compose Examples Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nginx.com/&quot;&gt;Nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.cloudfoundry.org/devguide/deploy-apps/blue-green.html&quot;&gt;Blue Green Deployments, Cloud Foundry Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://octopus.com/docs/deployment-patterns/canary-deployments&quot;&gt;Canary Deployments, Octopus Deploy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>docker</category><category>devops</category></item><item><title>Docker 101: Fundamentals &amp; the Dockerfile</title><link>https://www.paigeniedringhaus.com/blog/docker-101-fundamentals-the-dockerfile/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/docker-101-fundamentals-the-dockerfile/</guid><description>Containerize all project dependencies in one place for easy deployments anywhere.</description><pubDate>Sat, 23 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-101/docker-1.jpeg&quot; alt=&quot;Docker mascot Moby Dock&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;You, like me, may have heard of Docker before. You may have co-workers or developer friends who rave about it, who “dockerize” everything they can, and who are at an utter loss for words when it comes to explaining Docker, and all its glory, in terms that are understandable to the average person. Today, I will attempt to demystify Docker for you.&lt;/p&gt;
&lt;p&gt;This will actually be a two-part series on Docker, because Docker needs, at least, two separate posts for its two best known products:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker (and the Dockerfile),&lt;/li&gt;
&lt;li&gt;Docker Compose&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So let’s begin at the beginning and I’ll explain what Docker actually is, in terms even I understand.&lt;/p&gt;
&lt;h2&gt;What is Docker?&lt;/h2&gt;
&lt;p&gt;The Docker website itself simply describes Docker as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“the world’s leading software containerization platform” — &lt;a href=&quot;https://www.docker.com/what-docker&quot;&gt;Docker, Docker Overview&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That really clears it up, right? Umm…yeah, not really. A much better description of Docker is found on OpenSource.com.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/docker/docker&quot;&gt;Docker&lt;/a&gt; is a tool designed to make it easier to create, deploy, and run applications by using containers. Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other dependencies, and ship it all out as one package. — &lt;a href=&quot;https://opensource.com/resources/what-docker&quot;&gt;OpenSource.com, What is Docker?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;What Docker really does is separate the application code from infrastructure requirements and needs.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It does this by running each application in an isolated environment called a ‘&lt;strong&gt;container.&lt;/strong&gt;’&lt;/p&gt;
&lt;p&gt;This means developers can concentrate on the actual code to run in the Docker container without worrying about the system it will ultimately run on, and devops can focus on ensuring the right programs are installed in the Docker container, and reduce the number of systems needed and complexity of maintaining said systems after deployment.&lt;/p&gt;
&lt;p&gt;Which is a perfect segue to the next point: why Docker?&lt;/p&gt;
&lt;h2&gt;Why Docker?&lt;/h2&gt;
&lt;p&gt;I can’t tell you how many times I’ve heard a developer (myself included) say, “It works on my machine, I don’t know why it won’t work on yours.” — any developer, ever&lt;/p&gt;
&lt;p&gt;This is what Docker is designed to prevent — the inevitable confusion that comes when a dev’s been working on their local machine on a project for days (or weeks), and as soon as it’s deployed to a new lifecycle, the app won’t run. Most likely because there’s a host of installed dependencies that are necessary to run the application but they aren’t saved in the &lt;code&gt;package.json&lt;/code&gt; or the &lt;code&gt;build.gradle&lt;/code&gt; or specified in the &lt;code&gt;manifest.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every single Docker container begins as a pure vanilla Linux machine that knows nothing.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-101/jon-snow.png&quot; alt=&quot;Jon Snow is like an empty Docker container - they both know nothing&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The Docker container’s just like Jon Snow when it spins up: it knows nothing.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Then, we tell the container everything it needs to know — all the dependencies it needs to download and install in order to run the application. This process is done with a &lt;code&gt;Dockerfile&lt;/code&gt;, but I’m getting ahead of myself.&lt;/p&gt;
&lt;p&gt;For this section, suffice it to say, Docker takes away the guesswork (and hours spent debugging) from deploying applications because it always starts as a fresh, isolated machine and the very same dependencies get added to it. Every. Single. Time.&lt;/p&gt;
&lt;p&gt;No environments that have different versions of dependencies installed. No environments missing dependencies entirely. None of that nonsense with Docker.&lt;/p&gt;
&lt;h2&gt;Docker Tools&lt;/h2&gt;
&lt;p&gt;Before I dive into the Dockerfile, I’ll give a quick run down of Docker’s suite of tools.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-101/docker-ecosystem.png&quot; alt=&quot;The Docker ecosystem&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Docker has four main tools that it provides to accomplish tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.docker.com/engine/&quot;&gt;Docker Engine&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.docker.com/compose/overview/&quot;&gt;Docker Compose&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.docker.com/machine/overview/&quot;&gt;Docker Machine*&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.docker.com/engine/swarm/&quot;&gt;Docker Swarm&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;Docker Engine&lt;/strong&gt; is Docker’s&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“powerful open source containerization technology combined with a work flow for building and containerizing your applications.” — &lt;a href=&quot;https://docs.docker.com/engine/&quot;&gt;Docker, About Docker Engine&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s what builds and executes Docker images from either a single &lt;code&gt;Dockerfile&lt;/code&gt; or &lt;code&gt;docker-compose.yml&lt;/code&gt;. When someone uses a docker command through the Docker CLI, it talks to this engine to do what needs to be done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker Compose&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“is a tool for defining and running multi-container Docker applications” — &lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker, Overview of Docker Compose&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is what you use when you have an application made up of multiple microservices, databases and other dependencies. The &lt;code&gt;docker-compose.yml&lt;/code&gt; allows you to configure all those services in one place and start them all with a single command. I’ll cover Docker Compose in much greater detail in the follow up blog post.&lt;/p&gt;
&lt;p&gt;In years past, &lt;strong&gt;Docker Machine&lt;/strong&gt; was more popular than it is now.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Docker Machine is a tool that lets you install Docker Engine on virtual hosts, and manage the hosts with docker-machine commands.” — &lt;a href=&quot;https://docs.docker.com/machine/&quot;&gt;Docker, Docker Machine Overview&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s fallen by the wayside a bit as Docker images have become more stable on their native platforms, but earlier in Docker’s history it was very helpful. That’s about all you need to know about Docker Machine for now.&lt;/p&gt;
&lt;p&gt;The final tool, &lt;strong&gt;Docker Swarm&lt;/strong&gt;, won&apos;t be covered in detail. But for now, Docker Swarm&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“creates a swarm of Docker Engines where you can deploy application services. You don’t need additional orchestration software to create or manage a swarm” — &lt;a href=&quot;https://docs.docker.com/engine/swarm/&quot;&gt;Docker, Swarm Mode Overview&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These are the tools you’ll become familiar with, and now, we can talk about the Dockerfile.&lt;/p&gt;
&lt;h2&gt;The Dockerfile — where it all begins&lt;/h2&gt;
&lt;p&gt;Docker is a powerful tool, but its power is harnessed through the use of things called &lt;strong&gt;Dockerfiles&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession. — &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/&quot;&gt;Docker, Dockerfile Reference&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A Docker image consists of read-only layers each of which represents a Dockerfile instruction. The layers are stacked and each one is a delta of the changes from the previous layer.&lt;/p&gt;
&lt;p&gt;This is what I was talking about above, when a Docker container starts up, it needs to be told what to do, it has nothing installed, it knows how to do nothing. Truly nothing.&lt;/p&gt;
&lt;p&gt;The first thing the Dockerfile needs is a &lt;strong&gt;base image&lt;/strong&gt;. A base image tells the container what to install as its OS — Ubuntu, RHEL, SuSE, Node, Java, etc.&lt;/p&gt;
&lt;p&gt;Next, you’ll provide setup instructions. These are all the things the Docker container needs to know about: environment variables, dependencies to install, where files live, etc.&lt;/p&gt;
&lt;p&gt;And finally, you have to tell the container what to do. Typically it will be running specific installations and commands to the application specified in the setup instructions. I’ll give a quick overview of the most common Dockerfile commands next and then show some examples to help it make sense.&lt;/p&gt;
&lt;h2&gt;Dockerfile Commands&lt;/h2&gt;
&lt;p&gt;Below, are the commands that will be used 90% of the time when you’re writing Dockerfiles, and what they mean.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FROM&lt;/code&gt; — this initializes a new build stage and sets the &lt;a href=&quot;https://docs.docker.com/engine/reference/glossary/#base-image&quot;&gt;&lt;strong&gt;Base Image&lt;/strong&gt;&lt;/a&gt; for subsequent instructions. As such, a valid &lt;code&gt;Dockerfile&lt;/code&gt; must start with a &lt;code&gt;FROM&lt;/code&gt; instruction.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RUN&lt;/code&gt; — will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ENV&lt;/code&gt; — sets the environment variable &lt;code&gt;&amp;lt;key&amp;gt;&lt;/code&gt; to the value &lt;code&gt;&amp;lt;value&amp;gt;&lt;/code&gt;. This value will be in the environment for all subsequent instructions in the build stage and can be &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/#environment-replacement&quot;&gt;replaced inline&lt;/a&gt; in many as well.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXPOSE&lt;/code&gt; — informs Docker that the container listens on the specified network ports at runtime. You can specify whether the port listens on TCP or UDP, and the default is TCP if the protocol is not specified. This makes it possible for the host and the outside world to access the isolated Docker Container.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VOLUME&lt;/code&gt; — creates a mount point with the specified name and marks it as holding externally mounted volumes from the native host or other containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ok, now Dockerfile commands have been defined, so let’s look at some sample Dockerfiles. If you want to learn more about Docker commands, I’d highly recommend the &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/&quot;&gt;Dockerfile documentation&lt;/a&gt; — it’s very well written.&lt;/p&gt;
&lt;h2&gt;Dockerfile Examples&lt;/h2&gt;
&lt;p&gt;Here are a few sample Dockerfiles, complete with comments explaining each line and what’s happening layer by layer.&lt;/p&gt;
&lt;h3&gt;Node.js Dockerfile Example&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# creates a layer from the node:carbon Docker image
FROM node:carbon

# create the app directory for inside the Docker image
WORKDIR /usr/src/app

# copy and install app dependencies from the package.json (and the package-lock.json) into the root of the directory created above
COPY package*.json ./
RUN npm install

# bundle app source inside Docker image
COPY . .

# expose port 8080 to have it mapped by Docker daemon
EXPOSE 8080

# define the command to run the app (it&apos;s the npm start script from the package.json file)
CMD [ &quot;npm&quot;, &quot;start&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Java Dockerfile Example&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# creates a layer from the openjdk:8-jdk-alpine Docker image
FROM openjdk:8-jdk-alpine

# create the directory for where Tomcat creates its working directories
VOLUME /tmp

# copy the project JAR file to the container renamed as &apos;app.jar&apos;
COPY build/libs /app

# execute that JAR in the entry point below
ENTRYPOINT [&quot;java&quot;, &quot;-Djava.security.egd=file:/dev/./urandom&quot;, &quot;-jar&quot;, &quot;/app/java-example.jar&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Python Dockerfile Example&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# creates a layer from the ubuntu:16.04 Docker image 
FROM ubuntu:16.04

# adds files from the Docker client’s current directory
COPY . /app

# builds the application with make 
RUN make /app

# specifies what command to run within the container
CMD python /app/app.py
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Jenkins Dockerfile Example&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# creates a layer from the jenkins:lts Docker image
FROM jenkins/jenkins:lts

# sets user to root (because Docker always runs as root and Jenkins needs to know this)
  USER root
 
# add and install all the necessary dependencies
 RUN apt-get update &amp;amp;&amp;amp; \
 apt-get install -qy \
   apt-utils \
   libyaml-dev \
   build-essential \
   python-dev \
   libxml2-dev \
   libxslt-dev \
   libffi-dev \
   libssl-dev \
   default-libmysqlclient-dev \
   python-mysqldb \
   python-pip \
   libjpeg-dev \
   zlib1g-dev \
   libblas-dev\
   liblapack-dev \
   libatlas-base-dev \
   apt-transport-https \
   ca-certificates \
   zip \
   unzip \
   gfortran &amp;amp;&amp;amp; \
 rm -rf /var/lib/apt/lists/*
 
# install docker
 RUN curl -fsSL get.docker.com -o get-docker.sh &amp;amp;&amp;amp; sh get-docker.sh
 
# install docker compose
 RUN curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` &amp;gt; /usr/local/bin/docker-compose &amp;amp;&amp;amp; \
     chmod +x /usr/local/bin/docker-compose

# install pip for python
 RUN pip install cffi --upgrade
 RUN pip install pip2pi ansible==2.0
 
# copy groovy executors and plugins for jenkins and run the plugins
 COPY executors.groovy /usr/share/jenkins/ref/init.groovy.d/executors.groovy
 COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
 RUN /usr/local/bin/plugins.sh /usr/share/jenkins/ref/plugins.txt
 
# add the jenkins user to the docker group so that sudo is not required to run docker commands
 RUN groupmod -g 1026 docker &amp;amp;&amp;amp; gpasswd -a jenkins docker
 USER jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The commands aren’t really that hard or complicated, once you see the files broken down like this.&lt;/p&gt;
&lt;h2&gt;Images vs. Containers&lt;/h2&gt;
&lt;p&gt;The terms Docker image and Docker container are sometimes used interchangeably, but they shouldn’t be, they mean two different things.&lt;/p&gt;
&lt;p&gt;Docker &lt;strong&gt;images&lt;/strong&gt; are executable packages that include everything needed to run an application — the code, a runtime, libraries, environment variables, and configuration files.&lt;/p&gt;
&lt;p&gt;Docker &lt;strong&gt;containers&lt;/strong&gt; are a runtime instance of an image — what the image becomes in memory when executed (that is, an image with state, or a user process).&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-101/docker-containers.png&quot; alt=&quot;Docker container diagram example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Examples of Docker containers. Each one comes from a specific Docker image.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In short, Docker images hold the snapshot of the Dockerfile, and the Docker container is a running implementation of a Docker image based on the instructions contained within that image.&lt;/p&gt;
&lt;p&gt;We clear? Cool.&lt;/p&gt;
&lt;h2&gt;Docker Engine Commands&lt;/h2&gt;
&lt;p&gt;Once the Dockerfile has been written the Docker image can be built and the Docker container can be run. All of this is taken care of by the Docker Engine that I covered briefly earlier.&lt;/p&gt;
&lt;p&gt;A user can interact with the Docker Engine through the Docker CLI, which talks to the Docker REST API, which talks to the long-running Docker daemon process (the heart of the Docker Engine). Here’s an illustration below.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/docker-101/docker-cli.png&quot; alt=&quot;Docker CLI diagram&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The CLI uses the Docker REST API to control or interact with the Docker daemon through scripting or direct CLI commands. Many other Docker applications use the underlying API and CLI as well.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The CLI uses the Docker REST API to control or interact with the Docker daemon through scripting or direct CLI commands. Many other Docker applications use the underlying API and CLI as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker build&lt;/code&gt; — builds an image from a Dockerfile&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker images&lt;/code&gt; — displays all Docker images on that machine&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker run&lt;/code&gt; — starts container and runs any commands in that container&lt;/li&gt;
&lt;li&gt;there’s multiple options that go along with &lt;code&gt;docker run&lt;/code&gt; including&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; — allows you to specify ports in host and Docker container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-it—opens&lt;/code&gt; up an interactive terminal after the container starts running&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; — bind mount a volume to the container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; — set environmental variables&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; — starts the container in daemon mode (it runs in a background process)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker rmi&lt;/code&gt; — removes one or more images&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker rm&lt;/code&gt; — removes one or more containers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker kill&lt;/code&gt; — kills one or more running containers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker ps&lt;/code&gt; — displays a list of running containers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker tag&lt;/code&gt; — tags the image with an alias that can be referenced later (good for versioning)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker login&lt;/code&gt; — login to Docker registry&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These commands can be combined in ways too numerous to count, but here’s a couple simple examples of Docker commands.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker build -t user1/node-example .&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This says to Docker: build (&lt;code&gt;build&lt;/code&gt;) the image from the Dockerfile at the root level (&lt;code&gt;.&lt;/code&gt; ) and tag it &lt;code&gt;-t&lt;/code&gt; as &lt;code&gt;user1/node-example&lt;/code&gt;. Don’t forget the period — this is how Docker knows where to look for the Dockerfile.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run -p 3003:8080 -d user1/node-example&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This tells Docker to run (&lt;code&gt;run&lt;/code&gt;) the image that was built and tagged as &lt;code&gt;user1/node-example&lt;/code&gt;, expose port 3003 on the host machine and look for port 8080 inside the Docker container (&lt;code&gt;-p 3003:8080&lt;/code&gt;), and start the process as a background daemon process (&lt;code&gt;-d&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;That’s how simple it can be to run commands using the Docker CLI. Once again, the &lt;a href=&quot;https://docs.docker.com/engine/reference/run/&quot;&gt;Docker documentation&lt;/a&gt; is well done.&lt;/p&gt;
&lt;h2&gt;Conclusion &amp;amp; Part Two: Docker Compose&lt;/h2&gt;
&lt;p&gt;Now you’ve seen the tip of the iceberg of Docker. It’s a lightweight, isolated runtime environment known as a ‘container’ that you can spin up and configure just about anyway you like with the help of a Dockerfile.&lt;/p&gt;
&lt;p&gt;Stay tuned for &lt;strong&gt;&lt;a href=&quot;./docker-102-docker-compose&quot;&gt;part two&lt;/a&gt;&lt;/strong&gt; of this series where I’ll dive into the Docker Compose tool that lets you configure and run multiple applications with just one file and a single start command. It’s pretty darn cool.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this gives you a better understanding of the basics of Docker and its power.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/what-docker&quot;&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://opensource.com/resources/what-docker&quot;&gt;What is Docker?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/builder/&quot;&gt;Dockerfile Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/run/&quot;&gt;Docker Run Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>docker</category><category>devops</category></item><item><title>React, SVG Images and the webpack Loader to Make Them Play Nice</title><link>https://www.paigeniedringhaus.com/blog/react-svg-images-and-the-webpack-loader-to-make-them-play-nice/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/react-svg-images-and-the-webpack-loader-to-make-them-play-nice/</guid><description>React and SVGs did not start out friends. One npm package offered an answer.</description><pubDate>Fri, 08 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/react-svg-webpack/laptop-on-couch.jpeg&quot; alt=&quot;Laptop screen filled with code sitting on a couch&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Photo by &amp;lt;a href=&quot;https://unsplash.com/photos/iacpoKgpBAM?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&amp;gt;Goran Ivos&amp;lt;/a&amp;gt; on Unsplash&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This isn’t a new problem - the dilemma of getting SVGs to correctly render with React. But it is a problem that I hadn’t had to deal with and overcome until recently, and I’d like to share my experiences in the hope that it saves someone else a few hours of searching Github, StackOverflow and npm.&lt;/p&gt;
&lt;p&gt;At my current company, I’ve worked for two separate development teams, both of whom use JavaScript microservices for their UIs: one uses AngularJS, the other JavaScript MVC. All the backend services are Java Spring Boot applications.&lt;/p&gt;
&lt;p&gt;Recently, the news broke that Google was going to end long term support for AngularJS v1.5 - the version we were running on.&lt;/p&gt;
&lt;p&gt;It quickly became clear we had three options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Upgrade the system to &lt;a href=&quot;https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c&quot;&gt;AngularJS 1.7&lt;/a&gt; (which would continue to have long term support for 3 more years),&lt;/li&gt;
&lt;li&gt;Upgrade our application to Angular 2+,&lt;/li&gt;
&lt;li&gt;Or migrate to a competitor JavaScript framework: ReactJS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One of my colleagues and I were tasked with figuring out which was the best direction to take. This exploration was a process which deserves its own blog post, but suffice it to say, I was most in favor of venturing into React (I liked the syntax better for one). After we’d looked at our options and tinkered, we decided to see if we could make a small proof-of-concept (POC) in React work with our existing app (because we&apos;d need the two UIs to route back and forth to each other until the migration was complete).&lt;/p&gt;
&lt;p&gt;About 4 hours after starting our React POC, we had a working, albeit not very pretty, app. We added Jest and Enzyme unit tests, Cypress end-to-end tests and more. But for almost two weeks one thing eluded us: getting an SVG graphic to render correctly in the DOM.&lt;/p&gt;
&lt;p&gt;Today, I&apos;ll show you how I got SVGs working with a React application.&lt;/p&gt;
&lt;h2&gt;Why SVGs? What’s the Benefit? Why Not Just Make It Into a PNG?&lt;/h2&gt;
&lt;p&gt;Great question. The benefits of using SVGs are many, and in case you don’t know, SVG stands for &lt;a href=&quot;https://en.wikipedia.org/wiki/Scalable_Vector_Graphics&quot;&gt;&lt;strong&gt;Scalable Vector Graphics&lt;/strong&gt;&lt;/a&gt;. While the textbook definition sounds dense:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“SVG is an &lt;a href=&quot;https://en.wikipedia.org/wiki/XML&quot;&gt;XML&lt;/a&gt;-based &lt;a href=&quot;https://en.wikipedia.org/wiki/Vector_image_format&quot;&gt;vector image format&lt;/a&gt; for &lt;a href=&quot;https://en.wikipedia.org/wiki/Two-dimensional&quot;&gt;two-dimensional&lt;/a&gt; graphics with support for interactivity and animation” — &lt;a href=&quot;https://en.wikipedia.org/wiki/Scalable_Vector_Graphics&quot;&gt;Wikipedia, Scalable Vector Graphics&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They basically take the place of traditional images in other formats like JPEG, PNG, TIFF or GIF.&lt;/p&gt;
&lt;p&gt;Here are a few reasons why SVGs are superior to the other image formats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Crystal clear resolution no matter the screen size, zoom level or image size&lt;/strong&gt; — since SVGs are built on vector paths, shapes and fills, they can scale to any size with no loss of clarity. PNGs, on the other hand, are based on pixels, which won’t look sharp and clear at all times (especially on retina display devices).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Load speed is much faster&lt;/strong&gt; — if you’re using high res images on your site to cater to those retina displays, the PNG files can be pretty sizable, and larger files render more slowly. SVGs are just code, which means smaller file sizes (unless you’re loading something very detailed with a million vector paths).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animation is possible&lt;/strong&gt; — unlike PNG files which are static: what you see is what you get - SVGs can be animated and styled with CSS. Animations, different colors, changes in state (like mouse hover or click) - all these things can be done to SVGs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility and SEO&lt;/strong&gt; — Google indexes SVGs, which means better SEO scores for your site and better accessibility for people with vision impairments visiting your site.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Right. So SVGs It Is, Now How to Use Them In React&lt;/h2&gt;
&lt;p&gt;For my project, I was attempting to recreate one of the simpler screens of the existing AngularJS application in React. This screen contained four big, clickable cards that would take users to other various screens, and each card had a nice SVG file associated with words.&lt;/p&gt;
&lt;p&gt;So I copied the SVG files from the original project into the React app, imported the files into the component that would render them, and told the DOM to render them:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Image source={require(&quot;../img/key.svg&quot;)} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the JSX, I added the CSS styling, waited for webpack to do its magical parsing and... nothing. Well, not quite nothing, errors in the console about unrecognized file types, but certainly no SVG key-shaped icon displayed in the UI.&lt;/p&gt;
&lt;p&gt;And thus began the search for the library I needed to render SVGs correctly in React. This was a days long process. If you’re unaware there’s approximately 7,845,923 npm modules that all claim to make React play nicely with SVGs. Some of them probably work, the first 10 or so I tried, did not.&lt;/p&gt;
&lt;h2&gt;Then… SVG Inline Loader&lt;/h2&gt;
&lt;p&gt;Then I found it. An npm module aptly named &lt;a href=&quot;https://www.npmjs.com/package/svg-inline-loader&quot;&gt;&lt;code&gt;svg-inline-loader&lt;/code&gt;&lt;/a&gt;, it had decent documentation, it had 3,200 weekly downloads, it had 325 stars on Github, &lt;em&gt;it was developed and maintained by the core team that built webpack&lt;/em&gt; - it seemed promising.&lt;/p&gt;
&lt;p&gt;So I gave it a shot and saved it to my &lt;code&gt;devDependencies&lt;/code&gt; in the &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install svg-inline-loader react-inlinesvg --save-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then added the configuration object to the &lt;code&gt;webpack.config.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    test: /\.svg$/,
    loader: &quot;svg-inline-loader&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I was good to go. One simple update to webpack, a small adjustment to the JSX syntax and...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { Component } from &apos;react&apos;;
import KeyImage from &apos;../img/key.svg&apos;; 
import SVG from &apos;react-inlinesvg&apos;;
class Card extends Component(){
return(
    &amp;lt;div&amp;gt;
      &amp;lt; /* other UI stuff here */ &amp;gt; 
      &amp;lt;SVG src={KeyImage} /&amp;gt;
    &amp;lt;/div&amp;gt;  
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;BOOM — SVG displayed!&lt;/p&gt;
&lt;p&gt;I’d also like to add that this npm module has some pretty nifty extra features: it can remove extra tag info from SVGs (which happens a lot when they’re generated with Sketch or Adobe), and it can add classes or IDs to prevent SVG collisions. Nice.&lt;/p&gt;
&lt;p&gt;And that was it. No CSS changes, no super weird syntaxes, nothing like that. Just &lt;code&gt;svg-inline-loader&lt;/code&gt;, an extra module loader for webpack, and the problem was solved.&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope it helps you like it helped me.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Scalable_Vector_Graphics&quot;&gt;Scalable Vector Graphics&lt;/a&gt; definition&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/svg-inline-loader&quot;&gt;svg-inline-loader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://watb.co.uk/5-reasons-you-should-be-using-svgs-over-pngs/&quot;&gt;5 reasons you should be using SVGs over PNGs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>react</category></item><item><title>Leveraging a Spring Cloud Config Server in a Node.js App&apos;s Feature Toggles (Pt 2)</title><link>https://www.paigeniedringhaus.com/blog/leveraging-a-spring-cloud-config-server-in-a-nodejs-apps-feature-toggles-pt-2/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/leveraging-a-spring-cloud-config-server-in-a-nodejs-apps-feature-toggles-pt-2/</guid><description>Yes, you can use a Java config server to alter a Node.js service.</description><pubDate>Sat, 02 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/more-code.jpeg&quot; alt=&quot;Laptop screen filled with minified source code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;As I showed in my &lt;a href=&quot;./why-a-spring-cloud-config-server-is-crucial-to-a-good-ci-cd-pipeline-pt-1&quot;&gt;first post about the Spring Cloud Config server&lt;/a&gt;, setting up a configuration server for a Java Spring Boot application and then leveraging that server to provide environment variables to existing Spring Boot projects is really handy.&lt;/p&gt;
&lt;p&gt;The next trick was figuring out if it was possible to use that very same config server in a Node,js project.&lt;/p&gt;
&lt;p&gt;To give you a quick rundown, my team worked on a microservice-based application architecture, meaning, we had up to thirteen separate Java services and one Node service all running to power our application.&lt;/p&gt;
&lt;p&gt;It made total sense to go with a Java-based config server, since: thirteen Spring Boot microservices, but when our business partners decided they wanted to implement feature toggles, it became a priority to get the config server working in the Node project as well.&lt;/p&gt;
&lt;h2&gt;What is a Feature Toggle, and Why Do I Need It?&lt;/h2&gt;
&lt;p&gt;Let me set the stage by giving you a quick run down of what a feature toggle is and why it’s so beneficial for developers, business partners and customers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;feature toggle&lt;/strong&gt; is a technique in &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_development&quot;&gt;software development&lt;/a&gt; that attempts to provide an alternative to maintaining multiple &lt;a href=&quot;https://en.wikipedia.org/wiki/Source_code&quot;&gt;source-code&lt;/a&gt; branches (known as feature branches), such that a feature can be tested even before it is completed and ready for release. A feature toggle is used to hide, enable or disable the feature during run time. For example, during the development process, a developer can enable the feature for testing and disable it for other users.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Feature_toggle&quot;&gt;— Wikipedia, Feature Toggle&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically, a feature toggle allows developers to introduce new features to users in a more Agile development fashion.&lt;/p&gt;
&lt;p&gt;With feature toggles, devs can continue to maintain just one codebase but show different views of the UI to users in production versus the development team in lower life cycles, based on if those toggles are set to ‘on’ or ‘off’.&lt;/p&gt;
&lt;p&gt;They also allow our business and UX partners to validate early on, if new features are beneficial to our users, or if they need to reevaluate how we’re approaching a solution.&lt;/p&gt;
&lt;p&gt;Let me make one thing crystal clear though: &lt;strong&gt;feature toggles are not meant to be permanent solutions.&lt;/strong&gt; They are temporary, meant to remain only until the feature has been completed and validated that it’s useful or meets whatever other criteria was set for success or failure. Then the code around the feature toggle should be removed to keep the codebase clean and as free of technical debt as is possible.&lt;/p&gt;
&lt;p&gt;For my specific situation, our feature toggle was needed to hide a button that didn’t have full functionality yet because the backend service to support it wasn’t finished, and hide the radio buttons from users. They wouldn’t be needed until the button and service were done.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/feature-toggle-users.png&quot; alt=&quot;The UI a typical user sees (feature toggle hides buttons and checkboxes)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Feature toggle view for users: no button and no checkboxes.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Above is the UI view users in production would see: no buttons, no checkboxes. Below is the UI view developers working on the feature need to see: buttons and checkboxes present.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/feature-toggle-devs.png&quot; alt=&quot;The UI a developer sees (feature toggle shows buttons and checkboxes)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Feature toggle view for devs: buttons and checkboxes.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s look at how we got these two views simultaneously.&lt;/p&gt;
&lt;h2&gt;Setting Up Your Config Server Properties&lt;/h2&gt;
&lt;p&gt;Before we get to the Node config server, let’s first set up the new file with the following naming conventions in our config server properties repo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[application name]-[life cycle profile].yml
ex. my-ui-app-to-config-QA.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within this YAML file, you’ll be able to add your configuration properties for your UI feature toggle. Here’s all I had to include for my feature toggles.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;modifyDatesToggle: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Commit this to a Github repo, and we’re set there. You can see an example of the config properties repo &lt;a href=&quot;https://github.com/paigen11/spring-cloud-config-properties-sample&quot;&gt;here in Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;nodecloud-config-client Node.js Set Up&lt;/h2&gt;
&lt;p&gt;To leverage the existing Spring Cloud Config server set up with our Node frontend application, I chose the &lt;a href=&quot;https://www.npmjs.com/package/nodecloud-config-client&quot;&gt;&lt;code&gt;nodecloud-config-client&lt;/code&gt;&lt;/a&gt; on npm, as it’s a fairly well documented Spring Cloud Config Server client written for JavaScript.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I should mention, this is not to be confused with &lt;code&gt;node-cloud-config-client&lt;/code&gt; or &lt;code&gt;cloud-config-client&lt;/code&gt; — really, there’s a million versions of config client packages written for Node.js, but the one listed above and in the resources link is the one I used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So to get down to business, after saving the npm package to our UI’s &lt;code&gt;package.json&lt;/code&gt; dependencies, add it to the &lt;code&gt;server.js &lt;/code&gt;file (or wherever your Node server’s configuration is located).&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/node-cloud-config.png&quot; alt=&quot;Code set up in app.js file showing the cloud-config-client requirement&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;See the &lt;code&gt;client&lt;/code&gt; variable at the bottom — that’s where the config client comes in to play.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If you’re developing in multiple environments like my team did (local, QA, Q1, production, etc.), add a variable to access the Spring Cloud config server for all stages of the development process (these &lt;a href=&quot;https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#VCAP-SERVICES&quot;&gt;environment variable services&lt;/a&gt; are how we connected to it in Pivotal Cloud Foundry). I mentioned these back in my &lt;strong&gt;&lt;a href=&quot;./why-a-spring-cloud-config-server-is-crucial-to-a-good-ci-cd-pipeline-pt-1&quot;&gt;previous post&lt;/a&gt;&lt;/strong&gt;, if you’d like more info.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/config-logic.png&quot; alt=&quot;Logic in Node server determining how to fetch feature toggles from the Spring Cloud Config server&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The &lt;code&gt;configServerUrl&lt;/code&gt; goes through a series of checks for environment variables, and if it finds none of those (like during local development), it defaults to the hard coded URL. I used the same environment variables and logic for the &lt;code&gt;configServicesProfile&lt;/code&gt; and &lt;code&gt;featureToggle&lt;/code&gt;.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Next, add a variable to account for where the config services profile will be located (for local development I had it default to QA). And I added a variable to check for enabled/disabled feature toggles.&lt;/p&gt;
&lt;p&gt;The below code connects to the config server (when feature toggles are enabled), and maps any feature toggles found to an object.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ modifyDatesFeature : true }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then that object is sent to the rest of the UI with the &lt;code&gt;app.get&lt;/code&gt; endpoint simply called &lt;code&gt;&quot;/featureToggles&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/node-feature-toggle.png&quot; alt=&quot;Node code connecting to config server and checking for feature toggles&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Feature flag variable, call to the client to access the config server with the correct environment (QA in my case), and a check if the &lt;code&gt;featureToggle&lt;/code&gt; is &lt;code&gt;‘on’&lt;/code&gt;, map the properties that are available to it. Below is the endpoint to call the features.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Great. The Node server is set up, and you can get the features toggles (or whatever else you’re storing in the config server) just by changing a few variables.&lt;/p&gt;
&lt;h2&gt;Connecting Your Client Side UI Framework to Your Node Server&lt;/h2&gt;
&lt;p&gt;The first thing you’ll need to do on the frontend is make an AJAX call to the Node server to check for any existing feature toggles. The framework of the app implementing this was JavaScript MVC (an older framework popular years ago, I&apos;d never heard of it before I worked with it either), and here’s an example of what the call looked like.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/javascript-mvc.png&quot; alt=&quot;JavaScript client-side code calling for any feature toggles from Node server&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;In the JavaScript file that’s actually concerned with feature flags (for me, it was a &lt;code&gt;dates.js&lt;/code&gt; file), I imported the feature toggle AJAX call and created a function to check for the specific feature flag associated with this functionality: &lt;code&gt;modifyDatesToggle&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/js-feature-toggle-code.png&quot; alt=&quot;Feature toggle code for showing / hiding particular date / time feature&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The feature flag was imported at the top of the file, then I call to the feature flag endpoint to see if there’s anything there the file needs to be aware of. If the feature flag matches the variable I named “modifyDatesToggle”, it gets pulled in and applied to the file.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Finally, inside your JavaScript file using the feature toggle, group the code, wherever possible according to if the feature toggle is enabled, like so.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/feature-toggle-grouped-code.png&quot; alt=&quot;Code modifications that happen when feature toggle is enabled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Example 1: This check displays the check boxes if the &lt;code&gt;modifyDatesToggle&lt;/code&gt; is &lt;code&gt;“on.”&lt;/code&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The thinking goes, that by wrapping all the feature enabled code inside of the feature toggle check, even if the call to the config server fails for some reason, users will only ever see the code that should be deployed to production. This gives us extra protection by not being as dependent on more variables than necessary.&lt;/p&gt;
&lt;h2&gt;But Wait, There’s More — Enabling End-to-End Tests with Feature Toggles&lt;/h2&gt;
&lt;p&gt;There’s one more thing I wanted to include in this blog: how I used the same feature toggle logic to run or skip some of the Protractor end-to-end tests.&lt;/p&gt;
&lt;p&gt;If you’re using a configuration file for Protractor, and I don’t know why anyone wouldn’t, there’s a cool feature that lets you make your own &lt;a href=&quot;https://moduscreate.com/blog/protractor_parameters_adding_flexibility_automation_tests/&quot;&gt;custom parameters&lt;/a&gt;. I took a page out of my own book where the feature toggle is set in the &lt;code&gt;server.js&lt;/code&gt; file, and did a similar set up in the Protractor config file: if environment variables are passed in for the feature toggle, the tests that concern that feature will run, if it’s not, they’ll be ignored — I’ll show you the test syntax in a moment, as it’s a little unconventional.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/feature-toggle-e2e-config.png&quot; alt=&quot;Feature toggle setup in e2e testing configuration&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Here’s the configuration that all the Protractor tests use. Params takes in the modifyDatesToggle object and if it exists, it sets the params, if it doesn’t, it sets it to null.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;When you’re running the tests locally, you can actually pass the params in through the command line like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ protractor e2e/conf.js browser.params.modifyDatesToggle=‘true’
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To implement the feature toggle in the actual end-to-end tests, inside of each test that requires a feature toggle check, add an if statement right after the &lt;code&gt;‘it’&lt;/code&gt; declaration, checking if the feature toggle is null or not. As I said, this is a little weird to see, but it works.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/feature-toggle-test.png&quot; alt=&quot;Automated test utilizing feature toggled code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;An example of a Protractor end-to-end test with a feature toggle check. Not all the tests need this check — just the ones that require the feature toggle to be either off or on.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;If the feature toggle is not enabled, the test will be skipped, but show up as if it passed in the console (eliminating failing tests because the proper environment wasn’t present for the test to use).&lt;/p&gt;
&lt;p&gt;If the feature toggle is enabled, the test will run as normal. This prevents us from having to go through the tests one by one and either &lt;code&gt;x&lt;/code&gt; them out to ignore them or remove the &lt;code&gt;x&lt;/code&gt; so they’ll run depending on what the desired functionality is. And once it’s time to remove the feature toggle, it’s easy enough to either remove the unnecessary tests from the &lt;code&gt;spec&lt;/code&gt; file or just &lt;code&gt;x&lt;/code&gt; them out, depending on your team’s preference for keeping tests even after functionality has changed. (Personally, I would remove it.)&lt;/p&gt;
&lt;p&gt;Above, I showed how to run the feature toggle tests from the command line, but it can also be run programmatically when the application is being deployed.&lt;/p&gt;
&lt;p&gt;Segue: for my team personally, we use &lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt; for all our builds. That’s a whole other set of blog posts, but suffice it to say, while the build is running all the unit test are run, all the end-to-end tests are running, all the rest of the checks we have in place before declaring a feature is tested and ready for our business team to accept happens.&lt;/p&gt;
&lt;p&gt;Back to how this matters: since Jenkins is our job runner, we can pass the environment variables for the feature toggle tests to Jenkins through a &lt;code&gt;Jenkinsfile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/feature-toggles-jenkinsfile.png&quot; alt=&quot;Enabling feature toggle in Jenkinsfile&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;All that’s needed is the simple line at the bottom: &lt;code&gt;env.MODIFY_DATES_TOGGLE=true&lt;/code&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And that should be all you need to run your end-to-end tests — feature toggles on or off.&lt;/p&gt;
&lt;h2&gt;Automating The Feature Toggles&lt;/h2&gt;
&lt;p&gt;As I said before, my team hosted our applications on Pivotal Cloud Foundry, and in PCF, we use things called VCAP services to hold our environment variables. Through manifest files we could bind these services to our applications and pass in environment variables — variables like if feature toggles should be turned on or off. See where I’m going here?&lt;/p&gt;
&lt;p&gt;The check for the feature toggle environment variable makes deploying the app in an automated fashion easier. By including a simple environment variable (or not) to the manifest that deploys with each different stage of development, it’s easy to tell the application to check for settings in the config server (and employ them if need be) or not.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/qa-manifest.png&quot; alt=&quot;QA manifest that includes feature toggles&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;QA manifest screenshot.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;QA manifest: note the &lt;code&gt;SPRING_PROFILES_ACTIVE&lt;/code&gt; pointing to &lt;code&gt;QA&lt;/code&gt;, &lt;code&gt;FEATURE_TOGGLE&lt;/code&gt; environment variables with &lt;code&gt;‘on’&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-2/prod-manifest.png&quot; alt=&quot;Production manifest that does not include feature toggles&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Production manifest screenshot.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Production manifest: no feature toggle in sight, and the &lt;code&gt;SPRING_PROFILES_ACTIVE&lt;/code&gt; is set to &lt;code&gt;production&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There you have it. Now, you have seen how you can leverage a Spring Cloud Config server you’ve built with your Node.js application. Not only that, you can also configure end to end tests to run with the feature toggle on or off as well.&lt;/p&gt;
&lt;p&gt;If you’ve found other ways to implement feature toggles or other nifty things like this in your own JavaScript projects, I’d love to hear about them.&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Feature_toggle&quot;&gt;Wikipedia, Feature Toggle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/nodecloud-config-client&quot;&gt;NodeCloud Config Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/spring-cloud-config-properties-sample&quot;&gt;Sample Cloud Config Properties Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://moduscreate.com/blog/protractor_parameters_adding_flexibility_automation_tests/&quot;&gt;Protractor documentation around environment params&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category><category>nodejs</category><category>devops</category><category>spring boot</category></item><item><title>Why a Spring Cloud Config Server is Crucial to a Good CI/CD Pipeline (Pt 1)</title><link>https://www.paigeniedringhaus.com/blog/why-a-spring-cloud-config-server-is-crucial-to-a-good-cicd-pipeline-pt-1/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/why-a-spring-cloud-config-server-is-crucial-to-a-good-cicd-pipeline-pt-1/</guid><description>Store and update variables your app will need to run in just one place.</description><pubDate>Sat, 26 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-1/screen-of-code.jpeg&quot; alt=&quot;Laptop screen filled with minified source code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Before I began developing large-scale, enterprise level software, I didn’t fully comprehend the value of things like integration tests, automated build processes and shared libraries.&lt;/p&gt;
&lt;p&gt;For the small applications I built during my &lt;a href=&quot;./how-i-went-from-a-digital-marketer-to-a-software-engineer-in-4-months&quot;&gt;coding bootcamp&lt;/a&gt;, it was easy for me to do things like hard code URLs so my frontend application could talk to its backend counterparts and their databases.&lt;/p&gt;
&lt;p&gt;I only had two environments: my local development environment on my laptop and my AWS production environment where I hosted my projects portfolio, and it was a fairly simple, albeit entirely manual, process (with a good bit of trial and error) to get the pieces of the puzzle connected.&lt;/p&gt;
&lt;p&gt;Fast forward several months to my software engineering job of maintaining and improving upon an application backed by no less than 13 microservices. No, I’m not joking. Yes, all 13 are critical to this application working.&lt;/p&gt;
&lt;p&gt;Did I mention that in my team’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;test driven development (TDD)&lt;/a&gt;, agile process we also have 4 different development environments before a new feature makes it to production? Yep: a local development space, a QA space, a Q1 space, an acceptance space and finally our production space.&lt;/p&gt;
&lt;p&gt;So, think about it: does it make sense to have to manually update each and every one of these services as they move through the development process on their way to production? Of course it doesn’t.&lt;/p&gt;
&lt;p&gt;You need a centralized, easy-to-automate way to update those environment variables. This is where a cloud configuration server can shine.&lt;/p&gt;
&lt;p&gt;To give you a quick overview, cloud config servers are designed to:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Provide server and client-side support for externalized configuration in a distributed system. With the Config Server you have a central place to manage external properties for applications across all environments.”&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud.spring.io/spring-cloud-config/&quot;&gt;- Spring Cloud Config&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Basically, a config server allows you to externally store variables your application will need to run in all environments, regardless of lifecycle, and update them in one, centralized place.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-1/spring-cloud.jpeg&quot; alt=&quot;Spring Cloud logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Behold, the Spring Cloud.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The first config server I was introduced to is the &lt;a href=&quot;https://cloud.spring.io/spring-cloud-config/&quot;&gt;Spring Cloud Config&lt;/a&gt; server, since my team is responsible for a full stack application composed of many Java Spring Boot backend microservices and a JavaScript Node.js frontend microservice.&lt;/p&gt;
&lt;h2&gt;Setting Up Your Config Server&lt;/h2&gt;
&lt;p&gt;Setting up the config server is actually pretty easy.&lt;/p&gt;
&lt;p&gt;To get started, you can go the &lt;a href=&quot;http://start.spring.io/&quot;&gt;Spring Initializr site&lt;/a&gt;, add &lt;code&gt;Config Server&lt;/code&gt; as a dependency to the project and click the &quot;Generate Project&quot; button in the browser.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’ll also add that, at least at the time I’m writing this, the Spring Cloud Config Server is not compatible with Spring Boot version 2 (I found this out the hard way), so choose the highest Spring Boot version 1 snapshot you can.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-1/spring-initializr.png&quot; alt=&quot;Spring Initializr site&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is all you need to get your Spring Cloud Config Server running: the Config Server dependency. Note the version of Spring Boot is 1.5.14, not 2.0.2, which is the latest version it automatically defaults to.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Once you’ve downloaded the project and opened it up in your IDE of choice (mine is &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ&lt;/a&gt;), you can go straight to the main application file, add the &lt;code&gt;@EnableConfigServer&lt;/code&gt; and &lt;code&gt;@SpringBootApplication&lt;/code&gt; Spring Boot annotations, and you’re almost ready to go.&lt;/p&gt;
&lt;p&gt;Below is my actual main method file, truly, that’s all it needs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.myExampleConfigServer; 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer; 

@EnableConfigServer
@SpringBootApplication

public class MyExampleConfigServerApplication {  
  public static void main(String[] args) {
    SpringApplication.run(MyExampleConfigServerApplication.class,  args); 
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other file you’ll need to configure is your &lt;code&gt;application.yml&lt;/code&gt; file in your &lt;code&gt;resources/&lt;/code&gt; folder. This file will be where you set up your cloud config server’s access to GitHub (and the GitHub files it will use to provide application configuration variables).&lt;/p&gt;
&lt;p&gt;As you can see, there’s a spot for your GitHub URL (which I’ll come back to in a minute), username and password.&lt;/p&gt;
&lt;p&gt;Since our applications are hosted on &lt;a href=&quot;https://pivotal.io/platform&quot;&gt;Pivotal Cloud Foundry&lt;/a&gt;, we use what are called &lt;a href=&quot;https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html&quot;&gt;VCAP services&lt;/a&gt; (it stands for VMWare Cloud Application Platform). It’s a fancy way of saying a service where environment variables are stored that only people (and applications) who have access to that space within PCF can access. This lets us put sensitive information like service accounts and passwords somewhere besides a public GitHub repo where the credentials are available for the config server, but not available for anyone without authorization.&lt;/p&gt;
&lt;p&gt;Here’s my &lt;code&gt;application.yml&lt;/code&gt;. With these two files configured and a cloud platform to host your server, you’ll be ready to start using your config server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;application.yml&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server:  
  port:
    8888

spring:  
  application:    
    name: myexample-config-server  

cloud:    
  config:      
    server:        
      git:          
        uri: ${vcap.services.config-service.credentials.url}
        username: ${vcap.services.config-service.credentials.user}          
        password: ${vcap.services.config-service.credentials.token}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’d like to see an example of the config server app, I’ve put a starter project &lt;a href=&quot;https://github.com/paigen11/spring-cloud-config-server-example/tree/master&quot;&gt;here in GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ok, so you’ve got your config server. Great, now it’s time to set up your config server properties — the files the config server will actually access to pull environment variables for your projects.&lt;/p&gt;
&lt;h2&gt;Setting Up Your Config Server Properties&lt;/h2&gt;
&lt;p&gt;This part is a cinch. Create a totally empty new repo in GitHub, and then create a new file with the following naming conventions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[application name]-[life cycle profile].yml

ex. my-app-to-config-QA.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within this YAML file, you’ll be able to add your configuration properties for your application. Here’s some sample info you might include in the YAML.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;my-app-to-config-QA.yml&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;configurations:
  featureToggleFlag: true
  my-custom-flag: false
  sampleCronJob: &quot;0 0 1 * * *&quot;
  sampleUrl: http://google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Commit this file to a GitHub repo, copy that repo URL and place it in the Cloud Config Server URI in your config server’s &lt;code&gt;application.yml&lt;/code&gt;. Now the server knows where to look in GitHub for the config files you want to use.&lt;/p&gt;
&lt;p&gt;You can see an example of a config properties repo &lt;a href=&quot;https://github.com/paigen11/spring-cloud-config-properties-sample&quot;&gt;here in GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Connecting Your Java Spring Boot Application to Your Config Server&lt;/h2&gt;
&lt;p&gt;With both your config server and your properties you want the server to provide to your project, you need your project to be able to get those properties when your Spring Boot service starts up.&lt;/p&gt;
&lt;p&gt;Again, there’s not a lot of overhead to getting this working. In the &lt;code&gt;build.gradle&lt;/code&gt; file of your app that needs these config server values, you’ll need the following dependencies:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;build.gradle&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;compile group: &apos;org.springframework.cloud&apos;, name: &apos;spring-cloud-starter-config&apos;, version:&apos;1.3.3.RELEASE&apos;
compile group: &apos;org.springframework.boot&apos;, name: &apos;spring-boot-configuration-processor&apos;, version: &quot;${springBootVersion}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you’ll create a &lt;code&gt;bootstrap.yml&lt;/code&gt; file which will live alongside your &lt;code&gt;application.yml&lt;/code&gt; file in your &lt;code&gt;src/main/resources/&lt;/code&gt; folder, and it will contain information pointing to the config server’s location wherever it’s being hosted. It will look something like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;bootstrap.yml&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spring:
  application:
    name: ##APPLICATION NAME GOES HERE##
  cloud:
    config:
      uri: https://myexample-config-server.non-prod.com
---
spring:
  profiles: production
  cloud:
    config:
      uri:  https://myexample-config-server.prod.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you’ll go to whichever files actually need the config properties and add the annotations &lt;code&gt;@Configuration&lt;/code&gt; and &lt;code&gt;@ConfigurationProperties(prefix=”configurations&quot;)&lt;/code&gt; (or whatever you’ve named your config properties in the config properties YAML).&lt;/p&gt;
&lt;p&gt;Here&apos;s an example:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;XyzProperties.java&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
@ConfigurationProperties(prefix = &quot;configurations&quot;)
public class ConfigProperties {
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you notice, the properties are prefixed by &lt;code&gt;configurations&lt;/code&gt;. To bind these properties to the ConfigProperties class, you&apos;ll first need to add a &lt;code&gt;&quot;prefix&quot;&lt;/code&gt; to the &lt;code&gt;@ConfigurationProperties&lt;/code&gt; annotation like so:&lt;/p&gt;
&lt;p&gt;To bind the &lt;code&gt;“featureToggleFlag”&lt;/code&gt; property, add the following member variable. along with the getter and setter. Or use &lt;a href=&quot;https://projectlombok.org/features/constructor&quot;&gt;Lombok&lt;/a&gt;’s &lt;code&gt;@NoArgsConstructor&lt;/code&gt; and skip the getters and setters - your choice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;XyzProperties.java&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
@ConfigurationProperties(prefix = &quot;configurations&quot;)
public class ConfigProperties {
   private boolean featureToggleFlag;
   
   //Add Getters and Setters here if desired...
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you match the member variable name with the actual property name in the configuration properties, Spring will automatically bind it to the member variable. So far so good.&lt;/p&gt;
&lt;p&gt;The very last thing you must do before starting up your service is ensure that you set &lt;code&gt;SPRING_PROFILES_ACTIVE&lt;/code&gt; to the correct config properties environment. The current values would be &lt;code&gt;“QA”&lt;/code&gt; for the QA environment, &lt;code&gt;“Q1”&lt;/code&gt; for the Q1 environment, &lt;code&gt;“prod”&lt;/code&gt; for production and so on. Be warned, these values are case sensitive, so however you’ve named them in your config properties file, it must be exactly the same in the &lt;code&gt;&quot;Active Profiles&quot;&lt;/code&gt; input in IntelliJ&apos;s start script setup.&lt;/p&gt;
&lt;p&gt;In IntelliJ, this can be done by clicking the &quot;Edit Configurations&quot; property when setting up a Spring Boot project to run, and adding the correct value to the &lt;code&gt;&quot;Active Profiles&quot;&lt;/code&gt; input midway down the config modal.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/spring-cloud-server-part-1/intellij-active-profiles.png&quot; alt=&quot;Active profile setting inside of IntelliJ IDE&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Inside your IntelliJ run configuration, add this line in the &quot;Active Profiles&quot; input.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And that’s it.&lt;/p&gt;
&lt;p&gt;Now, when you start up the Spring Boot service, you should see &lt;code&gt;Spring Profile&lt;/code&gt; being set in the logs, and to be sure, you might also put in some &lt;code&gt;System.out.println&lt;/code&gt; messaging to let you know if it’s successfully reached the config server and acquired the properties needed.&lt;/p&gt;
&lt;p&gt;Fantastic, we&apos;ve built a config server, we&apos;ve moved environment variables out of your Spring Boot project to a centralized location, so changes can be made quickly and we&apos;ve configured a Java service to pull those variables from the config server. Nicely done.&lt;/p&gt;
&lt;h2&gt;Conclusion and Part Two: The Config Server and Node.js&lt;/h2&gt;
&lt;p&gt;But, how do you do the same thing with a JavaScript / Node.js project? Can you use the same Spring Boot config server? Or do you have to set up a separate Node-based config server?&lt;/p&gt;
&lt;p&gt;You can use the existing one, and I’ll show you how  to set it up, and how you might use it in a JavaScript project to enable and disable feature toggles for faster feature deployments in my &lt;strong&gt;&lt;a href=&quot;./leveraging-a-spring-cloud-config-server-in-a-node-js-apps-feature-toggles-pt-2&quot;&gt;next post&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.spring.io/spring-cloud-config&quot;&gt;Spring Cloud Config Initializr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/spring-cloud-config-server-example&quot;&gt;Sample Cloud Config Server Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paigen11/spring-cloud-config-properties-sample&quot;&gt;Sample Cloud Config Properties Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>java</category><category>devops</category><category>spring boot</category></item><item><title>What is Graphql, Really?</title><link>https://www.paigeniedringhaus.com/blog/what-is-graphql-really/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/what-is-graphql-really/</guid><description>The API standard providing a more efficient, powerful and flexible alternative to REST.</description><pubDate>Sat, 12 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/what-is-graphql/graphql.png&quot; alt=&quot;GraphQL logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I’ve been hearing about GraphQL for months now, but for the longest time I really didn’t understand what it was.&lt;/p&gt;
&lt;p&gt;Is it a new query language? A new type of database? Some other JavaScript black magic? Nope, none of the above.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GraphQL is a new API standard that provides a more efficient, powerful and flexible alternative to REST.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.howtographql.com&quot;&gt;— How to GraphQL&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;It’s an alternative to REST, so what? Why should I use GraphQL instead?&lt;/h2&gt;
&lt;p&gt;Great question.&lt;/p&gt;
&lt;p&gt;Here’s what sets GraphQL apart from traditional REST endpoints: with GraphQL, a client can specify &lt;em&gt;exactly what data it wants (from multiple sources)&lt;/em&gt;, and get back just that from a single endpoint.&lt;/p&gt;
&lt;p&gt;Traditional REST endpoints return fixed data structures, usually with extra info clients don’t need, and they require multiple endpoints (and HTTP calls) to get back all the necessary information. GraphQL does not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here&apos;s an example of two traditional HTTP calls to find students and their classes&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Call 1: HTTP get to: &apos;students/&amp;lt;id&amp;gt;&apos; 
// Returns:
{ &quot;student&quot;: 
  { 
    &quot;id&quot;: 1, 
    &quot;firstName&quot;:&quot;Jane&quot;, 
    &quot;lastName&quot;:&quot;Smith&quot;
  } 
}
// Call 2: HTTP get to: &apos;students/&amp;lt;id&amp;gt;/classes&apos;
// Returns:
{ &quot;classes&quot;:
  [{
    &quot;id&quot;: 1, 
    &quot;className&quot;:&quot;math&quot;
  }, 
  {
    &quot;id&quot;: 1, 
    &quot;className&quot;:&quot;english&quot;
  }]
}

/* Here is the same information as one GraphQL query */*
// Query:
query { Student( id:1 ){ 
    firstName 
    lastName 
    classes { 
      className
    }
  }
} 
// Returns:
{ &quot;data&quot;: 
  { &quot;Student&quot;: 
    { &quot;firstName&quot;:&quot;Jane&quot;, 
      &quot;lastName&quot;:&quot;Smith&quot;, 
      &quot;classes&quot;: 
      [{
        &quot;className&quot;: &quot;math&quot;
      }, 
      {
        &quot;className&quot;:&quot;english&quot;
      }]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One thing that cannot be stressed enough is that GraphQL is not a query language for databases. GraphQL is a query language for APIs.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This makes it database agnostic, and makes it possible to be used in any context where an API is used.&lt;/p&gt;
&lt;p&gt;And no, contrary to the fact that whenever GraphQL is mentioned, it seems to be in tandem with React (since Facebook invented both), GraphQL can be used everywhere a client communicates with an API: there’s server libraries for C, Go, Erlang, Java and more.&lt;/p&gt;
&lt;p&gt;JavaScript is by far the most popular language to utilize with GraphQL, and it has some really excellent server packages that work in conjunction to make GraphQL easily implementable with projects.&lt;/p&gt;
&lt;p&gt;It can be run straight from the command line with Node.js when Graphql.js is installed, but it really shines when it’s integrated into a project with the GraphQL API server sitting as a layer between the client frontend and the server backend and database(s).&lt;/p&gt;
&lt;p&gt;The implementation I’ve used is &lt;a href=&quot;https://www.apollographql.com/&quot;&gt;Apollo&lt;/a&gt;, and it integrates easily with various Node.js HTTP frameworks like Express, KOA, Hapi, etc. But that’s for another post.&lt;/p&gt;
&lt;h2&gt;Ok, you’ve piqued my interest. So how does GraphQL work?&lt;/h2&gt;
&lt;p&gt;GraphQL works based on strongly typed &lt;strong&gt;schemas&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In short, everything that you want GraphQL to return to you, must be explicitly defined in the schema (which some developers like and others feel like it’s making them define data twice).&lt;/p&gt;
&lt;h3&gt;Schemas: How GraphQL Defines and Structures the Data it Receives&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// **** Simple Schema Example for a Type Called Student ****
type Student { 
  firstName: String! // (the exclamation mark means it&apos;s required)
  lastName: String!
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Schema Definition Language (SDL) is the syntax for writing schemas, and &lt;strong&gt;queries&lt;/strong&gt; and mutations are composed to get back the required information from the server. Since the structure of the data returned from the single GraphQL endpoint is completely flexible, the query has to be extremely specific in what it requires.&lt;/p&gt;
&lt;p&gt;If something is specified in the schema but not returned, the response will contain a &lt;code&gt;null&lt;/code&gt; value for that field, but it will not throw an exception as sometimes happens with REST endpoints. However, if a specific field is not specified but is needed, the client won’t receive it until the schema is updated to include that field.&lt;/p&gt;
&lt;h3&gt;Queries: How GraphQL Asks for Data&lt;/h3&gt;
&lt;p&gt;Here&apos;s a basic query asking the server for all students&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// **** Basic Query Asking the Server for All Students ****
{ allStudents 
  {
    firstName 
    lastName
  }
}
// Returns: 
{&quot;allStudents&quot;:
  [{
    &quot;firstName&quot;:&quot;Jane&quot;, 
    &quot;lastName&quot;:&quot;Smith&quot;
  },
  {
    &quot;firstName&quot;:&quot;John&quot;, 
    &quot;lastName&quot;:&quot;Doe&quot;
  }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Mutations: How GraphQL Manipulates Data&lt;/h3&gt;
&lt;p&gt;In addition to queries, GraphQL uses something called &lt;strong&gt;mutations&lt;/strong&gt; to manipulate data stored in the backend. There’s generally three kinds of mutations to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create new data&lt;/li&gt;
&lt;li&gt;update existing data&lt;/li&gt;
&lt;li&gt;delete existing data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This mutation create a new student in the database&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// **** A Create Mutation to Make a New Student ****
mutation { createStudent(firstName: &quot;Robert&quot;, lastName: &quot;Johnson&quot;) 
  { 
    firstName 
    lastName
  }
}

// The server response would look like this:

&quot;createStudent&quot;: { 
  &quot;firstName&quot;:&quot;Robert&quot;, 
  &quot;lastName&quot;:&quot;Johnson&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Between queries to read data and mutations to manipulate data, all the CRUD functionality supplied by traditional REST endpoints is handled by GraphQL.&lt;/p&gt;
&lt;p&gt;Regardless of the way you’re implementing the GraphQL server (connected to a single database, over a number of third party legacy systems or as a hybrid of the two), when a query arrives at the GraphQL server, it &lt;strong&gt;resolves&lt;/strong&gt; the query by reading the payload and fetching the data. Then it uses the schema to return the data in the correct format to the client.&lt;/p&gt;
&lt;p&gt;This clearly defined schema structure is what helps GraphQL to be transport-layer agnostic (TCP, Websockets, etc. — it’s all good) and database agnostic (MySQL, MongoDB, Oracle, etc.).&lt;/p&gt;
&lt;p&gt;Likewise, if GraphQL is being implemented over multiple systems (as is likely the case in larger corporations with lots of sprawling legacy systems and APIs), it can neatly pull only the requested information from all the various endpoints, and resolve it into one, clean response, laid out by the schema.&lt;/p&gt;
&lt;h3&gt;Resolvers: How GraphQL Fetches the Data for Its Query (or Mutation) Field&lt;/h3&gt;
&lt;p&gt;Each of the fields that makes up a piece of the GraphQL query function is called a &lt;strong&gt;resolver&lt;/strong&gt;, and the sole purpose of the resolver is to fetch the data for its field.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// **** Sample Query and the Resolvers Corresponding to Each Field ****
query { Student(id:1){ 
    firstName 
    lastName 
  }
}
// Resolvers:
Student(id: String!): Student
firstName: (student: Student!) String
lastName: (student: Student!) String 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;GraphQL Client Libraries&lt;/h2&gt;
&lt;p&gt;GraphQL is a big step forward for frontend developers because instead of having to imperatively fetch data through:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;building and sending an HTTP request (&lt;code&gt;fetch&lt;/code&gt; in JavaScript),&lt;/li&gt;
&lt;li&gt;receiving and parsing the response,&lt;/li&gt;
&lt;li&gt;storing the data (locally or persisted),&lt;/li&gt;
&lt;li&gt;and finally displaying the data in the UI,&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Clients can declaratively fetch the data by:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;describing the data requirements,&lt;/li&gt;
&lt;li&gt;displaying the returned data in the UI&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Complexity and data storage are pushed to the server-side of the application, which is better suited to take care of the heavy computation work, and the frontend is free to do what it was designed to do: show that data to users quickly in a way they can understand.&lt;/p&gt;
&lt;p&gt;What I’ve described above is what GraphQL libraries like &lt;a href=&quot;https://www.apollographql.com/&quot;&gt;Apollo&lt;/a&gt; and &lt;a href=&quot;https://facebook.github.io/relay/&quot;&gt;Relay&lt;/a&gt; were designed to do. They abstract away the infrastructure implementation of connecting the backend services so developers can focus on the important parts of their application.&lt;/p&gt;
&lt;h2&gt;More About GraphQL&lt;/h2&gt;
&lt;p&gt;If you wanted to, you could stop right here with a much better understanding of what GraphQL is, but if you’d like to know a little more about the benefits on both the client and server side with GraphQL, read on.&lt;/p&gt;
&lt;h3&gt;GraphQL and the Client Side&lt;/h3&gt;
&lt;p&gt;As discussed in the previous sections using the GraphQL API makes frontend development easier with abstractions and helping implement common functionality on the client side.&lt;/p&gt;
&lt;p&gt;Here I’ll go into more detail on how it handles “infrastructure” features developers normally want in their apps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Directly Sending Queries and Mutations Sans HTTP Requests&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GraphQL allows for fetching data in a declarative manner. Instead of making low-level HTTP calls, a client can simply query for the data it needs and GraphQL takes care of the request and response handling for you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View Layer Integrations &amp;amp; UI Updates&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once the GraphQL client has received and handled the response, there’s a number of ways the UI can be updated to reflect the data. If you’re using React, the GraphQL clients make use of &lt;a href=&quot;https://reactjs.org/docs/higher-order-components.html&quot;&gt;higher-order component&lt;/a&gt; concepts (when a function takes one component and returns a new component) to fetch the data make it available to your components in their props.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Client Side Caching&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Typically, you’ll want to maintain some kind of a cache or data previously fetched from the server, it’s critical to having a good user experience and shorter load times as users interact with the UI. However, storing the data exactly as it’s resolved from the GraphQL client won’t be the most efficient way to hold it for most applications.&lt;/p&gt;
&lt;p&gt;Normalizing the data (flattening nested query results) so that the store only contains individual records that can be referenced with a unique global ID is a better option for quickly retrieving only the necessary data when the same query is made in the future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validating &amp;amp; Optimizing Queries Based on the Schema&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Also, since the schema contains all the information about what a client could do with a GraphQL API, the build environment can parse the GraphQL code that’s in the project and compare it against the schema’s information. This makes for catching errors and typos much earlier in the process easier (and less likely to happen in the hands of users).&lt;/p&gt;
&lt;p&gt;Likewise, UI code and data requirements can actually be written side-by-side in some languages like JavaScript, which makes it easier for developers to see that the right data ends up with the right parts of the UI.&lt;/p&gt;
&lt;h3&gt;GraphQL and the Server Side&lt;/h3&gt;
&lt;p&gt;Although GraphQL is talked about a lot around the frontend API, the API itself is still implemented on the server side. And it allows the backend developer to focus on describing the data, rather than implementing and optimizing numerous REST endpoints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GraphQL Query Execution&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For starters, GraphQL uses a simple algorithm for how it changes its queries into results. It traverses the query field by field, executing resolvers for each field.&lt;/p&gt;
&lt;p&gt;If a parent resolver function is required by a child, the parent query will resolve first and pass its result to the child for use in its own query. Finally, once the execution algorithm is done, it forms all the data into the correct shape and returns it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// **** Sample Query and Execution Algorithm ****
type Query {
  director(id: ID!): Director
}
type Director {
  movies: [Movie]
}
type Movie { 
  title: String 
  description: String
}

// **** Sample Query to the Server ****
query { director(id: &quot;2wsx3edc&quot;) 
  { movies 
    { 
      title 
      description
    }
  }
}

// **** Execution Algorithm Visualized ****
Query.director(root, { id:&quot;2wsx3edc&quot; }, context) -&amp;gt; director
Director.movies(director, null, context) -&amp;gt; movies
for each movie in movies
  Movie.title(movie, null, context) -&amp;gt; title
  Movie.description(movie, null, context) -&amp;gt; description
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Batched Query Resolving&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GraphQL also offers the ability to make data fetching smarter, if multiple similar calls will be made to the server in one query.&lt;/p&gt;
&lt;p&gt;In JavaScript, a utility called &lt;a href=&quot;https://github.com/facebook/dataloader&quot;&gt;DataLoader&lt;/a&gt; can be used to wrap the fetching function, which will wait for all the resolvers to run, then make sure to only fetch each item once.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// **** Sample Query and API Calls ****
query{ movies
  { title 
    director
    {
      firstName 
      lastName
    }
  }
}

/* Regardless of the fact that the API is being called for the same piece of data multiple times, the query executes for the director info */
fetch(&apos;/directors/1&apos;)
fetch(&apos;/directors/2&apos;)
fetch(&apos;/directors/2&apos;)
fetch(&apos;/directors/1&apos;)
fetch(&apos;/directors/1&apos;)

// **** Sample API Calls with DataLoader****
directorLoader = new DirectorLoader()
// Queue up all the fetches
directorLoader.load(1);
directorLoader.load(2);
directorLoader.load(2);
directorLoader.load(1);

/* Then the loader only makes the necessary amount of calls for each unique piece of information */
fetch(&apos;/directors/1&apos;)
fetch(&apos;/directors/2&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GraphQL Tooling and Its Ecosystem&lt;/h3&gt;
&lt;p&gt;As I mentioned briefly, GraphQL’s Type System allows us to define the surface area of our APIs and validate queries against a schema. What’s cool, is that GraphQL also allows clients to ask a server for information about its schema, in a move called &lt;strong&gt;introspection&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GraphQL Introspection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The designers of a schema obviously know what fields are available, but clients can query GraphQL using the &lt;code&gt;__schema&lt;/code&gt; meta field available on the root type of a Query to find out too. This is a powerful technique that can be used to provide many interesting, useful features.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// **** Introspection Query and Return Information ****
query{ 
  __schema { 
    types 
    { 
      name 
    }
  }
}
Schema Definition:
type Query {
  director(id: ID!): Director
}
type Director {
  movies: [Movie]
}
type Movie { 
  title: String 
  description: String
}

// Results:
{
  &quot;data&quot;: {
    &quot;__schema&quot;: {
      &quot;types&quot;: [
        {
          &quot;name&quot;: &quot;Query&quot;
        },
        {
          &quot;name&quot;: &quot;Director&quot;
        },
        {
          &quot;name&quot;: &quot;Movie&quot;
        },
        {
          &quot;name&quot;: &quot;ID&quot;
        },
        {
          &quot;name&quot;: &quot;String&quot;
        },
        {
          &quot;name&quot;: &quot;__Schema&quot;
        },
        {
          &quot;name&quot;: &quot;__Type&quot;
        },
        {
          &quot;name&quot;: &quot;__TypeKind&quot;
        },
        {
          &quot;name&quot;: &quot;__Field&quot;
        },
        {
          &quot;name&quot;: &quot;__InputValue&quot;
        },
        {
          &quot;name&quot;: &quot;__EnumValue&quot;
        },
        {
          &quot;name&quot;: &quot;__Directive&quot;
        },
        {
          &quot;name&quot;: &quot;__DirectiveLocation&quot;
        }
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;GraphiQL &amp;amp; GraphQL Playground&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Finally, there are two very useful GraphQL IDEs I’m familiar with. The first is &lt;a href=&quot;https://github.com/graphql/graphiql&quot;&gt;GraphiQL&lt;/a&gt;, which is a JavaScript, in-browser IDE that’s easy to install and use in projects (it also comes pre-bundled with Apollo for even easier use).&lt;/p&gt;
&lt;p&gt;The second is &lt;a href=&quot;https://github.com/graphcool/graphql-playground&quot;&gt;GraphQL Playground&lt;/a&gt;, which can be downloaded as a desktop app or used on its website. It incorporates some of the same components as GraphiQL, but boasts additional features like automatic schema reloading, query history, the ability to work with multiple GraphQL APIs at once, interactive schema documentation and more.&lt;/p&gt;
&lt;p&gt;In short, both are excellent tools, that allow you to debug and try queries on a GraphQL server without having to write queries over curl.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope this helps shed some light on the hot topic that is GraphQL. This is just the tip of the iceberg in terms of what it can do and how it does it, but there are already tons of great resources out there to learn more and start building your own projects using it.&lt;/p&gt;
&lt;p&gt;Personally, I haven’t used it for very long yet, but I’m already enjoying it.&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://graphql.org/&quot;&gt;GraphQL docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.howtographql.com/advanced/0-clients/&quot;&gt;How to GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.apollographql.com/&quot;&gt;Apollo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://facebook.github.io/relay&quot;&gt;Relay&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>graphql</category></item><item><title>JavaScript Array Methods to Make You a Better Developer</title><link>https://www.paigeniedringhaus.com/blog/javascript-array-methods-to-make-you-a-better-developer/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/javascript-array-methods-to-make-you-a-better-developer/</guid><description>Learn to manipulate arrays like a pro.</description><pubDate>Mon, 30 Apr 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/javascript-array-methods/code.jpg&quot; alt=&quot;close up shot of code text editor on computer screen&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Arrays are Such a Useful Data Structure in JavaScript&lt;/h2&gt;
&lt;p&gt;Back when I &lt;strong&gt;&lt;a href=&quot;./how-i-went-from-a-digital-marketer-to-a-software-engineer-in-4-months&quot;&gt;began my new career as a web developer&lt;/a&gt;&lt;/strong&gt;, the fact that I could loop through an array of objects in JavaScript was very cool.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetings = [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

sayHello = (greeting) =&amp;gt; {
    for(let i = 0; i &amp;lt; greeting.length; i++){
        console.log(greeting[i]);
    }
};

sayHello(greetings);
// Hello
// Guten tag
// Salaam
// Hola
// Ciao
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The classic &lt;code&gt;for&lt;/code&gt; loop will always have its place, but there’s a world of other array methods just waiting to be utilized in JavaScript. The right tool for the right job is what I’m constantly trying to keep in mind when solving problems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, having worked at it for almost 2 years, I’ve learned a heck of a lot more, including some much more sophisticated methods for manipulating arrays, which I’d like to share today.&lt;/p&gt;
&lt;p&gt;One more thing I’d like to add before diving in, is that, in general, it tends to be a better practice not to alter existing arrays or objects. If you mutate the original item, you run the risk of unforeseen side effects: wherever else in the code that array or object is referenced, the mutated result could be used instead. This can make finding the root cause of a bug caused by the mutated code more difficult than it needs to be, to say the least.&lt;/p&gt;
&lt;p&gt;Therefore, the methods I cover are known as &lt;a href=&quot;https://en.wikipedia.org/wiki/Pure_function&quot;&gt;pure functions&lt;/a&gt;, because instead of changing the original array, they instead make a copy and make the changes to that copy and return it to the scope outside of the method as a new array. Just something to keep in mind as you read through this article.&lt;/p&gt;
&lt;h3&gt;Map&lt;/h3&gt;
&lt;p&gt;The first method that will come in extremely handy is &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot;&gt;&lt;code&gt;Array.map()&lt;/code&gt;&lt;/a&gt;. The map method takes in an array, and creates a new array with the results of calling a function for every element in that array. It sounds a little complicated but it’s not too bad once you see some examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here’s Array.map() being used on an array of strings:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetings = [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

const sayHelloWorld = (hellos) =&amp;gt; hellos.map(hello =&amp;gt; {
    return `${hello} world`;
});

console.log(greetings);
// [ &apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos; ]

console.log(sayHelloWorld(greetings));

/* [
  &apos;Hello world&apos;,
  &apos;Guten tag world&apos;,
  &apos;Salaam world&apos;,
  &apos;Hola world&apos;,
  &apos;Ciao world&apos;
] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the &lt;code&gt;map&lt;/code&gt; loops over each element in the greetings array and produce a new array called &lt;code&gt;sayHelloWorld&lt;/code&gt; which has each greeting plus the word ‘world’ added to the end. But the original &lt;code&gt;greetings&lt;/code&gt; array remains unchanged, as you can see by the &lt;code&gt;console.log(greetings)&lt;/code&gt; line.&lt;/p&gt;
&lt;p&gt;It can also be applied to complex arrays of objects, not just simple arrays.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And here is Array.map() creating a new array of objects:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetingsByCountry = [{language: &quot;English&quot;, greeting: &quot;Hello&quot;},
                            {language: &quot;German&quot;, greeting: &quot;Guten tag&quot;},
                            {language: &quot;Arabic&quot;, greeting: &quot;Salaam&quot;},
                            {language: &quot;Spanish&quot;, greeting: &quot;Hola&quot;},
                            {language: &quot;Italian&quot;, greeting: &quot;Ciao&quot;}]

const helloByCountry = (hellos) =&amp;gt; hellos.map(obj =&amp;gt; {
    let newObj = {};
    newObj[obj.language] = obj.greeting;
    return newObj;
});

console.log(greetingsByCountry);
/* [
  { language: &apos;English&apos;, greeting: &apos;Hello&apos; },
  { language: &apos;German&apos;, greeting: &apos;Guten tag&apos; },
  { language: &apos;Arabic&apos;, greeting: &apos;Salaam&apos; },
  { language: &apos;Spanish&apos;, greeting: &apos;Hola&apos; },
  { language: &apos;Italian&apos;, greeting: &apos;Ciao&apos; }
] */

// helloByCountry is the new array of reformatted objects
console.log(helloByCountry);
/* [
  { English: &apos;Hello&apos; },
  { German: &apos;Guten tag&apos; },
  { Arabic: &apos;Salaam&apos; },
  { Spanish: &apos;Hola&apos; },
  { Italian: &apos;Ciao&apos; }
] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This array of objects &lt;code&gt;greetingsByCountry&lt;/code&gt; is used by &lt;code&gt;map&lt;/code&gt; to create a new array of objects where the key is &lt;code&gt;language&lt;/code&gt; and the value is &lt;code&gt;greeting&lt;/code&gt;. The original array of objects remains unchanged though. &lt;code&gt;map&lt;/code&gt; is very powerful and useful, and you&apos;ll find yourself reaching for it often.&lt;/p&gt;
&lt;h3&gt;Filter&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter&quot;&gt;&lt;code&gt;Array.filter()&lt;/code&gt;&lt;/a&gt; is another useful method. It works by creating a new array from the original of all the elements in that array that pass a test implemented by the provided function. Let’s take a look at an example of this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Check out how Array.filter() works:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetings = [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

const filteredGreetings = filterParam =&amp;gt; {
    return greetings.filter((hello) =&amp;gt; 
    hello.toLowerCase().indexOf(filterParam.toLowerCase()) &amp;gt; -1
    )
};

// greetings is unchanged
console.log(greetings);
// [ &apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos; ]

// filteredGreetings is a list of strings that contain the letter &apos;a&apos;
console.log(filteredGreetings(&apos;a&apos;));
// [ &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function &lt;code&gt;filteredGreetings&lt;/code&gt; takes in a query parameter (the string of &lt;code&gt;&quot;a&quot;&lt;/code&gt; in this case), and checks through the array of &lt;code&gt;greetings&lt;/code&gt; to see if that letter exists in these words. If it does, it returns the first index in the string in which that letter exists, and adds the word to the new array &lt;code&gt;filteredGreeting&lt;/code&gt;, and if it&apos;s not present in the string, the function returns -1, and it isn&apos;t added to the array.&lt;/p&gt;
&lt;h3&gt;Reduce&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot;&gt;&lt;code&gt;Array.reduce()&lt;/code&gt;&lt;/a&gt; method is powerful: it can be used in a variety of ways ranging from simple to very complex, significantly cutting down on the amount of code needed to achieve results. In essence, &lt;code&gt;reduce&lt;/code&gt; takes in an array, applies a function against something called an &quot;accumulator&quot; (more on that shortly) and each element in the array, and &lt;em&gt;reduces&lt;/em&gt; it down to a single value.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Array.reduce()&lt;/code&gt; can also accept a second, optional, argument called an &quot;initial value&quot;, which is simply the first value to use for the first callback of the function. If it’s not supplied, the first value in the array will be used instead.&lt;/p&gt;
&lt;p&gt;Now an accumulator, as the name suggests, &lt;strong&gt;accumulates&lt;/strong&gt; the value returned by the function each time the function’s callback is invoked. Makes sense, right? If the answer is &quot;no&quot;, it’s totally fine, read on for a few examples to help clear things up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Below is a simple example adding up numbers in an array using Array.reduce().&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const prices = [5.15, 7.55, 3.82, 10.11, 6.79];

const sum = (nums) =&amp;gt; nums.reduce((acc, currentVal) =&amp;gt; {
    return acc + currentVal;
});

const sum2 = (nums) =&amp;gt; nums.reduce((acc, currentVal, currentIndex) =&amp;gt; {
    return acc + currentVal;
}, 10);

// the array of prices is still intact
console.log(prices);
// [ 5.15, 7.55, 3.82, 10.11, 6.79 ]

// sum is its own value
console.log(sum(prices));
// 33.42

// sum2 is its own value
console.log(sum2(prices));
// 43.42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two examples using &lt;code&gt;Array.reduce()&lt;/code&gt; on an array of prices.&lt;/p&gt;
&lt;p&gt;Both functions take in the same array of numbers and run the same function (adding the accumulator to the current value being iterated over), but the second &lt;code&gt;reduce&lt;/code&gt; function &lt;em&gt;also&lt;/em&gt; takes in a second parameter of an initial value.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;sum&lt;/code&gt; function, the array of &lt;code&gt;nums&lt;/code&gt; is taken in, and since no initial value is provided as a second argument to &lt;code&gt;reduce&lt;/code&gt;, the function begins at the index default of 1 (if not specified), and it iterates over each value adding the current index value to the accumulated value with each loop.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;sum2&lt;/code&gt;, an initial value &lt;code&gt;val&lt;/code&gt; is provided as a second parameter to &lt;code&gt;reduce&lt;/code&gt; so the function begins with that value as the first one passed to the callback, and then continues with all the other numbers in the array afterwards. This means that before the internal function even runs, the &lt;code&gt;sum2’&lt;/code&gt;s value begins at 10 then loops through the rest of the array after that.&lt;/p&gt;
&lt;p&gt;In the end, the &lt;code&gt;prices&lt;/code&gt; array remains unchanged, and both &lt;code&gt;sum&lt;/code&gt; and &lt;code&gt;sum2&lt;/code&gt; are their own individual values (numbers), as well.&lt;/p&gt;
&lt;p&gt;Ready for another example? This one involves super heroes just for fun.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This second Array.reduce() example counts the number of times the various Avenger super hero names show up in the array.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const superHeroes = [&apos;Black Widow&apos;, &apos;Iron Man&apos;, &apos;Hawk Eye&apos;, &apos;Hulk&apos;,
 &apos;Thor&apos;, &apos;Iron Man&apos;, &apos;Thor&apos;, &apos;War Machine&apos;, &apos;Captain America&apos;];

const heroCount = heroes =&amp;gt;  heroes.reduce((allHeroes, hero) =&amp;gt; {
    if(hero in allHeroes) {
        allHeroes[hero]++;
    } else {
        allHeroes[hero] = 1;
    } 
    return allHeroes;
}, {});

// the array of Avengers is intact
console.log(superHeroes);
/* [
  &apos;Black Widow&apos;,
  &apos;Iron Man&apos;,
  &apos;Hawk Eye&apos;,
  &apos;Hulk&apos;,
  &apos;Thor&apos;,
  &apos;Iron Man&apos;,
  &apos;Thor&apos;,
  &apos;War Machine&apos;,
  &apos;Captain America&apos;
] */

// the number of times each Avenger is named is a rand new object
console.log(heroCount(superHeroes));
/* {
  &apos;Black Widow&apos;: 1,
  &apos;Iron Man&apos;: 2,
  &apos;Hawk Eye&apos;: 1,
  Hulk: 1,
  Thor: 2,
  &apos;War Machine&apos;: 1,
  &apos;Captain America&apos;: 1
} */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, the &lt;code&gt;superHeroes&lt;/code&gt; array is iterated over and if a hero is not included in the empty object passed as the second param to the reduce function, it creates an object with the key as that hero&apos;s name and the count set to 1. If the hero&apos;s name is already present in the object, it increments the number of times that name is seen in the string until the whole array&apos;s been accounted for.&lt;/p&gt;
&lt;p&gt;This is another example of how &lt;code&gt;reduce&lt;/code&gt; can be used to count the number of times a particular word is referenced in an array. The same kind of logic could also be used on a string, by simply splitting the string apart on spaces and then reducing through the resulting array and tallying up the words.&lt;/p&gt;
&lt;h3&gt;ForEach&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach&quot;&gt;&lt;code&gt;Array.forEach()&lt;/code&gt;&lt;/a&gt; method is a cleaner, more streamlined version of the OG &lt;code&gt;for&lt;/code&gt; loop, but it is not always the right solution. For instance, if you need to loop over an array only until you find something that matches whatever argument it is you’re trying to find and then break out of the loop, &lt;code&gt;forEach()&lt;/code&gt; is not the answer. &lt;code&gt;forEach&lt;/code&gt; will keep going until it has gone through &lt;em&gt;every element&lt;/em&gt; in that array. Period. Regardless of what it finds or doesn’t find.&lt;/p&gt;
&lt;p&gt;If you want to stop a loop early when some value is found, an array method like &lt;code&gt;some&lt;/code&gt; or &lt;code&gt;every&lt;/code&gt; or &lt;code&gt;find&lt;/code&gt; might better suit your needs.&lt;/p&gt;
&lt;p&gt;Another big caveat of &lt;code&gt;forEach&lt;/code&gt; is that it &lt;strong&gt;does not&lt;/strong&gt; return anything. &lt;strong&gt;A &lt;code&gt;forEach&lt;/code&gt; loop will always return a value of &lt;code&gt;undefined&lt;/code&gt;.&lt;/strong&gt; Unlike &lt;code&gt;map&lt;/code&gt; or &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt; is not chainable and does nothing more than run whatever function you&apos;ve defined against each item in the array. A typical use case is to execute side effects at the end of a chain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here&apos;s an Array.forEach() example where we deduplicate a set of greetings.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetings = [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hello&apos;, &apos;Ciao&apos;, &apos;Hello&apos;];

/* a new empty array to take in the modified strings */
const dedupedGreetings = new Set();

const sayHello = (hellos) =&amp;gt; {
    hellos.forEach((hello) =&amp;gt; {
        dedupedGreetings.add(hello);
    }
};

// greetings is unchanged
console.log(greetings);
// [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hello&apos;, &apos;Ciao&apos;]

// the new array has the unique greetings
console.log([...dedupedGreetings]);
// [ &apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Ciao&apos; ] 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;sayHello&lt;/code&gt; function loops over each string in the array and tried to add the &lt;code&gt;hello&lt;/code&gt; to the &lt;code&gt;dedupedGreetings&lt;/code&gt; Set.  Since &lt;code&gt;dedupedGreetings&lt;/code&gt; is declared &lt;em&gt;outside&lt;/em&gt; of the &lt;code&gt;forEach&lt;/code&gt; and we add values to it through our callback function, it works, but this is an example of a side effect. It’s not a perfect equivalent of a  &lt;code&gt;for&lt;/code&gt; loop, but it can certainly be useful in the right scenario.&lt;/p&gt;
&lt;h2&gt;Other Useful Array Methods&lt;/h2&gt;
&lt;p&gt;If there is a situation where you just need to know if an array includes a value, at least once, &lt;code&gt;Array.includes()&lt;/code&gt;, &lt;code&gt;Array.some()&lt;/code&gt; and &lt;code&gt;Array.every()&lt;/code&gt; may be the methods you need.&lt;/p&gt;
&lt;h3&gt;Includes&lt;/h3&gt;
&lt;p&gt;Like the method name indicates, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes&quot;&gt;&lt;code&gt;Array.includes()&lt;/code&gt;&lt;/a&gt; determines whether an array contains some element and returns a &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; boolean.&lt;/p&gt;
&lt;p&gt;If the array includes it more than one time, it won’t indicate it because it will stop iterating as soon as it finds the first value that evaluates to &lt;code&gt;true&lt;/code&gt;. &lt;code&gt;includes&lt;/code&gt; can also take a second parameter as an argument: a search index, which specifies where the search of the array should begin according to the index.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fun fact: &lt;code&gt;includes&lt;/code&gt; was named as such because MooTools had already added a method to the array prototype called &lt;code&gt;Array.contains&lt;/code&gt; which works slightly differently than how &lt;code&gt;includes&lt;/code&gt; works.&lt;/p&gt;
&lt;p&gt;To avoid breaking all the sites currently employing MooTools&apos; &lt;code&gt;contains&lt;/code&gt; method, Ecma International decided to rename their array method to &lt;code&gt;includes&lt;/code&gt; instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Here’s a simple example of Array.includes() at work:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetings = [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

const includesHello = (hellos) =&amp;gt; {
    return hellos.includes(&apos;Hello&apos;);
}

// greetings is unchanged
console.log(greetings);
// [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;]

// returns `true` because `Hello` is in the greetings array
includesHello(greetings);
// true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function just loops over the array and returns &lt;code&gt;true&lt;/code&gt; if the string is contained anywhere within the array.&lt;/p&gt;
&lt;h3&gt;Some&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some&quot;&gt;&lt;code&gt;Array.some()&lt;/code&gt;&lt;/a&gt; is similar to &lt;code&gt;includes&lt;/code&gt;, but instead of just taking in an array, it takes in both an array and the value or function to evaluate the items in the array against.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;some&lt;/code&gt; will iterate through an array and return &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; based on if it finds what it’s looking for. Also like &lt;code&gt;includes&lt;/code&gt;, &lt;code&gt;some&lt;/code&gt; will end its iteration as soon as it finds a value that evaluates to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Check out this example of Array.some():&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetings = [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

const someHello = (hellos, typeOfHello) =&amp;gt; {
    return hellos.some(hello =&amp;gt; hello === typeOfHello);
}

// greetings is unchanged
console.log(greetings);
// [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

// the string `Hola` is present in the greetings array, so this function returns true
someHello(greetings, &apos;Hola&apos;);
// true 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the function &lt;code&gt;someHello&lt;/code&gt;, takes two arguments: the array and the value the function is looking for (&lt;code&gt;typeOfHello&lt;/code&gt;). Since &lt;code&gt;‘Hola’&lt;/code&gt; exists, the function returns &lt;code&gt;true&lt;/code&gt;. When you just need to know if a value is present &lt;em&gt;at all&lt;/em&gt; in an array, &lt;code&gt;some&lt;/code&gt; might be the function you need.&lt;/p&gt;
&lt;h3&gt;Every&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every&quot;&gt;&lt;code&gt;Array.every()&lt;/code&gt;&lt;/a&gt; is like &lt;code&gt;some&lt;/code&gt;, only &lt;em&gt;every element&lt;/em&gt; in the array must pass the test and evaluate to &lt;code&gt;true&lt;/code&gt; for the function to return &lt;code&gt;true&lt;/code&gt; at the end. It’s pretty self-explanatory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here’s an example of Array.every() in action.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const greetings = [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

const everyHelloGreaterThanFour = (hellos) =&amp;gt; {
    return hellos.every(hello =&amp;gt; hello.length &amp;gt;= 4);
}

const everyHelloGreaterThanSix = (hellos) =&amp;gt; {
    return hellos.every(hello =&amp;gt; hello.length &amp;gt;= 6);
}

// greetings is unchanged
console.log(greetings)
// [&apos;Hello&apos;, &apos;Guten tag&apos;, &apos;Salaam&apos;, &apos;Hola&apos;, &apos;Ciao&apos;];

// each greeting string has a length of 4 or more chars
everyHelloGreaterThanFour(greetings);
// true

// each greeting string is not 6 or more chars
everyHelloGreaterThanSiz(greetings);
// false

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first function &lt;code&gt;everyHelloGreaterThanFour&lt;/code&gt;, checks the length of all the strings in the &lt;code&gt;greetings&lt;/code&gt; array and since they’re all greater than or equal to 4, it returns &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second function &lt;code&gt;everyHelloGreaterThanSix&lt;/code&gt;, does the same check on the &lt;code&gt;greetings&lt;/code&gt; array, but with a length greater than or equal to 6, and it returns &lt;code&gt;false&lt;/code&gt; since not all of the strings are at least that length.&lt;/p&gt;
&lt;h3&gt;Sort&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort&quot;&gt;&lt;code&gt;Array.sort()&lt;/code&gt;&lt;/a&gt; is an incredibly useful method, but it is also tricky remembering &lt;em&gt;how&lt;/em&gt; it sorts if a compare function is not supplied, which directs &lt;code&gt;sort&lt;/code&gt; on how to compare and arrange the data.&lt;/p&gt;
&lt;p&gt;Left to its own devices, &lt;code&gt;sort&lt;/code&gt; will convert all elements to strings and compare each element according to its Unicode order (so although “Banana” comes before “cherry” as strings, in a numeric sort, 9 comes before 80, because numbers are converted to strings, “80” comes before “9” in Unicode order).&lt;/p&gt;
&lt;p&gt;We fix this by passing simple functions to tell &lt;code&gt;sort&lt;/code&gt; how to do its job on the values in encounters.&lt;/p&gt;
&lt;p&gt;In general though, this is a very powerful and useful method that I use regularly, I just tend to supply a comparator function (I&apos;ve been bitten many times when I&apos;m lazy and don&apos;t).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This method &lt;em&gt;does&lt;/em&gt; modify the original array, but you’re only sorting it, and not directly altering the data, so there’s less chance of this type of change negatively impacting other blocks of code.&lt;/p&gt;
&lt;p&gt;It can be computationally expensive though, if you&apos;re trying to sort a big enough array of comples objects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Here’s Array.sort() on an array of numbers and on an array of objects.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const nums = [86, 10, 47, 29, 6, 55, 110];

// we tell the nums array how to sort its contents from lowest to highest
nums.sort((a, b) =&amp;gt; a - b);

// nums is sorted, but otherwise unchanged
console.log(nums);
// [6, 10, 29, 47, 55, 86, 110]

const greetingsByCountry = [{language: &quot;English&quot;, greeting: &quot;Hello&quot;},
                            {language: &quot;German&quot;, greeting: &quot;Guten tag&quot;},
                            {language: &quot;Arabic&quot;, greeting: &quot;Salaam&quot;},
                            {language: &quot;Spanish&quot;, greeting: &quot;Hola&quot;},
                            {language: &quot;Italian&quot;, greeting: &quot;Ciao&quot;}]

greetingsByCountry.sort((a, b) =&amp;gt; {
    let langA = a.language.toUpperCase();
    let langB = b.language.toUpperCase();
    if(langA &amp;gt; langB){
        return 1;
    }
    if(langA &amp;lt; langB){
        return -1;
    }
    if(langA === langB){
        return 0;
    }
})

// now greetingsByCountry is sorted alphabetically by language
console.log(greetingsByCountry);
/* [
  { language: &apos;Arabic&apos;, greeting: &apos;Salaam&apos; },
  { language: &apos;English&apos;, greeting: &apos;Hello&apos; },
  { language: &apos;German&apos;, greeting: &apos;Guten tag&apos; },
  { language: &apos;Italian&apos;, greeting: &apos;Ciao&apos; },
  { language: &apos;Spanish&apos;, greeting: &apos;Hola&apos; }
] */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first function sorts the numbers array from low to high. The second function sorts the greetings by various countries by their language value, which first converts all the characters to uppercase, (lowercase would work too), to eliminate the differences in Unicode caused by upper or lower case letters.&lt;/p&gt;
&lt;p&gt;Another nice thing to note is that many of these methods can be chained together, eliminating the need for extra variables, and making your code cleaner.&lt;/p&gt;
&lt;p&gt;And that’s it. JavaScript arrays and their built in methods.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;These are some of the methods I use most often when working with arrays in JavaScript. If you get good with these, you’ll be able manipulate code into doing exactly as you want in no time at all.&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot;&gt;&lt;code&gt;Array.map()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter&quot;&gt;&lt;code&gt;Array.filter()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot;&gt;&lt;code&gt;Array.reduce()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach&quot;&gt;&lt;code&gt;Array.forEach()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes&quot;&gt;&lt;code&gt;Array.includes()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some&quot;&gt;&lt;code&gt;Array.some()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every&quot;&gt;&lt;code&gt;Array.every()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MDN documentation for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort&quot;&gt;&lt;code&gt;Array.sort()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>javascript</category></item><item><title>How I Earned a Full-time Software Engineer Offer in 6 Months</title><link>https://www.paigeniedringhaus.com/blog/How_I_Earned_a_Full-time_Software_Engineer_Offer_in_6_Months/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/How_I_Earned_a_Full-time_Software_Engineer_Offer_in_6_Months/</guid><description>After I graduated from coding bootcamp, my hard work was only just beginning.</description><pubDate>Sun, 15 Apr 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/overhead-work.jpeg&quot; alt=&quot;overhead view of a person working on a computer&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;After I graduated from my 4 month coding bootcamp, I knew the hard work was only just beginning.&lt;/h2&gt;
&lt;p&gt;As I wrote about in my &lt;strong&gt;&lt;a href=&quot;./how-i-went-from-a-digital-marketer-to-a-software-engineer-in-4-months&quot;&gt;previous blog post&lt;/a&gt;&lt;/strong&gt;, just under two years ago I made a decision to pursue the goal of becoming a web developer. I went to coding boot camp &lt;a href=&quot;https://www.digitalcrafts.com&quot;&gt;DigitalCrafts&lt;/a&gt; for 16 weeks, I was overwhelmed with new information on a daily basis, but I made it to end and graduated.&lt;/p&gt;
&lt;p&gt;Not only did I graduate, but just the day before, I earned myself a contract-to-hire position as a Junior Java Developer at The Home Depot. The initial evaluation period was about three months, and, if I did well enough, and proved myself, I might get hired as a full-time Software Engineer.&lt;/p&gt;
&lt;p&gt;Here’s some tips for how I approached this new challenge.&lt;/p&gt;
&lt;h2&gt;1. Aim High&lt;/h2&gt;
&lt;p&gt;Just as my goal had once been making it through coding boot camp, my new goal became getting a job offer — and that’s my first piece of advice:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep setting new goals to help propel you forward — keep reaching higher.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/more-mountains.jpeg&quot; alt=&quot;hiker looking out over many mountains yet to climb&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This view was my new goal (Software Engineer), and after that, perhaps that mountain in the distance, representing my next goal: Senior Software Engineer.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;On my first day at The Home Depot, and for many days after that, I am not ashamed to admit, I had next to no idea what was happening or what I was doing. Of course, I did my best to follow along with my developer pair of the day (The Home Depot subscribes to the pair programming model), but honestly, I don’t feel like I contributed much in my early days.&lt;/p&gt;
&lt;p&gt;Once again, I was doing my best just to keep from drowning in all the new information being thrown at me: The Home Depot’s overall culture (welcoming and inclusive) and way of operating, my team’s way of developing software (TDD, agile and MVP-style with a focus on quality), and the tech stack my team used (which included all kinds of things I hadn’t encountered during boot camp, naturally: like Java, Jenkins and Pivotal Cloud Foundry, just to name a few).&lt;/p&gt;
&lt;h2&gt;2. Work, Work, Work, Work, Work&lt;/h2&gt;
&lt;p&gt;It was exciting and exhausting, and I was certain one day someone would catch on that I didn’t have it all figured out and I didn’t have a CS degree and they’d ask me to leave. Impostor syndrome is real, believe me — I still experience it pretty regularly.&lt;/p&gt;
&lt;p&gt;But here’s my next piece of advice, which is a direct quote from my oldest brother, George:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Work like hell for the first 6 months, listen carefully and learn from everyone you can — from the lowest of the low all the way up. Also, avoid the negative people, don’t engage in gossip and don’t consider any job beneath you if it takes the company forward.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And he was right, even though I was continuously inundated with new material, new ways of doing things and learning a totally new programming language (Java), I needed to do all I could to get up to speed quickly and prove I could add value and was worthy of being hired as an associate.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/late-nights.jpeg&quot; alt=&quot;lone lamp on next to an open laptop late at night&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I was never at the office quite this late, but there have been plenty of nights when I was one of the last people on the floor. I kind of like the peace and quiet actually - it’s easier to concentrate.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Here’s some things that helped me do that:&lt;/p&gt;
&lt;h2&gt;3. Ask Questions &amp;amp; Write Down the Answers&lt;/h2&gt;
&lt;p&gt;I took notes — lots and lots of notes. And I asked questions whenever I could — even if it sounded stupid in my head, I swallowed my pride and asked anyway.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a segue, but one of the most pleasant surprises I encountered as I joined the tech community is that, by and large, people are really willing to help.&lt;/p&gt;
&lt;p&gt;StackOverflow should have been a good indicator of this, but if you have a question and you’re on a Slack channel or with a bunch of other developers, they are almost always willing to share a similar experience they had and help you move forward or figure it out with you.&lt;/p&gt;
&lt;p&gt;It’s really encouraging when you&apos;re struggling to know other people are in it with you and have your back.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anyway, back to my point, I started with a notebook and a pen, then migrated it over to a note on my MacBook. That’s all it is — just a giant list of random notes, that I quickly learned would be invaluable to me.&lt;/p&gt;
&lt;p&gt;Most of the notes are things that are simple enough to do in practice, it’s just remembering how to do them because I don’t need to do them very frequently (since then I&apos;ve also been writing blog posts like these, and I can reference them too when I forget how to do things I&apos;ve done before but it&apos;s been a while 😛).&lt;/p&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;setting up &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ&lt;/a&gt; (my team’s IDE of choice) to run our SpringBoot Java microservices with environmental variables or Lombok annotations, or&lt;/li&gt;
&lt;li&gt;knowing what database tables to query when troubleshooting production issues, or&lt;/li&gt;
&lt;li&gt;having the commands handy for how to increase the logging levels in Pivotal Cloud Foundry applications for greater visibility into why network calls are failing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/taking-written-notes.jpeg&quot; alt=&quot;taking notes in a notepad at a coffee shop&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;No kidding, I (and most of my colleagues) have notebooks and digital note pads where we keep track of stuff that will come in handy in the future. Try it, you’ll be surprised how much you might reference it.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;None of these things are hard to do — but I do them infrequently enough, that it’s really helpful to be able to pull up my note sheet, and just search through it to get what I (or my teammates) need quickly.&lt;/p&gt;
&lt;h2&gt;4. Use the Resources Provided&lt;/h2&gt;
&lt;p&gt;My manager was kind enough to get me access to &lt;a href=&quot;https://www.pluralsight.com/&quot;&gt;Pluralsight&lt;/a&gt;, a fantastic online learning platform, and put together a library of courses covering my team’s tech stack to help me know what to focus on as I ramped up.&lt;/p&gt;
&lt;p&gt;He also gave me a piece of advice I’m still following to this day:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&quot;Take an hour after work every day just to improve your skills: watch some videos, work on a side project, read a book or some blog posts. The point is to take time outside of our day to day to keep improving, and after a while, that ~5 hours of extra time a week will really add up, and help differentiate you from other devs who just work the 9–5.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’ll admit, there have been plenty of days where I’m not motivated enough to do this by the time I get home, but I try to hit that 5 hour mark each week.&lt;/p&gt;
&lt;p&gt;Sometimes it’s sitting down for a few hours on the weekend, sometimes it’s just staying late after work an hour or two and letting the traffic die down at the same time, sometimes it’s sneaking in a little bit of reading or coding during lunch or waiting for builds to finish at work, but I can say I certainly feel like my problem solving skills and coding ability have improved from this kind of continued after-hours learning.&lt;/p&gt;
&lt;p&gt;And as I said above, I got to pair with a different dev on my team practically everyday, all of whom are knowledgeable, talented, capable people, so from them I was able to learn a whole lot.&lt;/p&gt;
&lt;p&gt;I was introduced to lots of new ways of doing things: new ways of approaching problems, new ways of debugging solutions, new ways of managing application architecture and feature writing and testing, so not only could I do something one way, I knew several ways to do it by getting exposure to it from my different pairs.&lt;/p&gt;
&lt;p&gt;I wasn’t afraid to ask questions either, I wanted to understand how we were building our applications and why. Besides combing through the code myself, which was sometimes such a mess of spaghetti that I’d end up very turned around and unsure of where to go next, I could ask my pair what this was doing or that was referencing or why the file structure was set up this way and get an answer I could understand and process.&lt;/p&gt;
&lt;p&gt;The Slack channels for the entire Home Depot IT department are active and full of helpful, smart people I could also turn to when I needed assistance.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/puzzle-pieces.jpeg&quot; alt=&quot;taking notes in a notepad at a coffee shop&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The resources I have access to helped me put the pieces of many puzzles together.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;5. Prepare to be Uncomfortable — If You’re Not Uncomfortable, You’re Not Growing&lt;/h2&gt;
&lt;p&gt;And here’s my final tip, and I think, what helped push me over the edge from &quot;maybe we should hire her&quot; to &quot;let’s hire her&quot;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Get used to being uncomfortable, get used to putting in extra time and effort, and show that you want to be there and you’re willing to persevere, even when it gets tough.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After about two months of working at The Home Depot, my manager sat me and another new developer who was hired a week before me down and gave us a personal project.&lt;/p&gt;
&lt;p&gt;The goal of the project was to show we had learned enough about a new language (Java) to build a simple application using the same tech stacks our team used, but on our own. This meant an app with AngularJS and Node.js for the frontend, Java, JDBC, Springboot and Gradle for the backend, a MySQL database, and integration tests.&lt;/p&gt;
&lt;p&gt;Ok, I can do this. I wasn’t sure how and I didn’t feel nearly as confident as I might sound, but I was ready to work. He gave us the specs and set us loose. Looking back, I can say without shame, it took me six weeks of after hours and weekend work, Pluralsight video tutorial references and walkthroughs, documentation references, Google and StackOverflow searches and little nudges of encouragement and question answering from my teammates to get there. When I look back at the code now, I cringe — it looks so hacky, but it worked.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/toss-the-laptop.jpeg&quot; alt=&quot;a woman looking defeated in front of her laptop, head in hands&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Yes, sometimes I wanted to toss my laptop out the window, but I didn’t. I stuck it out.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;When both of us showed our manager what we accomplished he said: &quot;Good job, it took you both way too long to get to this point. Now rebuild the backend service using Maven, XML and JPA/Hibernate.&quot; Three weeks (and again many after work hours later), we both had our second version to show him.&lt;/p&gt;
&lt;p&gt;And here’s the kicker — the thing that I think showed him I could go above and beyond what he’d asked and helped prove I should have a permanent spot on his team.&lt;/p&gt;
&lt;p&gt;To give a bit of background, first: our team uses &lt;a href=&quot;https://pivotal.io/platform&quot;&gt;Pivotal Cloud Foundry&lt;/a&gt; to host our apps. It’s a cloud platform like Google Cloud Platform or AWS or Microsoft’s Azure.&lt;/p&gt;
&lt;p&gt;I was very unfamiliar with PCF and how it worked in most every way, but I went ahead and signed up for a free personal account while working on my proejct, PCF gave me some amount of free credit ($70, maybe?), and I pushed my applications (with quite a bit of difficulty since I didn’t really understand what a Java JAR or WAR file was) up to PCF and hosted it in their cloud with a database service attached.&lt;/p&gt;
&lt;p&gt;When I finally showed my manager I’d built the app he’d asked me to, I could proudly do so with a link to the live site, not just my &lt;code&gt;localhost&lt;/code&gt; site on my laptop. That, in my mind, is one of the reasons I think I was made an offer to join The Home Depot as a Software Engineer, just about a month later.&lt;/p&gt;
&lt;p&gt;That project was by no means easy, but I learned so much from it (including that I learn best by doing, not by watching somebody else do it, but by physically opening an IDE and typing in the code — and fixing it when I make a typo and the console errors out), and I stuck it out, even though there were times I banged my head against the wall and wanted to just quit. I showed my grit and my desire to be there and succeed.&lt;/p&gt;
&lt;p&gt;In the end, about 5 months after I began as a contract-to-hire with The Home Depot, I was rewarded with a full-time offer to become a Software Engineer, and I couldn’t have been more thrilled.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/relieved-success.jpeg&quot; alt=&quot;a man with an elated smile and fists balled in success&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is close to the amount of joy and accomplishment I was feeling upon receiving that full-time offer.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;In Conclusion, Just Keep at It&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If you’re in your first developer job, or you’re still hunting for it, all I can say is: keep at it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My advice in TL:DR form:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Aim for jobs asking for more experience than you have,&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;work your butt off — you’ll be amazed at the changes you see in yourself,&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;don’t feel dumb for asking questions, but write down the answers so you won’t have to ask a second time,&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;use any and all resources at your disposal (including your coworkers),&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;prepare to continue being uncomfortable — it means you’re doing it right and you’re growing.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&apos;s cliché, but... if I could go from zero coding experience to a full time job offer and a title as a Software Engineer less than a year later, there’s no reason anyone else can’t too.&lt;/p&gt;
&lt;p&gt;You got this.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/full-time-software-engineer-offer/glasses.jpeg&quot; alt=&quot;pair of glasses resting on a desk in front of screens filled with code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;References &amp;amp; Further Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Definition of &lt;a href=&quot;https://en.wikipedia.org/wiki/Pair_programming&quot;&gt;pair programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Agile_software_development&quot;&gt;Agile software development methodology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://12factor.net/&quot;&gt;12 Factor App software development methodology&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>advice</category><category>career change</category></item><item><title>How I Went From a Digital Marketer to a Software Engineer in 4 Months</title><link>https://www.paigeniedringhaus.com/blog/how-i-went-from-a-digital-marketer-to-a-software-engineer-in-4-months/</link><guid isPermaLink="true">https://www.paigeniedringhaus.com/blog/how-i-went-from-a-digital-marketer-to-a-software-engineer-in-4-months/</guid><description>Like many people, my career path to web development wasn&apos;t a straight line.</description><pubDate>Sun, 08 Apr 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/laptop-1.jpeg&quot; alt=&quot;laptop close up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Like more and more folks today, my journey to web development was not linear.&lt;/h2&gt;
&lt;p&gt;I don’t have the traditional CS background, I haven’t tinkered with computers since the age of 15, and if you’d told me 10 years ago when I graduated from high school that today, I’d be a Software Engineer for a Fortune 50 company, I would have looked back and asked what that even meant.&lt;/p&gt;
&lt;h3&gt;So what changed?&lt;/h3&gt;
&lt;p&gt;Well, to be perfectly honest, a lot. Almost three years ago now, I was working as a digital marketer for a small advertising agency in Atlanta. I did things like content strategy, social media strategy, branding and copy writing, and I liked it. The creativity, the challenge of making something from nothing, the variety of things to keep in mind.&lt;/p&gt;
&lt;p&gt;What I didn’t like was the fact that we’d come up with incredible ideas for our clients — ideas that really pushed the envelope creatively, and then the clients either wouldn’t take our advice (in which case, why did they hire an advertising agency?), or they would approve our pitches and I would hand off my ideas to our teams of talented creatives and developers. I’d manage the project and the clients, and the graphic designers and developers would work their magic and come back with an amazing website.&lt;/p&gt;
&lt;p&gt;And more than anything I wanted to know how they did it. How could they make something so cool with nothing but a computer and an idea? So besides asking questions whenever I could (and not really understanding the answers I got about things like Magento and APIs and landing pages), I started doing some self-learning on the basics of HTML, CSS and JavaScript with the help of &lt;a href=&quot;https://www.codecademy.com/&quot;&gt;CodeAcademy&lt;/a&gt; and &lt;a href=&quot;https://teamtreehouse.com/&quot;&gt;Treehouse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It opened up a whole new world to me, a world where I could build the ideas I came up with myself, but I had a hard time connecting the dots from the exercises I was doing online to seeing how that translated to a real, live website others could use. Since I was also working full-time then, I didn’t have much extra time to try and go further either.&lt;/p&gt;
&lt;p&gt;Then, my world shifted. One Friday afternoon, my boss walked me down the street to a coffee shop and said without much preamble that that was my last day. I hadn’t done anything wrong, but they didn’t have enough marketing work to justify keeping me, so they were letting me go. I was stunned, and the following Monday, set adrift for the first time in my life, without a plan of what was happening next.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/mushroom-cloud.jpeg&quot; alt=&quot;mushroom cloud image post atom bomb drop&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;It wasn’t quite this dramatic, but it felt that way right after I was let go. I was in shock and hadn’t truly processed what had just happened.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Taking a leap&lt;/h3&gt;
&lt;p&gt;For a few weeks, I struggled with deciding what I wanted to do next — pursue a new job in marketing, or go back to school for web development, and stop wondering for the rest of my life: what if I’d just tried it?&lt;/p&gt;
&lt;p&gt;After some heartfelt conversations with my family and friends, my then fiancé (now husband) and a business acquaintance I’d made recently, but whose straightforward, no nonsense advice, immediately made me trust her, I decided to go for it.&lt;/p&gt;
&lt;p&gt;I’d give this web development thing a fair shot, and go back to school for it. What did I have to lose? If I didn’t love it, at least I’d have new skills coding skills to add to my resume, which definitely couldn’t hurt in the marketing world.&lt;/p&gt;
&lt;p&gt;I made the decision to go to one of the coding bootcamps in my city of Atlanta. The next thing to do was decide which one: there were three main bootcamps at the time, and after interviewing with each one, I chose &lt;a href=&quot;https://www.digitalcrafts.com/&quot;&gt;DigitalCrafts&lt;/a&gt;. At the time, they were relatively new to the scene and I could tell by talking to the founders and their chief instructor, they were really invested in making sure their students succeeded. And for me personally, I wanted a program and curriculum to help me fast track this new career — in four months I’d either sink or swim. Period.&lt;/p&gt;
&lt;p&gt;In July of 2016, I joined DigitalCrafts’ third cohort of full-stack web-development.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/compass.jpeg&quot; alt=&quot;holding a compass in front of the sea&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I had a plan. I wasn’t sure where I’d wind up at the end of all this, but I’d made a decision.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;The struggle was real&lt;/h3&gt;
&lt;p&gt;For 16 weeks, it felt like a fire hose of new information had been turned towards me, and my goal was to stay above water until the end.&lt;/p&gt;
&lt;p&gt;This was, hands down, the hardest thing I’d ever done in my life. Five years prior, I graduated from Emory University’s Goizueta Business School, which I considered no small feat, but it paled in comparison to the demanding pace and curriculum at DC.&lt;/p&gt;
&lt;p&gt;To put it in perspective: our cohort began with 15 students, by week 8 (halfway through), we were down to 12.&lt;/p&gt;
&lt;p&gt;During that time we learned so much: HTML, CSS, JavaScript, jQuery, AngularJS, NodeJS, Express, Python, Flask, Socket.io, MySQL, MongoDB, Git, Github the list goes on, but more than that, we learned how to learn and think like developers.&lt;/p&gt;
&lt;p&gt;I know it sounds cliché, but learning to break down problems (and projects) into smaller, more manageable chunks, how to ask the right questions to overcome obstacles, and how to persevere, even when it seemed like I could learn no more or figure out why my code wasn’t doing what I wanted.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/highs-and-lows.png&quot; alt=&quot;the ups and downs of learning to code at bootcamp: high highs and low lows over and over&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;This is specific to the framework of AngularJS, but it’s accurate for how I felt going through boot camp: awesome highs when I learned something new and got it to work, mingled with lows as new material was tossed at me and I hadn’t figured it out yet.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;I won’t lie, there were days I came home after 10 hours at school and cried in my husband’s arms, feeling like an impostor, feeling like maybe I wasn’t cut out to be a developer, feeling like I couldn’t do it, but day after day, I went back and I kept trying.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This is critical: just keep trying. Fail and try again. Trust me.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/what-developer.jpeg&quot; alt=&quot;developer wondering what in the world his code is doing&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;A reenactment of many, many moments during bootcamp. This guy is all of us many times when programming.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Preparation is key&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;If there’s one thing DigitalCrafts taught me well, it was the importance of my story and my digital presences.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most of my classmates and I had next to no prior development experience, so telling my story of how I’d come to web development and why I deserved to be given the time of day was paramount. This included things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;making sure my resume highlighted important qualities such as my ability to learn new technologies and concepts quickly,&lt;/li&gt;
&lt;li&gt;showcasing projects that demonstrated my ability to build working applications with a variety of development languages on my portfolio site,&lt;/li&gt;
&lt;li&gt;linking up my Github and keeping the code clean for interested parties to see my skills, and&lt;/li&gt;
&lt;li&gt;practicing coding and whiteboard interviewing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All so I’d be ready, when it came time for the real thing.&lt;/p&gt;
&lt;p&gt;I spent hours poring over my code, practicing coding challenges, reworking my resume and tweaking my portfolio until it was just perfect (on both mobile and desktop, of course — thank you, Bootstrap). And then came the nerve-wracking part, actually applying for web development jobs.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/whiteboard.jpeg&quot; alt=&quot;a programmer diagramming pseudo-code on a whiteboard&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The hallmarks of programming: whiteboards, dry erase markers and tons of pseudo-code and diagrams. Practice at this kind of stuff makes perfect (and helps you prepare for when the real test comes).&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Making opportunities happen&lt;/h3&gt;
&lt;p&gt;About three-quarters of the way through my bootcamp, I was contacted by a tech recruiter, and we connected really well.&lt;/p&gt;
&lt;p&gt;I told him I was looking for a company where I could have a positive impact and work with really good developers, people more experienced than myself, people I could learn from - basically the people I wanted to become one day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One of my biggest takeaways from my coding bootcamp was just how much I didn’t know, and my desire to improve and keep learning new things helped me decide, at least initially, that a great way to do that would be with lots of talented devs to learn from.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;He had me send him my resume, and I dove back into learning as much as I could during my bootcamp.&lt;/p&gt;
&lt;p&gt;In the meantime, I’d been applying to any and all junior development jobs I came across on my own, as well. I had daily job alerts sent to my inbox from &lt;a href=&quot;https://www.dice.com/&quot;&gt;Dice&lt;/a&gt;, &lt;a href=&quot;https://www.indeed.com/&quot;&gt;Indeed&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a href=&quot;https://www.glassdoor.com/index.htm&quot;&gt;Glassdoor&lt;/a&gt;, I was on the Atlanta tech Slack channel &lt;a href=&quot;https://tech404.io/&quot;&gt;Tech404&lt;/a&gt;, and I was attending local meet ups like the &lt;a href=&quot;https://www.meetup.com/AtlantaJavaScript/&quot;&gt;Atlanta JavaScript Meetup&lt;/a&gt; and the &lt;a href=&quot;https://www.meetup.com/python-atlanta/&quot;&gt;PyAtl: Altanta Python Programmers Meetup&lt;/a&gt; to meet more people in my local tech community.&lt;/p&gt;
&lt;p&gt;From past experience, I knew networking would be key to getting a job — the more people I had a chance to meet, the more I could show them I might be just the excited new developer they needed for their team.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/tech-networking.jpeg&quot; alt=&quot;programmers sitting together at an outdoor cafe&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;Meetups are a great way to meet some really cool, super smart people in the tech industry.
&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;To stay organized, I kept a spreadsheet of all the jobs I’d applied for, what date I’d applied on, if I’d received a response (both yeses and nos), contact details (if I could get them), any other extra info worth remembering, and links to the job posting.&lt;/p&gt;
&lt;p&gt;I also had a folder full of customized cover letters I included with all my job applications to show my interest, why I’d be an excellent fit for the job and how I could contribute on day one.&lt;/p&gt;
&lt;h3&gt;The call&lt;/h3&gt;
&lt;p&gt;Two weeks before I was due to graduate, the recruiter I’d spoken to before called me back.&lt;/p&gt;
&lt;p&gt;He’d put my resume in front of a hiring manager at The Home Depot and wanted to set up a phone screen. I was nervous, but I said yes and a few days later we talked. I don’t remember exactly what he asked me — looking back, we discussed pretty simple technical questions about things like databases and JavaScript, projects I’d built and obstacles I’d overcome during the process, and behavioral questions about how I’d handle different situations with coworkers. Overall, I felt ok after the call ended. When the recruiter called me back later that day, he told me whatever I’d said, I’d knocked it out of the park, they wanted to bring me in for an in-person interview!&lt;/p&gt;
&lt;p&gt;The day before I graduated, I went in for my in-person interview. I was nervous and didn’t know what to expect. It lasted four hours. The first hour and a half was with the hiring manager I’d spoken to on the phone, we did some simple white boarding questions, he asked me some more questions about how I would approach different challenges (both technical and behavioral), then I was paired up with one of the senior developers on his team and we worked on solving a problem for the application the team was building.&lt;/p&gt;
&lt;p&gt;Luckily for me, the application’s UI was being built using AngularJS, which I’d learned in bootcamp, so I was able to figure it out (with some help from my pair). At the end of the interview he showed me the code he’d written before I arrived to solve the same problem and compared it to my code, and they were almost identical! Wow, that felt good.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/pairing.jpeg&quot; alt=&quot;two programmers looking at code together&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;I didn’t feel nearly as cool and collected as these two look. I was trying not to freeze up and just make the code work.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I walked out just after noon feeling pretty good about my interview performance and very excited about how the company viewed development and improving its current technologies.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here’s a tip I learned even before I graduated from college about job hunting: during the interview, I get the name and email address of any one I speak to.&lt;/p&gt;
&lt;p&gt;That way, right after the interview, I can send a thank you email reiterating how much I appreciated the time and consideration, touching on something we discussed and saying how much I’d like to be part of their team (as long as it’s really how I feel).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It may sound like overkill, but I also make a point to send a handwritten thank you note — they’re so rare nowadays and I know it can make a difference (people I’ve been hired by in the past have told me so, after the fact).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bottom line: show them you want to be there, the right attitude and eagerness about something definitely makes a difference.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;What happened&lt;/h3&gt;
&lt;p&gt;In this particular case, I didn’t even have time to send anything beyond thank you emails, that same afternoon I got a call from my recruiter that The Home Depot wanted to extend me an offer to join as a Junior Java Developer. And I was thrilled to accept it (I also sent handwritten thank you notes too, saying how excited I was for the opportunity they were giving me).&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/joy.jpeg&quot; alt=&quot;woman jumping for joy overlooking a valley of mountain ranges before her&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;The view wasn’t this great, but this is exactly how I felt when I got the offer.&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And from there, I began the next hardest thing I’d ever done, growing into my first developer role. But that’s for another post.&lt;/p&gt;
&lt;h2&gt;The final stats&lt;/h2&gt;
&lt;p&gt;To give a quick breakdown of my journey, here’s what I did by the numbers.&lt;/p&gt;
&lt;p&gt;I joined DigitalCrafts for a 4 month, immersive bootcamp, covering both front and backend technologies. This was about 680 hours of in-classroom experience and an untold amount of time after class and on weekends when I was fixing projects, polishing up my website and doing whatever I could to learn more.&lt;/p&gt;
&lt;p&gt;In the space of about 40 days before I graduated, I applied for 53 jobs, received 10 email rejections, conducted 6 phone interviews, went in for 3 in-person interviews and was extended 1 full-time job offer.&lt;/p&gt;
&lt;p&gt;Just 16 short weeks ago, I’d known next to nothing about how web development worked, and by the end I had full-stack projects and a full-time development job offer.&lt;/p&gt;
&lt;p&gt;I am extremely lucky to have a supportive spouse and family, who made it possible for me to fully dedicate myself to making this transition to web development happen, but believe me, if I can do it, you can too.&lt;/p&gt;
&lt;p&gt;Now get to coding!&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/digital-marketer-software-engineer/you-can-do-it-success-kid.jpeg&quot; alt=&quot;success kid with the text &amp;quot;You can do it!&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
</content:encoded><category>advice</category><category>career change</category></item></channel></rss>