<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Brian Swank</title>
    <description>The latest articles on DEV Community by Brian Swank (@briansw).</description>
    <link>https://dev.to/briansw</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F17877%2F5c50b7d1-2a7f-4e43-9890-554b20aa6fe4.JPG</url>
      <title>DEV Community: Brian Swank</title>
      <link>https://dev.to/briansw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/briansw"/>
    <language>en</language>
    <item>
      <title>Validate Data on a Node Server with Joi</title>
      <dc:creator>Brian Swank</dc:creator>
      <pubDate>Thu, 21 May 2020 14:48:48 +0000</pubDate>
      <link>https://dev.to/briansw/validate-data-on-a-node-server-with-joi-53ki</link>
      <guid>https://dev.to/briansw/validate-data-on-a-node-server-with-joi-53ki</guid>
      <description>&lt;p&gt;This was originally published &lt;a href="https://swank.dev/blog/joi-input-validation/"&gt;on my blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Validating user input is an important part of building a secure, high-quality application. Let's take a look at why it's so important and how we can do it using &lt;a href="https://github.com/hapijs/joi"&gt;Joi&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Input Validation 101
&lt;/h2&gt;

&lt;p&gt;As a general rule, you should validate early and often to ensure that you're providing the proper feedback to your users around how to input data.&lt;/p&gt;

&lt;p&gt;Here's an example of a validation strategy for a web application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use proper &lt;code&gt;input&lt;/code&gt; types (e.g. &lt;code&gt;type="text"&lt;/code&gt; for text input, &lt;code&gt;type="url"&lt;/code&gt; for a URL, etc.).&lt;/li&gt;
&lt;li&gt;Validate input on &lt;code&gt;blur&lt;/code&gt; (e.g. use a Regex or similar to ensure the text matches a given pattern).&lt;/li&gt;
&lt;li&gt;Validate input on &lt;code&gt;submit&lt;/code&gt; (e.g. check for proper format and content prior to sending data to a server).&lt;/li&gt;
&lt;li&gt;Validate request &lt;code&gt;body&lt;/code&gt; to ensure everything that was delivered to the server is properly formatted &amp;amp; allowed.&lt;/li&gt;
&lt;li&gt;Use database schemas to ensure you're not adding anything to your data store that shouldn't be there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this tutorial, we'll focus on number 4 – validating as soon as data hits our server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start a Project
&lt;/h2&gt;

&lt;p&gt;We need a Node Server to test with, so we'll start by getting that set up using Hapi. Feel free to use your own app if you have one!&lt;/p&gt;

&lt;p&gt;I chose &lt;a href="https://hapi.dev/"&gt;Hapi&lt;/a&gt; because Joi is a package from the Hapi team, but you can use Joi with any Node framework, including inside serverless functions with no framework, which is where I typically use it!&lt;/p&gt;

&lt;p&gt;Create a new directory with &lt;code&gt;mkdir joi-input-validation&lt;/code&gt;. Then, run the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd joi-input-validation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm init -y&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm i @hapi/hapi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;touch index.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the following to &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Hapi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hapi/hapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Hapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4321&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it works&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// Our POST route for testing&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Node Server running at http://localhost:4321&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Run your Node server with &lt;code&gt;node index.js&lt;/code&gt;. If you visit &lt;a href="http://localhost:4321/"&gt;http://localhost:4321/&lt;/a&gt; you should see "it works" in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make a POST Request
&lt;/h2&gt;

&lt;p&gt;In this example, we'll simulate a successful submission of a username and password by sending it right back to the client as the response.&lt;/p&gt;

&lt;p&gt;Let's make a POST request to our server to test it out using this command: &lt;code&gt;curl -d '{"username":"bs","password":"p@ssword"}' -H "Content-Type: application/json" -X POST http://localhost:4321/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This request should return exactly what you send it: &lt;code&gt;{"username":"bs","password":"p@ssword"}&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Establish Validation Rules
&lt;/h2&gt;

&lt;p&gt;Now that we're set up and submitting data to our server, we can establish some rules for what that data should look like.&lt;/p&gt;

&lt;p&gt;We're asking for a username and a password, so here are some example rules that we might want to enforce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usernames should be at least 4 characters&lt;/li&gt;
&lt;li&gt;Usernames should be no more than 20 characters&lt;/li&gt;
&lt;li&gt;Passwords should be at least 12 characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With those rules as our guide, let's get validating! Just remember, whenever we make a change to our server, we'll need to kill it and start it again using &lt;code&gt;node index.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Validation
&lt;/h2&gt;

&lt;p&gt;Let's install Joi, which is our validation library: &lt;code&gt;npm i @hapi/joi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Don't forget, you can use this package and the following implementation with any (or no) Node framework.&lt;/p&gt;

&lt;p&gt;Next, let's add Joi to our project and define a schema to validate against. Add the following to the beginning of &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Hapi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hapi/hapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hapi/joi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// This object is what our object will need to look like&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// existing code...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have our schema designed and we're enforcing our rules, we need to edit our POST route and use that schema to test our data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="c1"&gt;// Our POST route for testing&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;abortEarly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="c1"&gt;// Data is valid, let's move on!&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Data is invalid, let's tell our user the bad news...&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the code above, we modified our handler to include a &lt;code&gt;try/catch&lt;/code&gt; block in order to either return our valid data or return validation errors. We want to return all validation errors to the client and not just the first one, so we also added an options object to our &lt;code&gt;validateAsync&lt;/code&gt; method with &lt;code&gt;abortEarly&lt;/code&gt; set to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try with invalid input
&lt;/h3&gt;

&lt;p&gt;If we repeat our &lt;code&gt;curl&lt;/code&gt; request, we'll see that we now get an array of errors back. With that information, the client can handle letting the user know exactly what needs to be changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try again with valid input
&lt;/h3&gt;

&lt;p&gt;Now, let's test with some valid input: &lt;code&gt;curl -d '{"username":"bswank","password":"mY_Secur3 p@22wrd"}' -H "Content-Type: application/json" -X POST http://localhost:4321/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's it! You're validating user input with a schema and can extend this concept to accept more complicated and realistic data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check out the all the code from this post in &lt;a href="https://github.com/bswank/joi-input-validation-example"&gt;this GitHub repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;There's way more to Joi than we covered here. Check out &lt;a href="https://hapi.dev/module/joi/"&gt;Joi's docs&lt;/a&gt; to learn more.&lt;/li&gt;
&lt;li&gt;You can use this &lt;a href="https://hapi.dev/module/joi/tester/"&gt;Schema Tester&lt;/a&gt; to learn how to build more complex schemas.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Need some help? Feel free to &lt;a href="https://twitter.com/briansw"&gt;reach out&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>hapi</category>
      <category>joi</category>
    </item>
    <item>
      <title>Implement Fuzzy Text Search with Mongoose</title>
      <dc:creator>Brian Swank</dc:creator>
      <pubDate>Fri, 15 May 2020 19:03:17 +0000</pubDate>
      <link>https://dev.to/briansw/implement-fuzzy-text-search-with-mongoose-1ae1</link>
      <guid>https://dev.to/briansw/implement-fuzzy-text-search-with-mongoose-1ae1</guid>
      <description>&lt;p&gt;There are a bunch of great services that make search really simple, but adding simple fuzzy text search to a Mongoose model is a quick &amp;amp; easy win for when those services are overkill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You'll need a Node project up and running with Mongoose installed and at least one Mongoose model.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Little Bit About Fuzzy Search
&lt;/h2&gt;

&lt;p&gt;Fuzzy search is a standard in search implementations. Users expect it and we should deliver as advocates of our users. A simple text search needs to allow for a small typo, a missing space, and other errors.&lt;/p&gt;

&lt;p&gt;Text search in MongoDB is fairly straight-forward. The &lt;code&gt;$regex&lt;/code&gt; operator allows for partial-text search and the &lt;code&gt;$text&lt;/code&gt; operator makes a full-text search possible, but enabling fuzzy search is a little more complicated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Indexing &amp;amp; n-grams
&lt;/h3&gt;

&lt;p&gt;In order to match something like "uzz" to "fuzzy" we need to break "fuzzy" up into smaller pieces and index it. &lt;code&gt;mongoose-fuzzy-searching&lt;/code&gt; is a simple package that helps us index text fields on our documents with n-grams, allowing us to match smaller text samples to potential matches in our collections – aka fuzzy search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Let's get started by installing the necessary package: &lt;code&gt;npm i mongoose-fuzzy-searching&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With our package installed, we can add it as a plugin to our &lt;code&gt;schema&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mongooseFuzzySearching&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose-fuzzy-searching&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mongooseFuzzySearching&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have the plugin added, any new documents added to our &lt;code&gt;User&lt;/code&gt; collection will have the appropriate text index! In order to use our newly-implemented plugin, all we need to do is call the &lt;code&gt;fuzzySearch&lt;/code&gt; method on our collection instead of &lt;code&gt;find&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../models/User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fuzzySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given an empty query, our &lt;code&gt;fuzzySearch&lt;/code&gt; method will act just like a &lt;code&gt;find&lt;/code&gt; call, returning all relavent results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;To learn more about how to use &lt;code&gt;mongoose-fuzzy-searching&lt;/code&gt; with existing data, it's various options, or with more complex &lt;code&gt;find()&lt;/code&gt; calls, check out the &lt;a href="https://www.npmjs.com/package/mongoose-fuzzy-searching"&gt;readme on NPM&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Need some help? Feel free to &lt;a href="https://twitter.com/briansw"&gt;reach out&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>mongoose</category>
      <category>node</category>
    </item>
    <item>
      <title>Deploy a Vue App to Cloudflare Workers</title>
      <dc:creator>Brian Swank</dc:creator>
      <pubDate>Wed, 13 May 2020 15:07:01 +0000</pubDate>
      <link>https://dev.to/briansw/deploy-a-vue-app-to-cloudflare-workers-col</link>
      <guid>https://dev.to/briansw/deploy-a-vue-app-to-cloudflare-workers-col</guid>
      <description>&lt;p&gt;Cloudflare Workers is probably the easiest way to deploy super fast serverless code to edge locations around the world. In this post, we'll explore what it takes to deploy a Vue application with Workers (hint: it doesn't take much).&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You'll need a &lt;a href="https://cloudflare.com/"&gt;Cloudflare&lt;/a&gt; account with Cloudflare Workers enabled, as well as the &lt;a href="https://workers.cloudflare.com/sites#plans"&gt;Workers Unlimited Plan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was able to test with the free plan so you probably can, too, but I recommend upgrading because it's a great deal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Vue App
&lt;/h2&gt;

&lt;p&gt;To get started, let's create a Vue app via the CLI with &lt;code&gt;npx @vue/cli create vue-on-workers &amp;amp;&amp;amp; cd vue-on-workers&lt;/code&gt;. This will create our app, install our dependencies, and put us right where we need to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Wrangler CLI
&lt;/h2&gt;

&lt;p&gt;Wrangler is a sweet CLI that Cloudflare cooked up for us. Install it with &lt;code&gt;npm i -g @cloudflare/wrangler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this next part, you'll &lt;a href="https://developers.cloudflare.com/api/tokens/create"&gt;need an API Token&lt;/a&gt;. TIP: Use the "Edit Cloudflare Workers" template.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;wrangler config&lt;/code&gt; to get set up using the CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Your Project
&lt;/h2&gt;

&lt;p&gt;With our Vue app created and Wrangler all config'd up, we can now turn our Vue project into a Wrangler project by running &lt;code&gt;wrangler init --site&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You may notice your project now has a &lt;code&gt;wrangler.toml&lt;/code&gt; file as well as an additional directory, called &lt;code&gt;workers-site&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, all that's left to do is add a couple things to the config file. Add your &lt;code&gt;account_id&lt;/code&gt; (can be found in the bottom-right of your Cloudflare dashboard) and ensure &lt;code&gt;bucket&lt;/code&gt; is set to the &lt;code&gt;dist&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"vue-on-workers"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"webpack"&lt;/span&gt;
&lt;span class="py"&gt;account_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"add_your_account_id"&lt;/span&gt; &lt;span class="c"&gt;# HERE&lt;/span&gt;
&lt;span class="py"&gt;workers_dev&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;route&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
&lt;span class="py"&gt;zone_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

&lt;span class="nn"&gt;[site]&lt;/span&gt;
    &lt;span class="py"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dist"&lt;/span&gt; &lt;span class="c"&gt;# AND HERE&lt;/span&gt;
    &lt;span class="py"&gt;entry-point&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"workers-site"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy to Workers
&lt;/h2&gt;

&lt;p&gt;Once you've set those two items in your &lt;code&gt;wrangler.toml&lt;/code&gt; file, run &lt;code&gt;npm run build &amp;amp;&amp;amp; wrangler publish&lt;/code&gt; to build and deploy!&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;🎉🎉🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Reading &amp;amp; Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There's additional work that needs to be done in order to ensure that Vue Router can handle routing appropriately, which you can read more about in this great &lt;a href="https://stackoverflow.com/questions/58432345/cloudflare-workers-spa-with-vuejs/58439234#58439234"&gt;Stack Overflow answer&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Workers is a great (&lt;em&gt;possibly&lt;/em&gt; better) solution for hosting a statically-generated site, like the ones you get from &lt;a href="https://gridsome.org/"&gt;Gridsome&lt;/a&gt;, &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt;, or &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Read more about &lt;a href="https://workers.cloudflare.com/sites"&gt;hosting a site on Cloudflare Workers&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Need some help? Want to chat? Feel free to &lt;a href="https://twitter.com/briansw"&gt;reach out&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>cloudflare</category>
      <category>workers</category>
    </item>
    <item>
      <title>Publish a Package to NPM</title>
      <dc:creator>Brian Swank</dc:creator>
      <pubDate>Mon, 11 May 2020 14:14:23 +0000</pubDate>
      <link>https://dev.to/briansw/how-to-publish-a-package-to-npm-in-5-minutes-50nh</link>
      <guid>https://dev.to/briansw/how-to-publish-a-package-to-npm-in-5-minutes-50nh</guid>
      <description>&lt;p&gt;Publishing a package to NPM is a quick and efficient way to re-use code across multiple projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we get going, make sure you have an &lt;a href="https://npmjs.org/"&gt;NPM account&lt;/a&gt; and have NPM installed and updated by running &lt;code&gt;npm i -g npm@latest&lt;/code&gt;. You'll also need &lt;a href="https://nodejs.org/en/"&gt;Node&lt;/a&gt; installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Project
&lt;/h2&gt;

&lt;p&gt;Let's get a project up and running. We'll build a small utility to catch and help us fix all our errors.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an empty directory: &lt;code&gt;mkdir super-error-handler &amp;amp;&amp;amp; cd super-error-handler&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generate a &lt;code&gt;package.json&lt;/code&gt;: &lt;code&gt;npm init -y&lt;/code&gt; This will produce some fine defaults.&lt;/li&gt;
&lt;li&gt;Create your utility: &lt;code&gt;touch index.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// super-error-handler/index.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;encodeURI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://stackoverflow.com/search?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a Test Environment
&lt;/h2&gt;

&lt;p&gt;Now that we have some code, let's see if it works!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create another empty directory outside of the original: &lt;code&gt;mkdir test-env &amp;amp;&amp;amp; cd test-env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generate another &lt;code&gt;package.json&lt;/code&gt;: &lt;code&gt;npm init -y&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a symbolic link to your utility so you can require it like other installed modules: &lt;code&gt;npm link /path/to/super-error-handler&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a file to test with: &lt;code&gt;touch index.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test-env/index.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;super-error-handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;testErrorHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;something bad happened&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;testErrorHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have some test code written with our error handler, let's give it a try: run &lt;code&gt;node index.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish to NPM
&lt;/h2&gt;

&lt;p&gt;Almost there! Since every NPM package needs a unique name, you'll need to namespace your package by setting the &lt;code&gt;name&lt;/code&gt; field in your &lt;code&gt;package.json&lt;/code&gt; to &lt;code&gt;@your_npm_username/super-error-handler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, from the &lt;code&gt;super-error-handler&lt;/code&gt; directory, run &lt;code&gt;npm adduser&lt;/code&gt; to authenticate to NPM and then &lt;code&gt;npm publish&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's it! You've published your first NPM package! Head to &lt;a href="https://npmjs.org/packages"&gt;npmjs.org&lt;/a&gt;&lt;br&gt;
to search for it and check it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Tips
&lt;/h2&gt;

&lt;p&gt;Now that your code is available on NPM, here are a few things you can and should do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check out the &lt;a href="https://docs.npmjs.com/files/package.json"&gt;NPM docs&lt;/a&gt; on &lt;code&gt;package.json&lt;/code&gt; fields and fill them in appropriately.&lt;/li&gt;
&lt;li&gt;Create a GitHub repo for your project.&lt;/li&gt;
&lt;li&gt;Add an &lt;code&gt;.npmignore&lt;/code&gt; file to keep some of your repo from being downloaded by users of your module. Here's a great &lt;a href="https://stackoverflow.com/questions/25124844/should-i-npmignore-my-tests"&gt;Stack Overflow question&lt;/a&gt; detailing how you might use one.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;np&lt;/code&gt; to level up your NPM game. It helps to take care of a bunch of additional publishing steps, including creating a release on GitHub. &lt;a href="https://www.npmjs.com/package/np"&gt;Read the docs&lt;/a&gt; on NPM.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Need some help or want to share your newly-uploaded NPM package? Feel free to &lt;a href="https://twitter.com/briansw"&gt;reach out&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Add Serverless Functions to Any Static Site</title>
      <dc:creator>Brian Swank</dc:creator>
      <pubDate>Fri, 08 May 2020 02:34:03 +0000</pubDate>
      <link>https://dev.to/briansw/add-serverless-functions-to-any-static-site-208g</link>
      <guid>https://dev.to/briansw/add-serverless-functions-to-any-static-site-208g</guid>
      <description>&lt;p&gt;Adding just a bit of backend functionality to your Netlify-hosted static site is a perfect use-case for serverless functions. Let's get up and running!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;Whether you want to keep a third-party or proprietary API key or secret from being shipped to the browser, or you just need a little server-side functionality, a serverless function can bridge the gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare Your Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;First, we need to make sure our project is hosted on Netlify.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's connect our project to a Netlify and get set up using &lt;a href="https://www.netlify.com/products/dev/"&gt;Netlify Dev&lt;/a&gt;, which will allow us to test our functions locally:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Netlify account if you don't have one already.&lt;/li&gt;
&lt;li&gt;Ensure you have the Netlify CLI installed locally. You can do this by running &lt;code&gt;npm i -g netlify-cli&lt;/code&gt;. If you run into a permissions issue, check out the &lt;a href="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally"&gt;NPM docs&lt;/a&gt; on the issue.&lt;/li&gt;
&lt;li&gt;Authenticate with Netlify by running &lt;code&gt;netlify login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Initialize your Netlify project by running &lt;code&gt;netlify init&lt;/code&gt;. This will create a site on Netlify and associate your project with that new site.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Configure a Functions Directory
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Now that we're set up with a Netlify project, we need to tell Netlify where to find our functions.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new directory at the root of your project. I typically name this directory something like, &lt;code&gt;/api&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a config file to tell Netlify where to look for your functions:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# netlify.toml&lt;/span&gt;

&lt;span class="nn"&gt;[dev]&lt;/span&gt;
    &lt;span class="err"&gt;functions:&lt;/span&gt; &lt;span class="err"&gt;'/api'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a Function
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Now that Netlify knows where to look for our functions, we can write our first one!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a new file in the &lt;code&gt;/api&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// testy.js&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yup, it works&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test Locally Using Netlify Dev
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;With our function created, let's make sure it works!&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start your dev server by running &lt;code&gt;netlify dev&lt;/code&gt;. You may need to &lt;a href="https://github.com/netlify/cli/blob/master/docs/netlify-dev.md#netlifytoml-dev-block"&gt;choose or configure&lt;/a&gt; a start command.&lt;/li&gt;
&lt;li&gt;Visit &lt;a href="http://localhost:8888/.netlify/functions/testy"&gt;http://localhost:8888/.netlify/functions/testy&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;

&lt;p&gt;If your local function is working correctly, go ahead and deploy it to Netlify with &lt;code&gt;netlify deploy&lt;/code&gt;!&lt;/p&gt;




&lt;p&gt;Thanks for reading! Need some help? Feel free to &lt;a href="https://twitter.com/briansw"&gt;reach out&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>netlify</category>
      <category>serverless</category>
      <category>node</category>
    </item>
    <item>
      <title>Introducing My New Website &amp; the Tech Behind It</title>
      <dc:creator>Brian Swank</dc:creator>
      <pubDate>Sun, 03 May 2020 23:15:39 +0000</pubDate>
      <link>https://dev.to/briansw/introducing-my-new-website-the-tech-behind-it-1npl</link>
      <guid>https://dev.to/briansw/introducing-my-new-website-the-tech-behind-it-1npl</guid>
      <description>&lt;p&gt;[Update – November 30th, 2021]: Just launched a newer version of my personal site built with next.js, but feel free to check out this post, which is still relevant, as well as the GitHub repo mentioned at the end.&lt;/p&gt;

&lt;p&gt;Hey, thanks for reading my very first DEV post in which I write about why and how I finally coded up my own site. This was originally published &lt;a href="https://swank.dev/blog/new-website"&gt;on my blog&lt;/a&gt;, which is on my &lt;a href="https://swank.dev/"&gt;shiny new website&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Where can I find you online?"
&lt;/h2&gt;

&lt;p&gt;If you're a web professional, or aspire to be one, you'll get used to answering this question. Whether it's a job application, an email with a potential client, or your Twitter bio – everyone wants to see your online space and check out your portfolio.&lt;/p&gt;

&lt;p&gt;My LinkedIn profile served me well to help present potential employers with some basic facts about me and my experience, but as soon as I got hired at my current gig, I felt like I was finally at a point where I could ditch it. With some extra time on my hands and a renewed interest in starting to create content to help mentor aspiring developers, I decided it was time to whip something up!&lt;/p&gt;

&lt;h2&gt;
  
  
  Content is Key
&lt;/h2&gt;

&lt;p&gt;I'm not so great at producing content. I tend to agonize over my creative process and then chicken out right before it's time to publish. I re-read and over-think and convince myself that my contribution is redundant or unnecessary.&lt;/p&gt;

&lt;p&gt;I have to keep reminding myself that I've been the grateful recipient of a TON of redundant, imperfect content. Those courses, posts, books, and videos happened to be in the right place at the right time and in the right format presented just the right way for me to consume and understand. I am who I am today because of them, and I hope that what I produce can help someone else in the same way.&lt;/p&gt;

&lt;p&gt;Practically speaking, I decided to keep it simple here. I love reading people's bios and all about the gear they use, so I followed suit and have an introduction and a &lt;a href="https://swank.dev/uses/"&gt;/uses&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overcoming My Design Shortcomings
&lt;/h2&gt;

&lt;p&gt;I typically come up with one or two patterns I like, but then I lack the depth of experience to extrapolate that into a more cohesive and complex design. The end product usually ends up consisting of the same pattern over and over again (which you may notice is the way I built this site).&lt;/p&gt;

&lt;p&gt;One way I tried to overcome my lack of design ability was to follow some &lt;strong&gt;simple design rules&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leave plenty of space (big margins and lots of padding)&lt;/li&gt;
&lt;li&gt;Use a font that's relatively easy to read at both large and small sizes&lt;/li&gt;
&lt;li&gt;Ensure reasonably-high contrast ratios&lt;/li&gt;
&lt;li&gt;Generate a color palette and use that palette throughout (I used &lt;a href="https://coolors.co/"&gt;Coolors.co&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Follow existing design patterns for layout (steal)&lt;/li&gt;
&lt;li&gt;Use CSS Grid and percentage-based-widths throughout to ensure that the site is naturally responsive&lt;/li&gt;
&lt;li&gt;Use CSS custom properties to make viewport-size-related changes super simple&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choosing a Tech Stack
&lt;/h2&gt;

&lt;p&gt;This was pretty simple. I've worked extensively with Vue, so I decided to take a swing at this site with &lt;a href="https://gridsome.org"&gt;Gridsome&lt;/a&gt;, which is the Vue counterpart to React's Gatsby.&lt;/p&gt;

&lt;p&gt;The experience has been great. I am having some issues with Babel transpilation and polyfilling, but the Gridsome community is working on some things related to this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content Management
&lt;/h3&gt;

&lt;p&gt;My page and blog post content is generated from markdown files parsed by &lt;a href="https://gridsome.org/plugins/@gridsome/vue-remark"&gt;&lt;code&gt;@gridsome/vue-remark&lt;/code&gt;&lt;/a&gt;, which gives me the ability to import and use Vue components, other markdown files, or any other data, as well as query the GraphQL layer directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting
&lt;/h3&gt;

&lt;p&gt;It's always a joy to deploy anything to &lt;a href="https://netlify.com/"&gt;Netlify&lt;/a&gt; and this site is no exception. I'm currently using Netlify's DNS management and Analytics products along with hosting for this site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functions
&lt;/h3&gt;

&lt;p&gt;The best way to add just a bit of backend functionality to a static site is a good ol' fashion serverless function. Upon launch, I didn't need any backend functionality, but I do have some plans for a couple I'll add in the future. More to come on this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source
&lt;/h3&gt;

&lt;p&gt;In case you'd like to use this as a boilerplate, submit a PR to fix all my terrible choices, or check out the source for any other reason, you can find it on &lt;a href="https://github.com/bswank/swank.dev"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Hope this was helpful!&lt;/p&gt;

</description>
      <category>netlify</category>
      <category>vue</category>
      <category>gridsome</category>
      <category>jamstack</category>
    </item>
  </channel>
</rss>
