<?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: Chris Williams</title>
    <description>The latest articles on DEV Community by Chris Williams (@scampiuk).</description>
    <link>https://dev.to/scampiuk</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%2F18802%2F110973a9-1bef-47c0-8e70-44667334b803.jpg</url>
      <title>DEV Community: Chris Williams</title>
      <link>https://dev.to/scampiuk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/scampiuk"/>
    <language>en</language>
    <item>
      <title>Ai isn't replacing your job - trust me, we've been here before.</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Sun, 25 Jun 2023 09:20:42 +0000</pubDate>
      <link>https://dev.to/scampiuk/ai-isnt-replacing-your-job-trust-me-weve-been-here-before-149p</link>
      <guid>https://dev.to/scampiuk/ai-isnt-replacing-your-job-trust-me-weve-been-here-before-149p</guid>
      <description>&lt;p&gt;As someone who has weathered several transitions in the technology landscape, I've learned that change, though often intimidating, brings with it a wealth of opportunities.&lt;/p&gt;

&lt;p&gt;I remember the early days of my career in web development when tools like HTML, CSS, and JavaScript frameworks were emerging. Many viewed these as threats to traditional coding roles. I recall the apprehension surrounding Dreamweaver in 1997. There was a sense that using such a tool, rather than coding HTML by hand, was somehow 'cheating.'&lt;/p&gt;

&lt;p&gt;But in reality, these technologies didn't 'steal' jobs. They transformed them. They opened up new avenues for creativity, efficiency, and complexity in our work, enabling us to transition from hard coding to crafting more intricate, interactive sites. &lt;/p&gt;

&lt;p&gt;Today, AI stands in a similar position. It's seen as a potential job-stealer, an automator of tasks that might leave us, developers, out of work. But if my experiences have taught me anything, it's that such innovations don't eradicate roles - they redefine them.&lt;/p&gt;

&lt;p&gt;To the developers early in their careers, I would say this: Embrace these changes. Upskill. Adapt. AI isn’t here to replace you, but to augment your capabilities. Much like HTML, CSS, and JavaScript frameworks, AI will allow you to do more, to innovate further.&lt;/p&gt;

&lt;p&gt;Remember, with every significant tech innovation, new roles emerge. The rise of web development tools gave birth to roles like UI/UX designers and frontend developers. Similarly, AI is creating exciting new positions like AI ethicists, data scientists, and machine learning engineers.&lt;/p&gt;

&lt;p&gt;These technologies also democratise their respective fields. Just as HTML, CSS, and JavaScript have made the web more accessible, AI has the potential to do the same, making expertise more widely available and breaking down barriers.&lt;/p&gt;

&lt;p&gt;Yes, fears are natural with change, but history shows that innovation typically creates as many opportunities as it disrupts. Embracing AI and adapting to its growth could lead to a richer, more diverse tech landscape.&lt;/p&gt;

&lt;p&gt;Lastly, remember this: Technology is a tool designed to augment our capabilities, not replace them. HTML, CSS, JavaScript frameworks, and now AI, all serve to amplify our abilities to create, to solve problems, to make a difference.&lt;/p&gt;

&lt;p&gt;As you shape your future, learn from those who have navigated past transitions. AI, like the web tools before it, is a tool in your hands. Use it wisely to create, innovate, and open up new possibilities for your career.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>developers</category>
      <category>career</category>
      <category>job</category>
    </item>
    <item>
      <title>Moderating Actions on Stream's Activity Feeds service</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Sun, 11 Jul 2021 07:04:26 +0000</pubDate>
      <link>https://dev.to/scampiuk/moderating-actions-on-getstream-io-s-activity-feed-1m4</link>
      <guid>https://dev.to/scampiuk/moderating-actions-on-getstream-io-s-activity-feed-1m4</guid>
      <description>&lt;h6&gt;
  
  
  (headline image by &lt;a href="https://unsplash.com/@purzlbaum"&gt;Claudio Schwarz&lt;/a&gt;)
&lt;/h6&gt;




&lt;blockquote&gt;
&lt;p&gt;This is for &lt;a href="https://getstream.io/activity-feeds/"&gt;Stream&lt;/a&gt;, or getstream.io's Activity Feeds service. This block is here so people who are searching for getstream.io can find it!  I'm never sure how to referr to the company, as just calling it 'Stream' when discussing it in a development setting gets very confusing :(&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  INTRO
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we're going to talk about, and solve, a problem with &lt;a href="https://getstream.io/activity-feeds/"&gt;Stream's Activity Feeds&lt;/a&gt; product: there's no build-in moderation tools.&lt;/p&gt;

&lt;p&gt;Is that a problem?  Yes, it really is.  Skipping past the problems of the legals of &lt;a href="https://www.dlapiper.com/en/japan/insights/publications/2020/12/ipt-news-q4-2020/whos-responsible-for-content-posted-on-the-internet-section-230-explained/"&gt;who is liable&lt;/a&gt; for &lt;a href="https://www.reuters.com/article/us-britain-tech-regulation-idUSKBN2060Q7"&gt;content on your platform&lt;/a&gt;, there's also compliance for User Generated Content on both &lt;a href="https://developer.apple.com/app-store/review/guidelines/#user-generated-content"&gt;App Store&lt;/a&gt; and &lt;a href="https://support.google.com/googleplay/android-developer/answer/9878810?hl=en-GB&amp;amp;ref_topic=9877466"&gt;Google Play&lt;/a&gt; to consider.  &lt;/p&gt;

&lt;p&gt;We're going to look at setting up your Activity Feed Types so we can create a firewall between Activities being added, and those being viewable.  We're also going to talk about a way of handing image moderation: AWS's &lt;a href="https://aws.amazon.com/rekognition/"&gt;Rekognition&lt;/a&gt; service.&lt;/p&gt;

&lt;p&gt;This isn't a tutorial on how to implement this, rather a guide on how to set up your Activity Feed Types so we can add moderation and other automation. &lt;/p&gt;

&lt;p&gt;I'll cover the practical 'how-do' in another article (and I'll update this once I've written it!)&lt;/p&gt;

&lt;h2&gt;
  
  
  WHAT YOU'LL NEED
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AWS account, and some basic understanding of what SQS is, and what Lambdas are,&lt;/li&gt;
&lt;li&gt;Getstream account, and some knowedge of the Activity Feed service&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AWS REKOGNITION
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html"&gt;AWS Rekognition&lt;/a&gt; is a machine learning tool that Amazon have trained over billions of images and videos, and we can use that power just by calling a simple API. By using this, we don't have to have people looking at each image manually, and have to deal with all the problems that come with that.  &lt;/p&gt;

&lt;p&gt;You'll want to be using the '&lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/procedure-moderate-images.html"&gt;Detecting Inappropriate Images&lt;/a&gt;' part.&lt;/p&gt;

&lt;p&gt;We need to upload the image to AWS Rekognition (which is built into the AWS SDK), and it will return a series of Labels, along with a Confidence (a number on how sure AWS is that this Label is right).  Then we can use those to determine if the images need to be hidden or not.&lt;/p&gt;

&lt;p&gt;You can see in the AWS Rekognition documentation the list of Labels you can get back, and from that you can choose what kind of images you do and don't want on your platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  STREAM
&lt;/h2&gt;

&lt;p&gt;Getting the Activity Feeds Types right here is the key.  We need to create a gap between the Activities created by users, and those activites being seen by other users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Activity Feed Type setup
&lt;/h3&gt;

&lt;p&gt;Imagine we want a platform where we have content creators and content viewers.  You could set it so each Creator has a &lt;code&gt;timeline&lt;/code&gt; feed, and each Viewer has a &lt;code&gt;notification&lt;/code&gt; feed that is subscribed to one or many Creator's Timelines.   &lt;/p&gt;

&lt;p&gt;Something like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5HiPLp4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gtq4pdnxuwdtli7qy8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5HiPLp4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gtq4pdnxuwdtli7qy8s.png" alt="image" width="567" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any time &lt;code&gt;creator-0001&lt;/code&gt; publishes to their &lt;code&gt;timeline&lt;/code&gt; feed, it will appear in the &lt;code&gt;notification&lt;/code&gt; feed for &lt;code&gt;viewer-9876&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You can see here, there is no way we can stop this happening.  If &lt;code&gt;creator-0001&lt;/code&gt; posts something we don't want, we're in trouble.&lt;/p&gt;

&lt;h3&gt;
  
  
  Moderation Activity Feed Type setup
&lt;/h3&gt;

&lt;p&gt;The solution is to create some kind of break between Creator publishing something, and the Viewer seeing it before we've had a chance to moderate it. &lt;/p&gt;

&lt;p&gt;Stream provide a way of doing this.  For each Activity Feed Type you can it up to puiblish the Activity to an SQS queue, so we can grab it from the queue, look at it, then publish it somehow.&lt;/p&gt;

&lt;p&gt;Something like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xx9ZxEfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hidqgmumg5ojay9gzuvk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xx9ZxEfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hidqgmumg5ojay9gzuvk.png" alt="image" width="709" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This method allows us to &lt;em&gt;code the link&lt;/em&gt; between the &lt;code&gt;unpublished_timeline:creator-0001&lt;/code&gt; and the &lt;code&gt;published_timeline:creator-0001&lt;/code&gt; feeds, and using AWS Rekognition we can inject image moderation into that step.  In fact, with this step, we can do any kind of moderation or action based on the content published we want.&lt;/p&gt;

&lt;p&gt;Your Lambda should take the code from the SQS queue (something Stream have &lt;a href="https://getstream.io/blog/using-the-stream-real-time-firehose-with-aws-sqs-lambda-and-sns/"&gt;written a tutorial on&lt;/a&gt;), and use the AWS SDK to send the image to Rekogntion.  Once you have your Labels back, you can then choose to ''copy'' the activity from one feed to another.&lt;/p&gt;

&lt;p&gt;There isn't a way of copying an Activity from one feed to another that I know off, so you have to re-create the Activity on the &lt;code&gt;published&lt;/code&gt; feed, and remove it from the &lt;code&gt;unpublished&lt;/code&gt; feed.. if someone from Stream knows a better way to do this, I would appreciate you letting me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  CONCLUSION
&lt;/h2&gt;

&lt;p&gt;With this set up, you will be able to perform any kind of moderation you wish on any Action published on your platform.  Using Lambdas and SQS means your solution will scale with your demands, and you can use this model to build in any kind of events.&lt;/p&gt;

&lt;p&gt;What about using SQS feeds to manage push notifications, or emails to users when content is published? It's also a good way of getting data &lt;em&gt;out&lt;/em&gt; of getstream into something you can look at and use without over-consuming your API usage.&lt;/p&gt;

&lt;p&gt;I would be super interested in knowing if this solution works for you, or how you have approached this problem! Please reach out on Twitter to &lt;a href="https://twitter.com/scampiuk"&gt;@scampiuk&lt;/a&gt; and let me know how it goes. &lt;/p&gt;

</description>
      <category>getstreamio</category>
      <category>aws</category>
      <category>lambda</category>
      <category>compliance</category>
    </item>
    <item>
      <title>A rather pointless performance test for Node</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Sun, 11 Oct 2020 21:07:40 +0000</pubDate>
      <link>https://dev.to/scampiuk/a-rather-pointless-performance-test-for-node-19pa</link>
      <guid>https://dev.to/scampiuk/a-rather-pointless-performance-test-for-node-19pa</guid>
      <description>&lt;p&gt;So today I performance a rather pointless performance test.&lt;/p&gt;

&lt;p&gt;I was wondering what difference the version of Node makes to simple performance tests: I would expect that the newer the version, the faster (in requests per second) it would be. &lt;/p&gt;

&lt;p&gt;Because it should be, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Test
&lt;/h2&gt;

&lt;p&gt;I copied-and-pasted a simple hello-world script...&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&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;http&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;hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&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;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&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;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&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;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hostname&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server running at http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hostname&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="nx"&gt;port&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;p&gt;and then installed Apache Bench, or &lt;code&gt;ab&lt;/code&gt; to hammer it:&lt;br&gt;
&lt;code&gt;ab -c500 -n100000  http://localhost:3000/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But how to get the different versions? Node version management is a pain on Linux, it's a nightmare on Macs, and I've not tried it on Windows but I can't imagine that it's fun.&lt;/p&gt;

&lt;p&gt;Here's the actual useful bit of this, an app called &lt;code&gt;n&lt;/code&gt;.  Just install it via &lt;code&gt;sudo npm install -g n&lt;/code&gt; and you've suddenly got a very powerful tool for switching node versions.&lt;/p&gt;

&lt;p&gt;So, if you want the LTS version?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt; % sudo n lts

  installing : node-v12.19.0
       mkdir : /usr/local/n/versions/node/12.19.0
       fetch : https://nodejs.org/dist/v12.19.0/node-v12.19.0-linux-x64.tar.xz
   installed : v12.19.0 (with npm 6.14.8)

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results
&lt;/h2&gt;

&lt;p&gt;Each test was ran three times, because #science, on the latest version of each major version back to Node 5.  No changes where made in the code, or the way the test was run.  This was all ran from my 8th gen i5 laptop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version     req/s  1         2          3
14.13.1      9732.52     9866.98     9894.88
13.14.0     11065.33    12051.36    12247.49
12.19.0      9261.99     9926.34     9869.66
11.15.0     12510.51    13466.22    13783.50
10.22.1     11740.82    11925.83    11727.70
 9.11.2     12702.04    13667.15    13632.01
 8.17.0     10570.54    11579.70    11914.19
 7.10.1     11062.46    11622.44    11650.05
 6.17.1      9236.92     9293.16     9593.82
 5.12.0      8991.05     9790.51     9560.93
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interesting.  From version 5,6, and 7 there's an obvious increase in performance from this simple metric.  After that, into version 8 it starts to flatten out, then something odd happens for 12 and 14. &lt;/p&gt;

&lt;h2&gt;
  
  
  What does this test show us?
&lt;/h2&gt;

&lt;p&gt;It shows us, in this very limited set of hardware, for a non-real-world code example, what the requests per second would be.&lt;/p&gt;

&lt;p&gt;That's about it.  &lt;/p&gt;

&lt;p&gt;From this, we can't tell anything, really, about the major differences between the versions, or what that version would be like to run our code in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  So this is a pointless set of numbers?
&lt;/h2&gt;

&lt;p&gt;No.  Well, yes, but the reason I did this was to try to disprove my bias to the notion that 'latest is greatest'.  To really test if your code is going to be benefit from a bump in version numbers, you're going too have to understand a couple of things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What your code does, and how the new version changes that&lt;/li&gt;
&lt;li&gt;What the performance of your code looks like &lt;em&gt;currently&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;What, other than performance, are the reasons &lt;em&gt;not&lt;/em&gt; to upgrade. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most of the time, if you're moving up between minor and bug versions, &lt;em&gt;security&lt;/em&gt; is your biggest reason to upgrade.  If there is a bug that particularly affects you then that's also another great reason to move up also. &lt;/p&gt;

&lt;h2&gt;
  
  
  So what now?
&lt;/h2&gt;

&lt;p&gt;I'm currently looking at correctly measuring the performance of our production codebases with tools such as Gatling, and tracing the code to find other bottlenecks and memory issues.  Once we understand what the &lt;em&gt;current&lt;/em&gt; numbers are, we can then use those to compare and contrast before future upgrades.&lt;/p&gt;

&lt;p&gt;We have a policy of sticking to the LTS (Long Term Support) version for production code.  This comes after a range of versions of node was being used in different projects in our stack, causing all kinds of problems testing, deploying, developing etc.  The tool &lt;code&gt;n&lt;/code&gt; has helped with quickly changing versions, but if you have a single policy for a version, it makes things a bit simpler.&lt;/p&gt;

&lt;p&gt;Cover image was Image by &lt;a href="https://pixabay.com/users/jackmac34-483877/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=1753611"&gt;jacqueline macou&lt;/a&gt;  from Pixabay &lt;/p&gt;

</description>
      <category>node</category>
      <category>performance</category>
      <category>testing</category>
    </item>
    <item>
      <title>Publishing your OpenAPI documents automatically with NodeJS and Express</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Mon, 13 Jul 2020 11:44:16 +0000</pubDate>
      <link>https://dev.to/scampiuk/publishing-your-openapi-documents-automatically-with-nodejs-and-express-34fn</link>
      <guid>https://dev.to/scampiuk/publishing-your-openapi-documents-automatically-with-nodejs-and-express-34fn</guid>
      <description>&lt;p&gt;Writing that OpenAPI spec document is one thing, but how can you make sure it's viewable to everyone who needs it? &lt;/p&gt;

&lt;p&gt;There are plenty of commercial tools for sharing API information around (&lt;a href="https://www.postman.com/"&gt;https://www.postman.com/&lt;/a&gt; is a great example), but what's a difficult thing to do if your API is for public consumption.&lt;/p&gt;

&lt;p&gt;You could maintain a copy on your website somewhere?  Make the OpenAPI spec available so people can copy-paste to &lt;a href="https://editor.swagger.io/"&gt;https://editor.swagger.io/&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;We've tried both and found that it's hard work to maintain an up-to-date version without doing some additional automation on deployment.&lt;/p&gt;

&lt;p&gt;Training people to check the file from the repo, copy-paste it to the online editor.. yea that works as well as you would expect it too.&lt;/p&gt;

&lt;p&gt;Why not just expose the OpenAPI document in a nice format directly on the API? &lt;/p&gt;

&lt;p&gt;The code to do this is really, really simple.&lt;/p&gt;

&lt;p&gt;We're going to use &lt;a href="https://www.npmjs.com/package/swagger-ui-express"&gt;swagger-ui-express&lt;/a&gt; by &lt;a href="https://github.com/scottie1984"&gt;Stephen Scott&lt;/a&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&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;swaggerUi&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;swagger-ui-express&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;router&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;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Router&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;jsYaml&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;js-yaml&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;fs&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;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Our document is YAML, if yours is JSON, then you can just&lt;/span&gt;
    &lt;span class="c1"&gt;// `const openApiDocument = require('spec/openapi.json')`&lt;/span&gt;
    &lt;span class="c1"&gt;// instead.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openApiDocument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsYaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;safeLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spec/petstore.yaml&lt;/span&gt;&lt;span class="dl"&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;utf-8&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;// We can enable the explorer also!&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;explorer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api-docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;swaggerUi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api-docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;swaggerUi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;openApiDocument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;// If you're not using a `router`, you can use&lt;/span&gt;
    &lt;span class="c1"&gt;// `app.use('/api-docs', swaggerUi.serve,&lt;/span&gt;
    &lt;span class="c1"&gt;//    swaggerUi.setup(swaggerDocument, options));&lt;/span&gt;

    &lt;span class="p"&gt;....&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's about it.  Firing up our app and heading over to &lt;code&gt;https://mycool.io/api-docs&lt;/code&gt; and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zh1CTPIx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/7bafkwfmdwn3aabeqv0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zh1CTPIx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/7bafkwfmdwn3aabeqv0f.png" alt="Alt Text" width="800" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, every time you deploy your API, the latest version of the OpenAPI document will be available for all to see. &lt;/p&gt;

&lt;p&gt;Thanks, I hope this helps someone get their API documentation in front of the people who need it - I've also written an article on &lt;a href="https://dev.to/scampiuk/handling-api-validation-with-openapi-swagger-documents-in-nodejs-17d0"&gt;Handling API validation with OpenAPI (Swagger) documents in NodeJS&lt;/a&gt; and &lt;a href="https://dev.to/scampiuk/openapi-swagger-specifications-that-write-your-tests-for-you-sort-of-4kc5"&gt;OpenAPI (Swagger) specifications that write your tests for you (sort of)&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Header image by &lt;a href="https://pixabay.com/photos/adult-break-business-caucasian-2449725/#_=_"&gt;rawpixel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>openapi</category>
      <category>documentation</category>
      <category>express</category>
    </item>
    <item>
      <title>Using Postman's CLI tool for API testing: newman</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Sun, 13 Oct 2019 14:00:11 +0000</pubDate>
      <link>https://dev.to/scampiuk/using-postman-s-cli-tool-for-api-testing-newman-5fn1</link>
      <guid>https://dev.to/scampiuk/using-postman-s-cli-tool-for-api-testing-newman-5fn1</guid>
      <description>Image by &lt;a href="https://pixabay.com/users/stevepb-282134/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=674828"&gt;Steve Buissinne&lt;/a&gt; from &lt;a href="https://pixabay.com/?utm_source=link-attribution&amp;amp;utm_medium=referral&amp;amp;utm_campaign=image&amp;amp;utm_content=674828"&gt;Pixabay&lt;/a&gt;

&lt;h2&gt;
  
  
  I need a tool to handle post-deployment testing properly
&lt;/h2&gt;

&lt;p&gt;I've got a project where I'm not handing post-deployment testing with any real grace.  It's been on the list of things to resolve, and I'm happy with it for the moment because of the pre-release tests, manual release testing, and monitoring post-release, but it does need solving.&lt;/p&gt;

&lt;p&gt;I stumbled upon the &lt;code&gt;newman&lt;/code&gt; cli tool from the &lt;a href="https://getpostman.com"&gt;good folks at getpostman.com&lt;/a&gt;.  It's a CLI, open source tool that runs the tests you have saved in your Postman collections, and gives the typical error state output / console output you expect from any modern testing tool, which means you can integrate it into your CI/CD workflow. &lt;/p&gt;

&lt;p&gt;For anyone who's not used Postman, it's a stunning tool for making requests to services, keeping collections of connections and such, and if you're doing almost any web-based development you need it.  If you're too old-school and like using cURL for everything?  Fine, it'll import and export cURL commands for you.  Go check it out. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9hOfAFHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/6esvdyzzxedzlw55hbau.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9hOfAFHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/6esvdyzzxedzlw55hbau.png" alt="Alt Text" width="800" height="492"&gt;&lt;/a&gt;&lt;a href="https://www.getpostman.com/"&gt;https://www.getpostman.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only problem for me - I don't use Postman like that.  I don't keep collections of things really, I just use it ad-hoc to test things or for a quick bit of debugging.  We've got a nice &lt;a href="https://dev.to/scampiuk/openapi-swagger-specifications-that-write-your-tests-for-you-sort-of-4kc5"&gt;collection of integration tests build around our OpenAPI specs&lt;/a&gt; that we rely on, so I've not had to do what others have done and create a large collection of API endpoints.&lt;/p&gt;

&lt;p&gt;The trick here is going to be keeping the duplication down to a minimum. &lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started: We're going to need an API to test against:
&lt;/h2&gt;

&lt;p&gt;I've stored everything for this project, &lt;a href="https://github.com/scampiuk/postman-newman-testing"&gt;you can see all the files on GitHub&lt;/a&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="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&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;bodyParser&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;body-parser&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;addRequestId&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;express-request-id&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addRequestId&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="nx"&gt;res&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="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;hello world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/foo&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;id&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;
    &lt;span class="nx"&gt;res&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bar&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="nx"&gt;bar&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="na"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/foo&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&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;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&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="na"&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;missing `bar`&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;res&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bar&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="nx"&gt;bar&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="na"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&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="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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&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;port&lt;/span&gt; &lt;span class="o"&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;address&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;port&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Example app listening to port %s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;port&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;p&gt;So we've got three endpoints to use: &lt;code&gt;/&lt;/code&gt; and &lt;code&gt;/foo&lt;/code&gt; as &lt;code&gt;GET&lt;/code&gt;, and &lt;code&gt;/foo&lt;/code&gt; as &lt;code&gt;POST&lt;/code&gt;.  There's a little validation in the &lt;code&gt;POST /foo&lt;/code&gt; endpoint.  I've added &lt;code&gt;express-request-id&lt;/code&gt; in and added it to the responses so we can make sure they're unique. &lt;/p&gt;

&lt;h2&gt;
  
  
  Starting the Collection
&lt;/h2&gt;

&lt;p&gt;I'm learning this as I blog here, so forgive any backtracking! I've gone into postman and created a new collection called &lt;code&gt;postman-newman-testing&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TCOZ43zN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/2l8eafu4i4kxhu2gitbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TCOZ43zN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/2l8eafu4i4kxhu2gitbg.png" alt="Postman collection created" width="800" height="523"&gt;&lt;/a&gt;A nice start, an empty collection created &lt;/p&gt;

&lt;p&gt;I went through and created and saved a request for each of the three endpoints, adding a little description for each:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FIB2pRSu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/qtbs7b6iudrhp7l4ofqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FIB2pRSu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/qtbs7b6iudrhp7l4ofqx.png" alt="Alt Text" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;
Three requests added to the collection.  If you have trouble with this, I recommend the very helpful documentation over at [the Postman Learning Center](https://learning.getpostman.com/)



&lt;h2&gt;
  
  
  Adding some tests:
&lt;/h2&gt;

&lt;p&gt;Remembering the goal here is to create something that can help us run some post-deployment tests, so we're going to define some simple tests in the collection for each of the endpoints. I want to ensure: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I get a &lt;code&gt;requestId&lt;/code&gt; back for each response&lt;/li&gt;
&lt;li&gt;I get a &lt;code&gt;200&lt;/code&gt; response for each&lt;/li&gt;
&lt;li&gt;I can trigger a &lt;code&gt;500&lt;/code&gt; response when I expect there to be an error&lt;/li&gt;
&lt;li&gt;The expected values come back for the &lt;code&gt;POST /foo&lt;/code&gt; and &lt;code&gt;GET /foo&lt;/code&gt; endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The documentation for the test scripts is all in the &lt;a href="https://learning.getpostman.com/docs/postman/scripts/test_scripts"&gt;Postman Learning Center&lt;/a&gt; as you would expect, and thankfully it's going to be really familiar for anyone who's worked with tests and JS before.&lt;/p&gt;

&lt;p&gt;So, after a little hacking around, I discovered something cool; when you make the tests, they're executed each time you execute that request, so if you're using Postman to dev with, you can't 'forget' to run the tests. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--30mX4Cun--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/u8tbzrxtt2r30279ef5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--30mX4Cun--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/u8tbzrxtt2r30279ef5i.png" alt="Alt Text" width="800" height="523"&gt;&lt;/a&gt;The four tests are executed each time, so we're testing the response code, shape of the response, that it's a JSON type returned, and that it's as fast as we expect it to be&lt;/p&gt;

&lt;h3&gt;
  
  
  Variations
&lt;/h3&gt;

&lt;p&gt;I want to test two different outputs from an endpoint, success and failure, but I don't think I should have to save two different requests to do that, so how are we going to test our &lt;code&gt;POST /foo&lt;/code&gt; endpoint?  I'm going to come back to that at some point once I understand more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate all the things
&lt;/h2&gt;

&lt;p&gt;I've got my collection set up with all the happy-path tests, and if open the Collection Runner, and run my collection (..), then I get a nice board of green boxes telling me my API is, at a very basic level, doing what I expect it to be doing. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wy5a2POK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/cwk8546kbiijox3jifba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wy5a2POK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/cwk8546kbiijox3jifba.png" alt="Alt Text" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;
Everything is 5 by 5



&lt;p&gt;Let's work out &lt;code&gt;newman&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I've exported the collection from Postman and stored it under &lt;code&gt;docs/postman-collection.json&lt;/code&gt; in the project root, installed &lt;code&gt;newman&lt;/code&gt; (&lt;code&gt;$ npm install --save-dev newman&lt;/code&gt;), and ran the command to run the tests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gh3HxzQV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/b1aoyzq323um2f2nivtl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gh3HxzQV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/b1aoyzq323um2f2nivtl.png" alt="Alt Text" width="475" height="695"&gt;&lt;/a&gt;&lt;/p&gt;
There's all kinds of nice output there!



&lt;p&gt;So that's amazing, I've made some simple API tests, but it's not going to do me any good for the simple reason, that in my collection all my URLs are set to &lt;code&gt;http://localhost:8081&lt;/code&gt;, so I need to work out how to change that.&lt;/p&gt;

&lt;p&gt;After a bit of clicking and Googling, we can do this.  Postman has support for Environments - you can see them at the top-right of the main window. I created a couple ('development' and 'staging') and created a value called &lt;code&gt;host&lt;/code&gt; in them with the &lt;code&gt;http://localhost:8081&lt;/code&gt; for &lt;code&gt;development&lt;/code&gt;, and &lt;code&gt;https://api.mydomain.com:3000&lt;/code&gt; for the &lt;code&gt;staging&lt;/code&gt; environment.  These are a bit fiddly, the same as some of the other parts of Postman's UI, but it's possible ;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h3YP5JKu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/33l6m8tph8elt6vecadc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h3YP5JKu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/33l6m8tph8elt6vecadc.png" alt="Alt Text" width="734" height="712"&gt;&lt;/a&gt;&lt;/p&gt;
It took too long to work this out



&lt;p&gt;Next, we go into the Collection and change the host names in the saved requests to use &lt;code&gt;{{host}}&lt;/code&gt; - the &lt;code&gt;{{ }}&lt;/code&gt; method is how Postman handles environment variables, and could be used for things like API keys.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U8D9icS9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/riqhaegc75ahnswg4ve8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U8D9icS9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/riqhaegc75ahnswg4ve8.png" alt="Alt Text" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;
As you can see, I've changed the hostname to `{{host}}/` and I'm using the `development` environment, and all is well



&lt;p&gt;So let's translate to the &lt;code&gt;newman&lt;/code&gt; tool.&lt;/p&gt;

&lt;p&gt;Ahh. Ok.&lt;/p&gt;

&lt;p&gt;So exporting the Collection doesn't bring any of the environment variables with it. We have to export those as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rdfm1ZeG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/4u01fi7l7r2ykqmbj019.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rdfm1ZeG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/4u01fi7l7r2ykqmbj019.png" alt="Alt Text" width="715" height="107"&gt;&lt;/a&gt;&lt;/p&gt;
I left the file naming scheme as it is



&lt;p&gt;And now, we're going to want to use those environment configs with our &lt;code&gt;newman&lt;/code&gt; execution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gqNFGZEj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/zpx9jo7ngvpkokvc56uo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gqNFGZEj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/zpx9jo7ngvpkokvc56uo.png" alt="Alt Text" width="600" height="847"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boom! Git controlled, command line executed testing for APIs in different environments, using a tool all devs should be using anyway for a simple post-deployment check.  There's the obvious steps of adding this to your Jenkins / Gitlab / whatever pipeline which I'm not going to cover here, but I'm happy with what's been discovered over the last couple of hours. &lt;/p&gt;

&lt;p&gt;One last thing, lets put this into the &lt;code&gt;package.json&lt;/code&gt; file so we can re-use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postman-newman-testing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"development"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"debug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon src/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node src/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Error: no test specified&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; exit 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test-post-deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"newman run ./docs/postman-collection.json -e ./docs/$npm_package_config_environment.postman_environment.json"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chris Williams &amp;lt;chris@imnotplayinganymore.com&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ISC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"body-parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.19.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.17.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"express-request-id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.4.1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"newman"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nodemon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.19.3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can handle configs for environments as we like, and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run test-post-deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to execute the test!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;While it may be another set of tests and definitions to maintain (I would really like this to be based from our OpenAPI spec documents, but I'll figure that out later), this seems to be a great way of achieving two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A really simple set of tests to run post-deployment or as part of the monitoring tooling&lt;/li&gt;
&lt;li&gt;The collection file can be handed out to devs working with the APIs: The're going to be using Postman (probably) anyway, so give them a head-start.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Postman is just one of those tools that you have to use if you're doing web-dev, or app-dev.  Given that it's just 'part' of the dev toolkit, we may as well use the familiarity and use it as part of the testing tools as well. &lt;/p&gt;

&lt;p&gt;There are some things that I would like to know a bit more about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be able to store the output in a file, maybe, so it's visible quickly in Jenkins &lt;/li&gt;
&lt;li&gt;Set the severity of individual tests - so if we fail some it's an instant roll-back, if we fail some others it's a loud klaxon in the engineering office for someone to investigate, but it may be resolved by fixing forwards&lt;/li&gt;
&lt;li&gt;Test for sad-paths , make sure that the right error response codes are coming back for things without having to create the responses for them:  I think there's something you can do with the Collection Runner and a file of sample data, and then flag if tests should be red or green, but I didn't get around to that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks also to those who've replied to my on-going tweets about all things Postman over the last couple of hours, esp &lt;a href="https://twitter.com/DannyDainton"&gt;Danny Dainton&lt;/a&gt;, who also has his own Dev.to articles over at &lt;a href="https://dev.to/dannydainton"&gt;https://dev.to/dannydainton&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks again for the comments on previous articles, I would love to hear how you use this in your projects! Get me on &lt;a href="https://twitter.com/Scampiuk"&gt;https://twitter.com/Scampiuk&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postman</category>
      <category>testing</category>
      <category>api</category>
      <category>javascript</category>
    </item>
    <item>
      <title>OpenAPI (Swagger) specifications that write your tests for you (sort of)</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Mon, 23 Sep 2019 22:27:59 +0000</pubDate>
      <link>https://dev.to/scampiuk/openapi-swagger-specifications-that-write-your-tests-for-you-sort-of-4kc5</link>
      <guid>https://dev.to/scampiuk/openapi-swagger-specifications-that-write-your-tests-for-you-sort-of-4kc5</guid>
      <description>&lt;p&gt;I recently wrote the article &lt;a href="https://medium.com/@Scampiuk/handling-api-validation-with-openapi-swagger-documents-in-nodejs-1f09c133d4d2?source=your_stories_page---------------------------" rel="noopener noreferrer"&gt;Handling API validation with OpenAPI (Swagger) documents in NodeJS&lt;/a&gt;, which went into how to pass on the work of input validation to the OpenAPI spec. This follows on, showing how to lighten the testing load and ensure your API is producing exactly the output you’ve painstakingly documented.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AdztNVuObpOSvrLaBbE9q2Q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AdztNVuObpOSvrLaBbE9q2Q.jpeg"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@pinjasaur?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Paul Esch-Laurent&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/javascript?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Faster testing by relying on the OpenAPI spec as a single source of truth.
&lt;/h3&gt;

&lt;p&gt;There is nothing, &lt;em&gt;nothing,&lt;/em&gt; more predictable than API documentation being wrong.&lt;/p&gt;

&lt;p&gt;It’s hard to keep that document up to date with all the other pressures of having to, you know, maintain the API. It’s simpler to push the fix or feature and then update the doc. Eventually.&lt;/p&gt;

&lt;p&gt;I would be lying if I was looking for the solution to this exact problem, but I’ve discovered one as a by-product of two other things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using the API spec document for validation.
We covered this in &lt;a href="https://dev.to/scampiuk/handling-api-validation-with-openapi-swagger-documents-in-nodejs-17d0"&gt;https://medium.com/@Scampiuk/handling-api-validation-with-openapi-swagger-documents-in-nodejs-1f09c133d4d2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Using the API spec document for testing. ( This guide )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This little duo means the API spec &lt;em&gt;has&lt;/em&gt; to be up to date, else you can’t pass any of your tests. Nice, hu?&lt;/p&gt;

&lt;p&gt;We’re going to start with as simple as a test application as possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Let’s run it…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chris@chris-laptop:~/Projects/openapi-testing$ curl localhost:3000
{"version":"1.0.0"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ok so that’s simple and working, let’s create a spec that defines this, rather limited, API. Using OpenAPI 3 spec, we’ll be quite verbose in the way we build the objects up so we can re-use them in the future:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We can see that our GET / endpoint needs to return an object with the a property called version which has a pattern of ^\d.\d.\d$ , and it requires a header called X-Request-Id which is a &lt;a href="https://en.wikipedia.org/wiki/Universally_unique_identifier" rel="noopener noreferrer"&gt;UUID&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But our current endpoint doesn’t fulfill this criteria! We’ve created the thing we hate, the thing worst than no API documentation: &lt;em&gt;bad&lt;/em&gt; API documentation. The solution? Tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install supertest chai mocha --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once we have that installed, let’s create a nice simple test&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Then in package.json , under the scripts block, add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"test": "./node\_modules/.bin/mocha --exit --timeout 10000"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will run our test we’ve just created, exit once it’s done, have a sane time-out time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F547%2F1%2Ak2wT93ReEq-ASuXMBKWp0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F547%2F1%2Ak2wT93ReEq-ASuXMBKWp0w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve expelled some effort to test this endpoint, but the tests are a false positive — we know the spec requires the X-Request-Id to be defined, and our test doesn’t cover that.&lt;/p&gt;

&lt;p&gt;We’re going to look at the same tooling as we used in the previous guide, express-openapi-validate . This thing is going to ingest our spec file, and in the same way we used it previously to validate the input to an API, we’re going to use it to validate the &lt;em&gt;output&lt;/em&gt; of the API.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express-openapi-validate js-yaml app-root-path --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And now we’re going to change the index.spec.js around a bit, taking out the explicit definition of what we expect in the endpoint, and adding in the OpenApiValidator…&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;and run the test again…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F895%2F1%2A17D_Ty865erMcFL9wFJSIQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F895%2F1%2A17D_Ty865erMcFL9wFJSIQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There! It failed this time, and told us why it failed: response.headers should have required property "x-request-id"&lt;/p&gt;

&lt;p&gt;Note we’ve not had to define that in the test: in fact we’ve taken out code for testing what shape the response is, it’s taken the spec and worked out what’s required for a GET / request. Let’s fix the endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install faker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;( if you’ve not looked at &lt;a href="https://www.npmjs.com/package/faker" rel="noopener noreferrer"&gt;faker&lt;/a&gt; before, I strongly recommend it, I’m abusing it here slightly but it’s a fantastic fake data generator))&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F633%2F1%2ANDAt_1pzx8WqCMsvkS24Mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F633%2F1%2ANDAt_1pzx8WqCMsvkS24Mg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We changed the response to set the X-Request-Id header with a UUID, and now the tests pass.&lt;/p&gt;

&lt;p&gt;What happens if we break the format of version? We’ll change the request to send x1.0.0 instead, which doesn’t match the pattern for Version …&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F910%2F1%2AiHIRd8nryi66U9oeSDHTFw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F910%2F1%2AiHIRd8nryi66U9oeSDHTFw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tests fail, because you’re sending the wrong value.&lt;/p&gt;

&lt;p&gt;This is crazy powerful. Now, because you’ve defined things in your spec file correctly, you can re-use patterns in your API and ensure that the spec is being fulfilled on your tests, while updating &lt;em&gt;all&lt;/em&gt; your tests if you update the spec file. You write less lines in your tests, focus on putting the effort into the spec file (because that’s now driving your tests…) and things become simpler.&lt;/p&gt;

&lt;h4&gt;
  
  
  In conclusion
&lt;/h4&gt;

&lt;p&gt;Using the OpenAPI spec to control how data gets into your API, and using it to build your tests around, means that it becomes the single source of truth about your API. Sure, there are ways of cheating this and not documenting all the objects, or not testing endpoints, but why do that?&lt;/p&gt;

&lt;p&gt;By combining these two approaches, we’ve found that workflow on the API now &lt;em&gt;starts&lt;/em&gt; with the OpenAPI specification, then building tests, then implementing the endpoints. TDD becomes almost the de facto way of approaching development. While before API development may have started by firing up Postman and thrashing through some ideas, now it’s all tested by this near-magic combination of &lt;a href="https://www.npmjs.com/package/supertest" rel="noopener noreferrer"&gt;supertest&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/mocha" rel="noopener noreferrer"&gt;mocha&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/chai" rel="noopener noreferrer"&gt;chai&lt;/a&gt;, and &lt;a href="https://www.npmjs.com/package/express-openapi-validate" rel="noopener noreferrer"&gt;OpenApiValidator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are a couple of things missing from this set-up which I’m still working on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I would like code coverage reports via nyc to ensure that all the endpoints and response codes defined in the OpenAPI spec document are implemented&lt;/li&gt;
&lt;li&gt;I would like the test validation to error if there are objects or properties in the API responses that are &lt;em&gt;not&lt;/em&gt; documented — I just can’t work that one out at the moment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I would love to hear how you use this in your projects! Get me on &lt;a href="https://twitter.com/Scampiuk" rel="noopener noreferrer"&gt;https://twitter.com/Scampiuk&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>node</category>
      <category>javascript</category>
      <category>swagger</category>
    </item>
    <item>
      <title>Handling API validation with OpenAPI (Swagger) documents in NodeJS.</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Wed, 17 Apr 2019 20:45:07 +0000</pubDate>
      <link>https://dev.to/scampiuk/handling-api-validation-with-openapi-swagger-documents-in-nodejs-17d0</link>
      <guid>https://dev.to/scampiuk/handling-api-validation-with-openapi-swagger-documents-in-nodejs-17d0</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KxEAprF2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AmGQlv5buR3vC2AWM" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KxEAprF2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AmGQlv5buR3vC2AWM" alt="" width="800" height="534"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@punttim?utm_source=medium&amp;amp;utm_medium=referral"&gt;Tim Gouw&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article was originally posted on my Medium blog.&lt;/p&gt;

&lt;p&gt;I always found the hardest thing about API work was the documentation.&lt;/p&gt;

&lt;p&gt;Sure, there are loads of nice tools out there to help you define it, provide nice front-ends and the like, but maintaining that isn’t anywhere nearly as fun as getting the actual work done. So soon enough, you’ve got stale documentation with little errors, and validation rules that don’t &lt;em&gt;quite&lt;/em&gt; match up.&lt;/p&gt;

&lt;p&gt;A recent NodeJS API project came my way which had out-of-date &lt;a href="https://swagger.io/docs/specification/about/"&gt;OpenAPI 3&lt;/a&gt; documentation for the few endpoints it already had, but the understanding that we where going to start using it a lot more, so it needed to get up to scratch.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;OpenAPI Specification&lt;/strong&gt; (formerly Swagger Specification) is an API description format for REST APIs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I figured that if we where going to maintain this OpenAPI spec, which contained all the validation rules for the endpoints, then there must be a way we could use that to save us some time.&lt;/p&gt;

&lt;p&gt;What if we could use that spec to enforce the validation? What if we could use it as the basis of the endpoint testing?&lt;/p&gt;

&lt;p&gt;If we could get these two things, we have the wonderful combo of the OpenAPI spec needing to be write for the validation to work, and the validation being unable to deviate from the spec — so no more dodgy documentation where that param is documented as an int but it’s actually a float..&lt;/p&gt;

&lt;p&gt;.. and if we can build tests based from the documentation then all our outputs have to be as defined, so the consumers of the API don’t get urked if we send an object and they’re expecting an array.&lt;/p&gt;

&lt;p&gt;Using the OpenAPI spec to enforce the validation and be the crux of the tests enforces good definition of the API and removes all the nasty little ‘Ohh yea, that only returns X if Y’ that plagues API development IMHO.&lt;/p&gt;

&lt;p&gt;So let’s stop waffling here and create something simple to prove how this works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HsjxizGd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/258/1%2AqCL0FrKWUbo2hQdlzsQbig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HsjxizGd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/258/1%2AqCL0FrKWUbo2hQdlzsQbig.png" alt="" width="258" height="482"&gt;&lt;/a&gt;Randall Munroe — &lt;a href="https://xkcd.com/1481/"&gt;&lt;/a&gt;&lt;a href="https://xkcd.com/1481/"&gt;https://xkcd.com/1481/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First we’re going to spec our endpoint. To save some time, I’ve used one of the sample specifications as a base. There’s a very nice editor / visualization tool at &lt;a href="https://editor.swagger.io/"&gt;https://editor.swagger.io/&lt;/a&gt; to work with your spec files.&lt;/p&gt;

&lt;p&gt;Here’s the sub-set of the specification we’re going to look at:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;An endpoint that expects two variables in the path, {dataset} and {version} that are both strings. There are three possible variables in the post body also, one of which is required. It has two responses, a 200 that returns an array of records, and a 404. The response has a bunch of criteria also.&lt;/p&gt;

&lt;p&gt;Let’s store this thing as /spec/api.spec.yaml&lt;/p&gt;

&lt;p&gt;Now, a quick build of an Express app to handle responses to the path as documented:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is as simple as it gets. So lets run it and check out if it works in Postman.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QMkn8394--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aoom6LdT-5q5znO8v5BRkiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QMkn8394--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aoom6LdT-5q5znO8v5BRkiw.png" alt="" width="800" height="579"&gt;&lt;/a&gt;As expected, our API responds by telling us what we told it.&lt;/p&gt;

&lt;p&gt;This all so-far-so-normal. Lets add the good stuff. Looking at the spec, we should now start adding validation into the endpoint we’ve just created — ensuring all those numbers are numbers, that the criteria is there etc.. But we don’t want to do that as we’ve already spent the time writing that all into the spec.&lt;/p&gt;

&lt;p&gt;We’re going to install a node module called &lt;a href="https://www.npmjs.com/package/express-openapi-validate"&gt;express-openapi-validate&lt;/a&gt; ( along with js-yaml) to handle this for us. Now we’ve got that installed, let’s change up the code a little:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Lost more going on here!&lt;/p&gt;

&lt;p&gt;We’ve loaded the app.spec.yaml file and we’re creating an OpenApiValidator object with it, along with some interesting looking options. The options are all inherited from the parsing app &lt;a href="https://ajv.js.org/#options"&gt;ajv&lt;/a&gt; . Our two are :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;allErrors: true, // makes it return all errors, not just the 1st
removeAdditional: "all", // Removes any undocumented params
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re validating the spec against the request as middleware, where we’re telling it what method we’re looking for and the path, and we’ve added some error handling to give us something to display if it doesn’t all go according to plan.&lt;/p&gt;

&lt;p&gt;Let’s mess up our request, and try again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tctmrBmG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Adslf-VNJZMssFw2aFeMOTA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tctmrBmG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Adslf-VNJZMssFw2aFeMOTA.png" alt="" width="800" height="579"&gt;&lt;/a&gt;What, an API that returns with useful error messages?!&lt;/p&gt;

&lt;p&gt;Okay! We’ve just added validation against the OpenAPI spec! It’s capturing the two things I broke: The removal of the required field criteria , and the incorrect type of .body.rows . It’s not a very graceful error message, but it’s telling the consumer what’s gone wrong, and you’ve not had to write any of it. It’s also returning the right status code of 400 for us. Sweet!&lt;/p&gt;

&lt;p&gt;Let’s fix the request and try once again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_7MRrKNh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AUX0vm12pzIu-X6_8HugfTw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_7MRrKNh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AUX0vm12pzIu-X6_8HugfTw.png" alt="" width="800" height="579"&gt;&lt;/a&gt;Much better, but something’s missing…&lt;/p&gt;

&lt;p&gt;All looks as before.. but it’s stripped out the foo: "bar" from the body, because it wasn’t documented. The validator stripped it out because it was undocumented. No more sneaking in properties in post bodies and not telling anyone.&lt;/p&gt;

&lt;p&gt;This means now, if you format your OpenAPI spec correctly, the data arrives to your code validated and correct. Now, I’m not saying it’s perfect — there is a known problem with trying to parse numbers in the path, and Express handles everything as a string, but it’s much faster than having to maintain the OpenAPI spec document -and- the validation on the endpoint.&lt;/p&gt;

&lt;p&gt;I’m hoping that gives you enough grounding in how to approach this so you can start using your OpenAPI spec documents as the amazing resource that it is. Treat the spec well and it’ll not only provide you with documentation for the consumers of the API, but will also do a lot of the work for you.&lt;/p&gt;

&lt;p&gt;The next thing to look at, which I’ll link to once I write it, is the other side of this, which is writing tests that ensure that the output of your API conforms to the OpenAPI spec — thus forcing you to write API responses that your consumers expect!&lt;/p&gt;

&lt;p&gt;I would love to hear how you use this in your projects! Get me on &lt;a href="https://twitter.com/Scampiuk"&gt;https://twitter.com/Scampiuk&lt;/a&gt;&lt;/p&gt;

</description>
      <category>swagger</category>
      <category>api</category>
      <category>openapi</category>
      <category>node</category>
    </item>
    <item>
      <title>Mining for Crypto in the browser is not evil.</title>
      <dc:creator>Chris Williams</dc:creator>
      <pubDate>Fri, 29 Sep 2017 21:54:12 +0000</pubDate>
      <link>https://dev.to/scampiuk/mining-for-crypto-in-the-browser-is-not-evil-330j</link>
      <guid>https://dev.to/scampiuk/mining-for-crypto-in-the-browser-is-not-evil-330j</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F960%2F1%2AC1qnCfK-xsnL6-lqgwkRHw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F960%2F1%2AC1qnCfK-xsnL6-lqgwkRHw.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The old argument is that the content on the internet needs paying for. Long gone are the days where everything is created by enthusiasts and people messing around in their spare time. Today’s content and platforms are high-quality and expensive to produce, and at the moment we’ve really only got three models to pay for it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Subscription or pay-per-content. You want it? Open your wallet — subscription models are becoming more popular for the high-end content such as video and music, and that’s great. But it doesn’t really trickle down to things that you don’t really think you should be paying for, stuff that doesn’t have that real, tangible sense of value. Sure I’ll subscribe to &lt;a href="https://play.google.com/intl/en_uk/about/music/index.html" rel="noopener noreferrer"&gt;Google Play Music&lt;/a&gt;, &lt;a href="http://www.amazon.co.uk/tryprimefree?tag=imnotplayinga-21" rel="noopener noreferrer"&gt;Amazon Prime&lt;/a&gt;, and &lt;a href="https://www.strava.com/premium" rel="noopener noreferrer"&gt;Strava&lt;/a&gt;, but would I pay per month to use Twitter? No.&lt;/li&gt;
&lt;li&gt;Ads and marketing
You’re the product that’s being sold here, have no illusions. Hope you like ads. You’re targeted within 10 feet of your location and everyone knows what mood you’re currently in, and if you’re planning to buy a toaster or a coffee in the next ten minutes. Feeling a little grubby?&lt;/li&gt;
&lt;li&gt;Donations. That thing you’ll get around to next time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, now there’s the idea of a fourth option. A bit of code runs in the website, extension, or app that you’re making good use of, and quietly and unobtrusively uses some of your CPU cycles to make a bit of money for it’s creator. You get the content ad-free, they get paid — this is what coin mining in browser could lead to.&lt;/p&gt;

&lt;p&gt;Now, there’s an option to have a business model without advertising in mind. A model that isn’t trying to squeeze every little last drop of revenue out of you, because the money is being earned by you being on the site. The miner doesn’t care who you are or what shopping mood you’re in, it just get’s on and mines a tiny fraction of a given crypto-currency.&lt;/p&gt;

&lt;p&gt;Is that so bad? Apparently people think so.&lt;/p&gt;

&lt;p&gt;This is from two genuine reviews of an extension we tried this over the week. These got posted once it was published on &lt;a href="https://www.reddit.com/r/firefox/comments/737kze/mining_codes_been_discovered_in_two_reviewed/" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;that it contained the miner — something that we had put in the description of the extension from the very beginning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No addon is worth giving the author CPU time and electricity. That’s what a coin miner takes from you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No addon? I use a few that make my workday easier because of what their authors have created, and I try to donate or pay when I can. What if I didn’t have to, because every hour I had their tool open in the browser, it earned them money? What about websites, does the same apply here if they can offer me an advert-free, tracking free experience?&lt;/p&gt;

&lt;p&gt;Here’s another one&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;he’s taking your electricity and bill so he can pay his.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Is that any difference between someone taking up your screen space to show you adverts? That just about defines all brand-awareness advert campaigns.&lt;/p&gt;

&lt;p&gt;I’m not going to say here that this technology won’t have it’s problems. People will abuse it, and because of this others will distrust it. I personally learned about it after reading what &lt;a href="https://thehackernews.com/2017/09/pirate-bay-cryptocurrency-mining.html" rel="noopener noreferrer"&gt;The Pirate Bay did&lt;/a&gt; a weekend ago. The reaction to that where news articles that included the words ‘hidden’ and ‘secretly’, not a great first impression made to the world.&lt;/p&gt;

&lt;p&gt;But, I’m not going to say that this is a bad technology ether. The idea of an advert free web, and a more anonymous web because of that, is something that we should be excited about.&lt;/p&gt;

&lt;p&gt;Let’s not stamp on ways that content creators can earn enough to pay the bills.&lt;/p&gt;

</description>
      <category>mining</category>
      <category>coinhive</category>
      <category>advertising</category>
      <category>cryptocurrency</category>
    </item>
  </channel>
</rss>
