<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[JoyceJetson]]></title><description><![CDATA[JoyceJetson]]></description><link>https://blog.joycejetson.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 03 May 2026 18:25:42 GMT</lastBuildDate><atom:link href="https://blog.joycejetson.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Powering home automation with WebSocket APIs]]></title><description><![CDATA[Get started with the Home Assistant WebSocket API
In Part 1 of this series, we learned about the WebSocket protocol and how to set up our own WebSocket server in Node.js. Next, let’s explore how to use a public WebSocket API to access smart devices a...]]></description><link>https://blog.joycejetson.com/powering-home-automation-with-websocket-apis-8885a7601523</link><guid isPermaLink="true">https://blog.joycejetson.com/powering-home-automation-with-websocket-apis-8885a7601523</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Thu, 06 Jul 2023 17:04:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163468523/f6a86638-3da9-4893-a443-51edb099ad2d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-get-started-with-the-home-assistant-websocket-api">Get started with the Home Assistant WebSocket API</h4>
<p>In Part 1 of this series, we learned about the <a target="_blank" href="https://learning.postman.com/docs/sending-requests/websocket/websocket/">WebSocket</a> protocol and how to <a target="_blank" href="https://blog.postman.com/set-up-a-websockets-server-in-node-js-postman/">set up our own WebSocket server in Node.js</a>. Next, let’s explore how to use a public WebSocket API to access smart devices around a connected home.</p>
<h3 id="heading-rest-and-websockets-for-a-connected-home">REST and WebSockets for a connected home</h3>
<p>When it comes to transmitting data in a connected home environment, both <a target="_blank" href="https://blog.postman.com/rest-api-examples/">REST</a> and WebSockets are commonly used protocols, but they have different characteristics and use cases.</p>
<p>REST follows a request-response pattern, where a client sends a request to a server, and the server responds with the requested data. This is useful for accessing and controlling smart devices and services, and works well for scenarios where data updates are not required in real-time. For example, you could use a REST API to turn on a smart light.</p>
<p>On the other hand, WebSockets enables bidirectional communication between a client and server, enabling real-time data transmission. This is useful for applications that require continuous data updates, such as real-time monitoring of sensor data and displaying live dashboards. For example, you could use a WebSocket API to continuously monitor the temperature in a room over a persistent connection.</p>
<p>In the next section, let’s take a look at a popular home automation platform that provides both REST and WebSocket APIs.</p>
<h3 id="heading-home-assistant-for-home-automation">Home Assistant for home automation</h3>
<p><a target="_blank" href="https://www.home-assistant.io/">Home Assistant</a> is a popular open-source home automation platform that lets you control and monitor smart devices from different brands using a unified interface. Instead of using separate applications to control the kitchen lights, thermostat, and other connected devices all manufactured by different producers, you can manage almost everything from a single Home Assistant web dashboard running on a Raspberry Pi or other dedicated server within your local network.</p>
<p>Home Assistant is ideal for DIY smart-home tinkerers because it supports a wide range of integrations and protocols, allowing you to customize automation scenarios based on events, schedules, and sensor readings.</p>
<p>Next, let’s take a look at Home Assistant’s WebSocket API.</p>
<h3 id="heading-home-assistant-websocket-api">Home Assistant WebSocket API</h3>
<p>In addition to a <a target="_blank" href="https://developers.home-assistant.io/docs/api/rest/">REST API</a><a target="_blank" href="https://blog.postman.com/rest-api-examples">,</a> Home Assistant also contains a <a target="_blank" href="https://developers.home-assistant.io/docs/api/websocket">WebSocket API</a> to stream information. To learn how to authenticate the WebSockets connection and send saved messages to the Home Assistant server, follow along with this <a target="_blank" href="https://quickstarts.postman.com/guide/home-assistant/index.html?index=..%2F..index#0">step-by-step tutorial</a>, watch the <a target="_blank" href="https://youtu.be/Qk9A0QbG5-I">video</a>, and reference <a target="_blank" href="https://www.postman.com/postman/workspace/program-smart-lights/collection/6481ed9afe7f1bdfaa732408">the sample collection</a>.</p>
<iframe src="https://www.youtube.com/embed/Qk9A0QbG5-I?feature=oembed" width="700" height="393"></iframe>

<p>Using a long-lived token, you can use Postman to establish a connection with our Home Assistant server running locally, and then send and receive messages using the WebSocket API.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163466245/8a192c24-3dd2-4c1a-ac50-221565285d69.png" alt /></p>
<p>You can also configure your own <strong>Saved Messages</strong> to create your own customized themes and sequences.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163467285/10acb9c6-ab9a-4bd6-b6ad-bccaa810d193.png" alt /></p>
<p>Home Assistant also provides a <a target="_blank" href="https://developers.home-assistant.io/docs/api/rest">REST API</a>. Explore Home Assistant’s WebSocket and REST APIs side-by-side in Postman to better understand the differences between the two protocols.</p>
<h3 id="heading-additional-resources">Additional resources</h3>
<p>You can work in Postman using different API patterns and protocols. Check out these Postman resources to learn more about WebSockets:</p>
<ul>
<li><a target="_blank" href="https://www.postman.com/postman/workspace/websockets/documentation/14057978-712d684f-c252-4bd9-a7a6-6a893e41adea">Guide to Postman WebSockets</a> collection</li>
<li><a target="_blank" href="https://learning.postman.com/docs/sending-requests/websocket/websocket/">Using WebSocket requests</a> docs</li>
<li><a target="_blank" href="https://youtu.be/H-7EZVj9D-k">WebSocket requests</a> video</li>
</ul>
<p>Browse the <a target="_blank" href="https://www.postman.com/postman/workspace/program-smart-lights/overview">Program smart lights</a> public workspace for APIs from other providers, such as Philips Hue and Elgato, to automatically control smart lights in your home or office. And let us know in the comments below what kind of projects you want to learn about, and what you’re doing with WebSockets.</p>
]]></content:encoded></item><item><title><![CDATA[Negative testing for more resilient APIs]]></title><description><![CDATA[Unhappy path test cases to ensure proper input validation and error handling
Photo by Intricate Explorer on Unsplash
I’ve previously shared how to build resilient APIs with chaos engineering and security hacking with the Big List of Naughty Strings. ...]]></description><link>https://blog.joycejetson.com/negative-testing-for-more-resilient-apis-af904a74d32b</link><guid isPermaLink="true">https://blog.joycejetson.com/negative-testing-for-more-resilient-apis-af904a74d32b</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Thu, 27 May 2021 21:10:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163488592/3d06c76e-7167-4b21-acd2-720332508b9a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-unhappy-path-test-cases-to-ensure-proper-input-validation-and-error-handling">Unhappy path test cases to ensure proper input validation and error handling</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@intricateexplorer?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Intricate Explorer</a> on <a target="_blank" href="https://unsplash.com/s/photos/rocky-road?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>I’ve previously shared how to <a target="_blank" href="https://medium.com/better-practices/chaos-d3ef238ec328">build resilient APIs with chaos engineering</a> and <a target="_blank" href="https://youtu.be/E66R1nP7d-A">security hacking with the Big List of Naughty Strings</a>. I’ve also broken some hearts, so I have some experience with breaking things. In this post, let’s go beyond <a target="_blank" href="https://medium.com/better-practices/acing-your-apis-what-you-need-to-know-for-test-automation-e3fdba3519b9">basic test automation</a> in Postman, and learn why intentionally trying to break things increases the resilience of your applications. We’ll also explore some common negative test scenarios.</p>
<h3 id="heading-happy-path-vs-unhappy-path">Happy path vs. Unhappy path</h3>
<p>During product design and development, stakeholders focus on intended user behavior. Product owners describe this happy path with business requirements. Engineers push code to enable users to do these things. A user who demonstrates this expected behavior follows the happy path.</p>
<p>These are examples of happy paths:</p>
<ul>
<li>User creates a new account</li>
<li>User signs in with their new credentials</li>
<li>User retrieves information about their account</li>
</ul>
<p>But what happens when there’s unintended behavior, like when a user submits invalid inputs? These unhappy path scenarios are often neglected in design and development. But with enough traffic, unexpected inputs will inevitably come from both well-intentioned and malicious users.</p>
<p>These are examples of unhappy paths:</p>
<ul>
<li>User creates a new account without providing all required inputs</li>
<li>User signs in with invalid credentials</li>
<li>User pastes a SQL query that gets executed (maliciously or unintentionally)</li>
</ul>
<p>A strong test plan covers both happy and unhappy paths. Positive test cases describe happy path scenarios, where errors result in failed tests. Negative test cases describe unhappy path scenarios, where expected errors result in passed tests.</p>
<h3 id="heading-trying-to-break-the-unbreakable-api">Trying to break the Unbreakable API</h3>
<p>In this livestream with my colleagues Trent McCann, Quality Engineering Manager, and Evan Lindsey, Lead SDET, I tried to <a target="_blank" href="https://youtu.be/c-5UMf6sWk4">break the Unbreakable API</a>. This API was engineered by Evan to demonstrate the importance of validating inputs and handling errors.</p>
<iframe src="https://www.youtube.com/embed/c-5UMf6sWk4?feature=oembed" width="700" height="393"></iframe>

<p>“How to break an API” livestream</p>
<p>Typically, architects and engineers of an API are very familiar with the vulnerabilities of that API. However, they’re focused on enabling happy path user stories. They may not be thinking through all possible scenarios a user might encounter when interacting with the API. In the next section, let’s explore some conventional ways to break an API.</p>
<h3 id="heading-a-recommended-testing-flow">A Recommended Testing Flow</h3>
<blockquote>
<p><code>*Unbreakable API Lite*</code> <em>is a simplified version of</em> <code>*Unbreakable API*</code> <em>used in the “How to Break an API” livestream. Instead of managing authorization for multiple roles, the role of</em> <code>*admin*</code> <em>is removed and</em> <code>*employee*</code> <em>is renamed to</em> <code>*user*</code><em>. In</em> <code>*Unbreakable API Lite*</code><em>, once you create a user and set the returned token, you will have access to all available endpoints.</em></p>
</blockquote>
<p>The collection <code>[Testing Flow for Lite](https://www.postman.com/postman/workspace/unbreakable-api/documentation/1559645-c2db0576-6f29-4338-908e-25892275fe03)</code> includes examples of positive and negative test scenarios for the API referenced in <code>Unbreakable API Lite</code>. For engineers, <code>Testing Flow for Lite</code> can be a guide for input validation and error handling. And for testers, it can be a recipe for mischief.</p>
<p><a target="_blank" href="https://god.gw.postman.com/run-collection/1559645-c2db0576-6f29-4338-908e-25892275fe03?action=collection%2Ffork&amp;collection-url=entityId%3D1559645-c2db0576-6f29-4338-908e-25892275fe03%26entityType%3Dcollection%26workspaceId%3Db2d28b8c-70a9-4101-8a39-782ab83fed1b"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163487201/4085340c-e2f3-4813-beb7-8f393e87875f.png" alt /></a></p>
<p>Try it out in Postman</p>
<ol>
<li><strong>Fork the collection</strong>: Fork the collection <code>[Testing Flow for Lite](https://www.postman.com/postman/workspace/unbreakable-api/documentation/1559645-c2db0576-6f29-4338-908e-25892275fe03)</code> to your workspace. You may need to enable your public profile if you haven’t already.</li>
<li><strong>Create a new user</strong>: Find the <code>User create</code> request, and update the values under the <strong>Body</strong> tab. Hit <strong>Send</strong> to create the new user, and also set a collection variable called <code>userToken</code> that can be used in subsequent calls.</li>
<li><strong>Step through the collection</strong>: Explore the positive and negative test scenarios outlined in the remaining folders. Under the <strong>Authorization</strong> tab, notice the authorization method used for each request. Under the <strong>Pre-request Script</strong> and <strong>Tests</strong> tabs, notice code that runs before and after you send each request.</li>
<li><strong>Run the collection automatically</strong>: This collection can also be run to automate your testing flow. This is done using the <a target="_blank" href="https://learning.postman.com/docs/running-collections/intro-to-collection-runs/">Runner</a> in Postman, <a target="_blank" href="https://learning.postman.com/docs/running-collections/using-newman-cli/command-line-integration-with-newman/">Newman</a> from the command line, or <a target="_blank" href="https://learning.postman.com/docs/designing-and-developing-your-api/monitoring-your-api/monitoring-apis-websites/">Monitors</a> on Postman servers. Remember to set up a new, unique user under the <code>User create</code> request before running the collection in its entirety.</li>
</ol>
<h3 id="heading-positive-and-negative-testing">Positive and Negative testing</h3>
<p>The examples in the <code>Positive</code> folder of <code>Testing Flow for Lite</code> describe happy path scenarios, such as:</p>
<ul>
<li>Retrieve all movies</li>
<li>Create a new movie</li>
<li>Retrieve the new movie by ID</li>
</ul>
<p>For positive test cases, you write a test asserting a successful response like receiving a <code>200 OK</code>, or similar, HTTP status code. If there’s errors in those assertions, the test should fail. For example, to test the endpoint of a user creating a new movie, write a Postman test and assertion like this:</p>
<p>pm.<strong>test</strong>("Status code is 200", <strong>function</strong> () {</p>
<p>  pm.response.to.have.status(200);</p>
<p>});</p>
<p>The examples in the <code>Negative</code> folder describe unhappy path scenarios, such as:</p>
<ul>
<li>Retrieve all movies, using an authorization token when not needed</li>
<li>Create a new movie, using an invalid authorization token</li>
<li>Delete the movie, when cascade is not set on database cleanup</li>
</ul>
<p>For negative test cases, you write tests expecting certain errors. If your application doesn’t return expected errors or swallows exceptions, your application isn’t handling unexpected input gracefully. In these cases, your tests should fail if you don’t see the expected errors.</p>
<p>For example, what happens when a user creates a new movie and submits an invalid authorization token? We expect the server to return a <code>401 Unauthorized</code>, or similar, HTTP status code. To test that case, send a token that you know is invalid, and write a Postman test and assertion like this:</p>
<p>pm.<strong>test</strong>("Status code is 401", <strong>function</strong> () {</p>
<p>  pm.response.to.have.status(401);</p>
<p>});</p>
<h3 id="heading-the-importance-of-negative-testing">The importance of negative testing</h3>
<p>With negative testing, you are asserting the application accommodates unexpected user behaviors. When unexpected user behavior crashes the whole system, engineering rushes to put failsafes in place, adding tests to ensure they are handling that exact scenario correctly going forward.</p>
<p>With negative testing, you’re proactively exploring these edge cases to increase the resilience of your APIs in production. It’s important to establish a workflow and foster a supportive organizational culture to do this, before your system fails.</p>
<p>Level up your testing in Postman with these additional resources:</p>
<ul>
<li><a target="_blank" href="https://www.postman.com/postman/workspace/test-examples-in-postman/overview">Test examples in Postman</a> public workspace</li>
<li><a target="_blank" href="https://medium.com/better-practices/acing-your-apis-what-you-need-to-know-for-test-automation-e3fdba3519b9">Acing your API tests — what you need to know for test automation</a> blog and examples</li>
<li><a target="_blank" href="https://medium.com/better-practices/chaos-d3ef238ec328">Chaos engineering to increase resilience</a> blog and recipe</li>
<li><a target="_blank" href="https://youtu.be/c-5UMf6sWk4">How to break an API</a> livestream</li>
<li><a target="_blank" href="https://youtu.be/E66R1nP7d-A">Security hacking with the Big List of Naughty Strings</a> livestream</li>
</ul>
<p><strong>🙏🏼 Technical review by Evan Lindsey.</strong></p>
]]></content:encoded></item><item><title><![CDATA[How Postman Engineering handles a million concurrent connections]]></title><description><![CDATA[The Server Foundation team at Postman shares the origin story of the Bifrost websocket gateway
In the Marvel Cinematic Universe, Bifrost is the name of the rainbow bridge that allows instantaneous travel between the realms of gods and humanity. Simil...]]></description><link>https://blog.joycejetson.com/how-postman-engineering-handles-a-million-concurrent-connections-15c8807f6393</link><guid isPermaLink="true">https://blog.joycejetson.com/how-postman-engineering-handles-a-million-concurrent-connections-15c8807f6393</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Tue, 22 Dec 2020 18:42:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163498603/f2f2a29f-8d09-4eac-a79b-876ef26216df.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-the-server-foundation-team-at-postman-shares-the-origin-story-of-the-bifrost-websocket-gateway">The Server Foundation team at Postman shares the origin story of the Bifrost websocket gateway</h4>
<p>In the Marvel Cinematic Universe, Bifrost is the name of the rainbow bridge that allows instantaneous travel between the realms of gods and humanity. Similarly, and equally magically, our Bifrost websocket gateway lets Postman clients instantaneously connect to Postman services.</p>
<p>Photo by <a target="_blank" href="https://unsplash.com/@trfotos?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Toni Reed</a> on <a target="_blank" href="https://unsplash.com/s/photos/rainbow-bridge-calgary?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>As I’ve previously shared in <a target="_blank" href="https://medium.com/better-practices/how-postman-engineering-does-microservices-aa026a3d682d">How Postman Engineering Does Microservices</a>, all software architectures are a continuous work in process. Operating in the real world means occasionally re-evaluating old ways of thinking to adjust to new circumstances. That is the natural evolution of software design.</p>
<p>Here is the story of how Postman engineers developed the Bifrost websocket gateway by chipping away at a service that grew too big.</p>
<h3 id="heading-development-teams-at-postman">Development teams at Postman</h3>
<p>Most development teams at Postman work in cross-functional squads focused on a single core domain, such as documentation or <a target="_blank" href="https://learning.postman.com/docs/collaborating-in-postman/version-control-for-collections/">version control</a>. Guided by the principles of <a target="_blank" href="https://en.wikipedia.org/wiki/Domain-driven_design">domain-driven design</a>, each squad develops internal microservices and Postman features for Postman users.</p>
<p>While most engineers work in squads, some work in functional teams that build components shared across the entire engineering organization. The Server Foundation team is an example of a functional team at Postman. These engineers create the utilities used by other squads to build, ship, and observe their own features. This team is also where the resident AWS and infrastructure experts reside.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163490671/2c22769f-a0b4-4a90-acac-0eb91eeb2b33.png" alt /></p>
<p><em>the Server Foundation team is an example of a functional team at Postman that creates and manages stuff used across the entire engineering organization</em></p>
<p>Most microservices at Postman are loosely coupled so they can evolve independently of other teams. Unfortunately, a service can sometimes grow too big, providing a breadth of seemingly unrelated services. These services allow the team to rapidly iterate, but may start acting more like a bloated monolith, a big ball of mud, or whatever you want to call these unwieldy creatures.</p>
<p>When this happens at Postman, many engineers across different teams end up contributing to the code, requiring careful coordination across every team for each and every update.</p>
<h3 id="heading-the-monolithic-sync-service">The monolithic Sync service</h3>
<p>One of the Postman services that grew too big to be managed efficiently is called Sync. It has the daunting task of synchronizing all the activity in the Postman client on your local machine with Postman servers. Every user action in Postman results in a series of API calls handled over websocket connections, following a <a target="_blank" href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">publish-subscribe pattern</a>, so that information flows in real time between users and across teams.</p>
<p>For example, this is what happens when you log into Postman and update a collection:</p>
<ol>
<li>You add a parameter to the Postman collection.</li>
<li>Postman keeps a record of the update in version control stored with your profile.</li>
<li>Postman displays the latest information to viewers of the collection in real time.</li>
</ol>
<p>Sync was originally intended to handle database transactions, like updating a collection. However, this time last year, Sync also managed additional activities, such as notifying and displaying the latest version to everyone subscribed to the collection.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163491745/7f79820e-073b-43fd-bfb1-e0a1b047ddf4.jpeg" alt /></p>
<h3 id="heading-sync-under-pressure">Sync under pressure</h3>
<p>When you’re building a car, the frame is the main supporting structure to which all other components are attached. A tiny crack in the frame might not seem like a big deal. It could probably go unnoticed driving around at low speeds. At higher speeds, however, there’s a ripple effect escalating misalignments. The seemingly insignificant crack allows vibrations to amplify throughout the rest of the vehicle until it escalates into a flaming wreckage.</p>
<blockquote>
<p><strong><em>“Stuff that goes unnoticed in smaller systems becomes inescapable in more complex systems.”<br /> —</em></strong> <a target="_blank" href="https://www.linkedin.com/in/kunagpal/"><strong><em>Kunal Nagpal</em></strong></a><strong><em>, engineering manager at Postman</em></strong></p>
</blockquote>
<p>Sync was one of the earliest services at Postman, and its monolithic architecture allowed the team to ship Postman features quickly. Over time, it began handling more and more responsibilities. To this day, the Sync service still has widespread influence across the engineering organization, and lots of engineers feel the pain when Sync behaves unexpectedly or there’s scheduled downtime.</p>
<p>In 2019, Sync was handling both websocket connections and database transactions. With more and more collaboration happening among our 11 million users at that time, Postman was approaching a million concurrent connections at peak load.</p>
<p>As the foundation for virtually every microservice at Postman, the strain on Sync was growing.</p>
<ul>
<li><strong>Cascading failure due to backpressure:</strong> Every deployment to Sync results in disconnecting Postman clients connected over websockets. When a million sockets reconnect, server resources are degraded, which can then result in more disconnections, causing a predictable but unavoidable surge that can take 6 to 8 hours to recover.</li>
<li><strong>Impacting user experience:</strong> Even though it didn’t happen often, dropped connections meant an occasional delay in seeing the latest updates and activity in a Team Workspace.</li>
<li><strong>Higher cost of maintenance</strong>: Since every squad relied on Sync, virtually every engineer at Postman had to learn how to handle dropped connections, initiate new ones, and then reconcile any conflicts in the data.</li>
</ul>
<p>The Server Foundation team knew they wanted to increase the efficiency of websocket connections, and also handle them separately from the Sync service. The destination was clear, but the path to get there was not.</p>
<blockquote>
<p><em>“This is the natural evolution of software design. Microservices start nimble, but they build up, and need to be broken back down. We wanted to separate socket handling from Sync because we were about to introduce a lot more functionality.”</em> -<a target="_blank" href="https://www.linkedin.com/in/yashishdua/">Yashish Dua</a>, software engineer at Postman</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163492910/0dcc616c-3306-490d-ac7f-253f80c2873d.png" alt /></p>
<p><em>some internal services grow too big requiring careful coordination across teams</em></p>
<h3 id="heading-here-is-what-happened">Here is what happened</h3>
<h4 id="heading-step-1-we-got-organizational-buy-in">Step 1: We got organizational buy-in</h4>
<p>The first challenge to tackle was not a technical one. This was not Postman’s first ambitious rollout. Engineering had learned from past go-arounds to begin with the people. Starting in October of 2019, the Server Foundation engineers held a series of reviews dedicated to communicating the goal to the broader organization, and explaining the benefit for all dependent services.</p>
<p>If this new system succeeded, handling dropped connections and dealing with the aftermath would no longer be commonplace. This was a real incentive for the other engineering teams to support and migrate to the new system. This open communication and coordination would continue throughout the duration of this project.</p>
<h4 id="heading-step-2-we-identified-the-unknown-unknowns">Step 2: We identified the unknown unknowns</h4>
<p>Engineering knew the direction they were heading in. Despite that, they took some time to think through all the scenarios and better understand the underlying concepts. The engineers scheduled exploratory sessions with other stakeholders to identify unknown unknowns, the unforeseeable conditions which can pose a greater risk than the known knowns.</p>
<p>While the Postman organization is used to researching and planning, this part of the process took a lot longer than normal due to the critical nature of this change. They researched different options, considered auxiliary requirements, and came up with a plan over the course of two months.</p>
<h4 id="heading-step-3-we-built-the-bifrost-websocket-gateway">Step 3: We built the Bifrost websocket gateway</h4>
<p>The Bifrost is composed of two parts:</p>
<ul>
<li><strong>Public gateway</strong>: The gateway uses the Fastify web framework and Amazon AWS ElastiCache for Redis as a central message broker to manage all websocket connections.</li>
<li><strong>Private API</strong>: The API also uses Fastify as a low overhead web framework to proxy traffic to other internal Postman services.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163494106/c44d87e8-a96c-407a-ad88-1d270a60e0cf.png" alt /></p>
<p><em>Bifrost is composed of two parts: a public gateway and a private API</em></p>
<h4 id="heading-step-4-we-tested-the-new-gateway">Step 4: We tested the new gateway</h4>
<p>When Postman engineers are ready to ship a feature, they are expected to test the feature, along with any related features. Since almost every Postman feature relies on websockets, this meant every single feature had to be tested for this release. Furthermore, a framework for <a target="_blank" href="https://www.postman.com/automated-testing/">automated testing</a> of websockets had not <em>yet</em> been set up at Postman, so all the testing was completed manually before Bifrost could be used in production.</p>
<p>This was an arduous journey, but by the end of January 2020, engineering had a working proof of concept.</p>
<h4 id="heading-step-5-we-migrated-to-the-new-gateway">Step 5: We migrated to the new gateway</h4>
<p>All Postman clients, such as the Electron app or the Web, rely on an initial bootstrap call to another core service named Godserver. This server determines the clients’ access and configuration, and is how engineering controls incremental product rollouts. Because this was all predetermined and controlled by the Godserver, migrating to the Bifrost gateway would not require a single Postman client code update.</p>
<p>The Server Foundation team outlined the squads’ migration steps, the required code changes and configuration to apply. Over the course of a few weeks, dependent services began transitioning from relying on Sync to Bifrost-based handling of their websocket connections. The Godserver diverted more and more traffic to the new websocket gateway to see how Bifrost handled the load and responded to edge cases.</p>
<blockquote>
<p><em>“It’s like changing an engine on an aircraft in mid-flight.”</em> -<a target="_blank" href="https://www.linkedin.com/in/numaanashraf/">Numaan Ashraf</a>, director of engineering at Postman</p>
</blockquote>
<h4 id="heading-step-6-we-scaled-the-service">Step 6: We scaled the service</h4>
<p>The Bifrost gateway was working!</p>
<p>But Postman had acquired another million or so users while the gateway was in planning and development. And the other engineering teams had not paused their own work during this time. New collaboration features, like <a target="_blank" href="https://learning.postman.com/docs/collaborating-in-postman/version-control-for-collections/">version control</a> and <a target="_blank" href="https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#roles-in-postman">role-based access control (RBAC)</a>, relied heavily on websockets for information to be updated in real time. There was a flood of upcoming product releases that would truly test the new gateway.</p>
<p>Bifrost was ready to support the increased demands and scale websocket handling.</p>
<ul>
<li><strong>Horizontal scaling</strong>: Most of the time, Postman services handle increased usage by either scaling to higher capacity instances or by adding more compute instances to the fleet. So engineers at Postman usually scale <strong><em>up</em></strong> a service by increasing the size and computing power of AWS EC2 instances, for example, by using AWS Elastic Beanstalk. But for Bifrost, websocket handling scales <strong><em>out</em></strong> by using <strong><em>more</em></strong> machines. Its optimum efficiency is achieved when smaller-sized instances are used in large numbers. This type of hyper-horizontal scaling works well for Bifrost because clients don’t require high network throughput, and limiting each machine to fewer connections limits the blast radius of failures.</li>
<li><strong>New load factor of CPU and memory</strong>: Most Postman services can effectively scale with a single dimension of scaling metric, like CPU, memory, or latency. However, for Bifrost, things get a bit more nuanced because both memory and CPU usage have different impacts on operations at various levels of throughput. To account for that, Bifrost uses a custom scaling metric based on load factor. The load factor is a multidimensional calculation that imparts a custom non-linear scaling profile.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163495326/f5f40ad4-6138-4afc-9681-aec60c190e4a.jpeg" alt /></p>
<p>Let’s dig into the architectural and technology decisions made by Postman engineering.</p>
<h3 id="heading-the-bifrost-architecture-and-tech-stack">The Bifrost architecture and tech stack</h3>
<p>The Bifrost system has two major components-a Gateway and an API. This two-part architecture is the secret sauce to the stability and scalability of the system.</p>
<p>The Gateway acts as the termination point for all websocket connections. Even though commercial gateways are available for purchase, it was important to preserve the legacy business logic accumulated over years of optimization. Postman engineers also wanted to fully control how websockets are handled, for example, if they wanted to tap into the protocol handshake. For the Bifrost gateway, they used Amazon ElastiCache for Redis allowing them to query the Redis cache using reader and writer nodes. Splitting the traffic into two nodes for read and write operations further allows the team to optimize the performance.</p>
<blockquote>
<p><em>“Bifrost is our gateway for all websocket connections. It’s a proxy for all Postman clients, and responsible for handling low-level socket operations for internal Postman services.”</em> -<a target="_blank" href="https://www.linkedin.com/in/mudit-mehta-6920a2113/">Mudit Mehta</a>, software engineer at Postman</p>
</blockquote>
<p>Most every other service at Postman uses <a target="_blank" href="https://sailsjs.com/">Sails</a> as a real-time MVC framework for Node.js. For the Bifrost gateway, however, the engineers needed a performant backend framework capable of handling high volumes with speed and optimized memory usage. Once again, they wanted to go deeper into the socket layer, below the higher-level abstractions provided by Sails. So they turned to <a target="_blank" href="https://www.fastify.io/">Fastify</a> and forked the <a target="_blank" href="https://github.com/socketio/socket.io-adapter">socketio-adapter</a> middleware to optimize for their own use cases.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163496639/0e9be49d-add0-48ed-8e09-206805c4f1c7.png" alt /></p>
<p><em>the Bifrost gateway used AWS, Redis, and Fastify to handle websockets</em></p>
<p>In addition to the gateway, the other component of Bifrost is the private API that proxies traffic to other Postman services. It is based on flexible business rules, and so constantly re-evaluated for how and where to forward inbound traffic.</p>
<blockquote>
<p><em>“Simple components. Complex logic.”</em> -<a target="_blank" href="https://www.linkedin.com/in/kunagpal/">Kunal Nagpal</a>, engineering manager at Postman</p>
</blockquote>
<p>For both components, the engineering team decided to roll their own. Although the gateway part of Bifrost isn’t updated frequently, the team has full control over what happens in the deeper layers of websocket handling. The API part of Bifrost is the brains of the operation and converts incoming real-time messages to standard HTTP calls. It can also be updated more quickly as an independent component from Sync and the Bifrost gateway.</p>
<p>Remember that secret sauce? Decoupling Bifrost into these two discrete systems allows both parts to optimize for their own objectives.</p>
<h3 id="heading-the-journey-is-far-from-over">The journey is far from over</h3>
<p>As with all juicy engineering stories, this isn’t the end. I’ll leave you with a few cliffhangers about what’s coming up next for Postman engineering.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163497434/5ef3e30a-6393-4745-83a9-adbbb484a7fd.jpeg" alt /></p>
<ul>
<li><strong>Build additional redundancy</strong>: The Redis cache is a central message broker. Websocket handling still relies on a single point of failure, so what happens if the cache ever goes down?</li>
<li><strong>Increase bandwidth and throughput</strong>: The gateway is currently capable of handling 10x concurrency, but the Postman community is growing fast and engineering is building out more collaboration features. The need to handle more websocket traffic is coming up quickly.</li>
<li><strong>Continue breaking down the monolith:</strong> The Sync service contains a jumble of other services entwined within its codebase. Decoupling socket handling from Sync loosens its grip on other services, so other services can now be more easily peeled off.</li>
</ul>
<p>This was another behind-the-scenes peek at how Postman engineering operates. Stay tuned for more stories from the trenches.</p>
<p><strong>🙏🏼 Technical review by Kunal Nagpal, Yashish Dua, Mudit Mehta, and Shamasis Bhattacharya.</strong></p>
<p><em>Originally published at</em> <a target="_blank" href="https://blog.postman.com/postman-engineering-million-concurrent-connections/"><em>https://blog.postman.com</em></a> <em>on December 22, 2020.</em></p>
]]></content:encoded></item><item><title><![CDATA[The Good Documentation Checklist]]></title><description><![CDATA[See how you measure up to these nine better practices for Postman documentation
I’ve previously talked about the traits of a good collection. While not all collections grow up to be documentation, collections are the foundational building blocks for ...]]></description><link>https://blog.joycejetson.com/the-good-documentation-checklist-1ef992192f15</link><guid isPermaLink="true">https://blog.joycejetson.com/the-good-documentation-checklist-1ef992192f15</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Mon, 02 Nov 2020 23:49:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163597308/7bb2bef5-3b24-427e-8de7-26228ba41286.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-see-how-you-measure-up-to-these-nine-better-practices-for-postman-documentation">See how you measure up to these nine better practices for Postman documentation</h4>
<p>I’ve previously talked about <a target="_blank" href="https://blog.postman.com/the-good-collection/">the traits of a good collection</a>. While not all collections grow up to be documentation, collections are the foundational building blocks for all <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/documenting-your-api/">Postman documentation</a> viewable on the web. Here, I’m going to talk about the traits of good documentation.</p>
<p>Postman documentation has become widely adopted across the API community because it enables better collaboration and API adoption. Let’s learn from the thousands of publishers who document their APIs in Postman — like <a target="_blank" href="https://docs.microsoft.com/en-us/graph/use-postman">Microsoft</a>, <a target="_blank" href="https://documenter.getpostman.com/view/9956214/T1LMiT5U">Twitter</a>, and <a target="_blank" href="https://documenter.getpostman.com/view/12072907/T1DjjKE7">Dropbox</a> — and find out what makes their documentation successful.</p>
<h3 id="heading-what-is-good-documentation">What is good documentation?</h3>
<p>Effective documentation teaches someone how to use your API. Since the intended audience is people, and not machines, effectiveness is a subjective measure. Still, we can find some shared similarities across good documentation.</p>
<p>Take a look at this breakdown of nine helpful documentation tips and see how your own process measures up.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163592654/fe9b621d-bf10-45c8-b540-15cf3826c0fa.png" alt /></p>
<p><em>An interactive version of this blog post in a collection called</em> <a target="_blank" href="https://documenter.getpostman.com/view/1559645/TVYGbHs1"><em>The Good Documentation Checklist</em></a></p>
<blockquote>
<p><strong><em>In true Postman fashion, I’ve documented these guidelines in a collection. You can experience an interactive version of this blog post in</em></strong> <a target="_blank" href="https://documenter.getpostman.com/view/1559645/TVYGbHs1"><strong><em>The Good Documentation Checklist</em></strong></a> <strong><em>template, which is comprised of examples from publishers who document their APIs in Postman.</em></strong></p>
</blockquote>
<h3 id="heading-step-1-create-a-postman-collection">Step 1. <strong>Create a Postman Collection</strong></h3>
<h4 id="heading-generate-from-an-api-specification">✅ <strong>Generate from an API specification</strong></h4>
<p>If you’re using an API specification format, such as <a target="_blank" href="https://blog.postman.com/openapi-specification-postman-how-to/">OpenAPI</a>, you can <a target="_blank" href="https://learning.postman.com/docs/getting-started/importing-and-exporting-data/#importing-api-specifications">import a spec file</a> into Postman to automatically generate a collection. Once you have a collection, you can automatically generate web-viewable Postman documentation.</p>
<h4 id="heading-find-a-collection">✅ <strong>Find a collection</strong></h4>
<p>It’s possible someone else has already done the heavy lifting of creating a collection. Check with your teammates to see if they have a collection that can provide a starting point for the full-fledged collection. Or, you may discover that community members are sharing unofficial collections documenting your <a target="_blank" href="https://www.postman.com/api-network/">public API</a>.</p>
<h4 id="heading-start-from-scratch">✅ <strong>Start from scratch</strong></h4>
<p>If you’re starting from scratch, you can import cURL as raw text for each API call. Or as a last resort, input every endpoint’s URL, method, etc.</p>
<h3 id="heading-step-2-organize-the-api-metadata">Step 2. <strong>Organize the API metadata</strong></h3>
<h4 id="heading-verify-the-request-metadata">✅ <strong>Verify the request metadata</strong></h4>
<p>If you previously used a machine-readable data format, consider renaming your requests to be more human-readable. Verify the API metadata (e.g. method, URL, headers) displays in the way you want.</p>
<h4 id="heading-organize-logically-in-folders">✅ <strong>Organize logically in folders</strong></h4>
<p>If your collection contains lots of requests, stay clean and tidy by ordering and grouping requests in <a target="_blank" href="https://learning.postman.com/docs/sending-requests/intro-to-collections/#managing-collections">folders</a> to make the documentation easier to navigate.</p>
<h4 id="heading-add-and-format-descriptions">✅ <strong>Add and format descriptions</strong></h4>
<p>Provide a <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/authoring-your-documentation/#documenting-with-descriptions">description</a> for each parameter, request, folder, and collection. Style your descriptions, add tables, and embed screenshots <a target="_blank" href="https://learning.postman.com/docs/postman/collections/using_markdown_for_descriptions/">using Markdown</a> so readers can quickly identify the most relevant details. You will author the content inside Postman in Markdown, but consumers will view it in the web browser as HTML.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163593857/176335ac-f42d-4172-94a7-a47209e23381.png" alt /></p>
<p><a target="_blank" href="https://documenter.getpostman.com/view/9956214/T1LMiT5U"><em>Twitter API documentation</em></a> <em>with metadata, examples, and folders</em></p>
<h3 id="heading-step-3-include-a-getting-started-guide">Step 3. <strong>Include a Getting Started guide</strong></h3>
<h4 id="heading-add-headings-in-the-introduction">✅ <strong>Add headings in the Introduction</strong></h4>
<p>The collection description should include relevant information about rate limiting, content types, or settings that apply across endpoints. Any h1 heading that you add to the collection description automatically displays in the side navigation. This makes it easier for the reader to scan for important sections of the documentation.</p>
<h4 id="heading-explain-authorization">✅ <strong>Explain authorization</strong></h4>
<p>The collection description is also a good place to be explicit about how to authorize requests — including instructions explaining what developers need to do to acquire and use credentials. Additionally, Postman has <a target="_blank" href="https://learning.postman.com/docs/sending-requests/authorization/">auth helpers</a> under the <strong>Authorization</strong> tab to help get users interacting with your API quickly. Some publishers choose to manually add authorization headers under the <strong>Headers</strong> tab of a request, but you can also add an authorization type for an entire folder or collection.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163594877/1c3d7806-3821-49a5-9368-ffd397f7873c.png" alt /></p>
<p><a target="_blank" href="https://documenter.getpostman.com/view/12072907/T1DjjKE7"><em>Dropbox documentation</em></a> <em>includes headings in the Introduction and explains Authorization using screenshots for more guidance</em></p>
<h3 id="heading-step-4-keep-it-dry-with-variables">Step 4. <strong>Keep it DRY with variables</strong></h3>
<h4 id="heading-use-variables">✅ <strong>Use variables</strong></h4>
<p>Just like in programming, <a target="_blank" href="https://learning.postman.com/docs/sending-requests/variables/#variable-scopes">Postman variables</a> make it easy to change a value in one spot and propagate those changes throughout a collection so you can keep your code DRY (Don’t Repeat Yourself) instead of WET (Write Everything Twice).</p>
<h4 id="heading-consider-variable-scopes">✅ <strong>Consider variable scopes</strong></h4>
<p>Postman supports several variable types and scopes to support different scenarios. For example, a collection variable is useful when the value is inextricably linked to a particular collection. Environment variables can be decoupled from the collection to be used with another collection (e.g. user authorization tokens or server configuration details).</p>
<h4 id="heading-add-placeholder-text">✅ <strong>Add placeholder text</strong></h4>
<p>Postman relies on string substitution to render variable values in the web documentation. Use placeholder text as a variable’s value to indicate what value to use. If you leave the value blank, Postman displays no information in the documentation.</p>
<h3 id="heading-step-5-show-use-cases">Step 5. <strong>Show use cases</strong></h3>
<h4 id="heading-provide-examples">✅ <strong>Provide examples</strong></h4>
<p>Save <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/authoring-your-documentation/#using-examples-in-your-docs">examples</a> of requests and responses so users can understand the endpoint and troubleshoot issues more quickly. This is especially useful when a user is browsing the documentation and doesn’t yet have their access credentials. Ensure that these examples contain readable, prototypical usage of your API endpoints.</p>
<h4 id="heading-demonstrate-scenarios">✅ <strong>Demonstrate scenarios</strong></h4>
<p>Good documentation is more than just API reference. It includes user scenarios to show what is possible with the API. Guide new users through the proper sequence of API calls to accomplish a specific workflow <a target="_blank" href="https://blog.postman.com/how-to-make-money-using-postman-chaining-requests/">using variables to pass along data</a>. These use cases can be grouped in folders or as a stand-alone collection.</p>
<h3 id="heading-step-6-be-secure">Step 6. <strong>Be secure</strong></h3>
<h4 id="heading-use-variables-for-secrets">✅ <strong>Use variables for secrets</strong></h4>
<p>Another great use for variables is <a target="_blank" href="https://blog.postman.com/how-to-use-api-keys/">to store your secrets</a> instead of hard-coding your confidential data. Remember to update your secrets with placeholder text, so you don’t leak any confidential information.</p>
<h4 id="heading-set-up-a-sandbox-environment">✅ <strong>Set up a sandbox environment</strong></h4>
<p>Some publishers have an isolated testing environment called a sandbox. This allows users to play around with the API without incurring any costs or side effects in a production environment. You can show users how to interact with your sandbox by pre-populating a collection and environment with the sandbox domain and test credentials.</p>
<h3 id="heading-step-7-share-private-api-documentation">Step 7. <strong>Share private API documentation</strong></h3>
<h4 id="heading-collaborate-with-teammates">✅ <strong>Collaborate with teammates</strong></h4>
<p>Share your API documentation with teammates by sharing the collection to a <a target="_blank" href="https://learning.postman.com/docs/collaborating-in-postman/collaboration-intro/">team workspace</a>. The default role is that anyone is a “Viewer” of the collection but you can grant “Editor” capabilities to trusted team members. <a target="_blank" href="https://learning.postman.com/docs/collaborating-in-postman/version-control-for-collections/#forking-a-collection">Fork</a> and then merge the collection so you can choose when to work independently versus collaboratively.</p>
<h3 id="heading-step-8-share-public-api-documentation">Step 8. <strong>Share public API documentation</strong></h3>
<h4 id="heading-publish-the-documentation">✅ <strong>Publish the documentation</strong></h4>
<p>In addition to sharing API documentation privately, you can also share collections and environments publicly as web-viewable documentation. Documentation is based on a Postman collection, so you can <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/documenting-your-api/#documenting-an-existing-collection">generate it from an existing collection</a> or <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/documenting-your-api/#creating-documentation-for-a-new-collection">create it in conjunction with a new collection</a>.</p>
<h4 id="heading-embed-the-run-in-postman-button">✅ <strong>Embed the Run in Postman button</strong></h4>
<p>The <strong>Run in Postman</strong> button is one way to share a Postman collection (and optional environment). This button is found in the <a target="_blank" href="https://explore.postman.com/">Postman API Network</a>, at the top of published documentation in the web, and also where publishers embed the stand-alone button (like in a README or developer portal).</p>
<h4 id="heading-add-it-to-the-api-network">✅ <strong>Add it to the API Network</strong></h4>
<p>When you share API documentation publicly, you can also list those collections in the <a target="_blank" href="https://explore.postman.com/">Postman API Network</a> for broader discovery. Make sure to add a concise description and tags so users can easily identify relevant APIs.</p>
<h4 id="heading-spruce-up-your-profile">✅ <strong>Spruce up your profile</strong></h4>
<p>When you publish a collection, you can do that from either a <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/add-templates/#setting-up-your-profile">personal profile</a> or <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/add-api-network/#setting-up-your-team-profile">team profile</a>. Taking the time to fill out your team profile gives readers a clear sense of who a collection is published by helping them to decide whether to try it out or not. You can add a name, description, photo, and custom URL.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163595968/3c317697-1c4f-4639-87a6-de9a3fec51a0.png" alt /></p>
<p><em>Example of a</em> <a target="_blank" href="https://explore.postman.com/263615"><em>Team profile page</em></a> <em>listing multiple collections in the Postman API Network</em></p>
<p>If you’ve ticked most of these boxes, then you can confidently say that you have <strong>good documentation</strong>. For all you overachievers, let’s forge ahead to a bonus round.</p>
<h3 id="heading-step-9-advanced-stuff">Step 9. <strong>Advanced stuff</strong></h3>
<h4 id="heading-add-scripts">✅ <strong>Add scripts</strong></h4>
<p>You can add JavaScript that executes before or after a request runs. These <a target="_blank" href="https://learning.postman.com/docs/writing-scripts/intro-to-scripts/">pre-request and test scripts</a> are useful for setting and getting variable values. Writing scripts is also good for debugging, like logging output to the console. If you find yourself reusing a lot of scripts, you can add them to entire collections or folders to run along with every request within that collection or folder.</p>
<h4 id="heading-keep-track-of-metrics">✅ <strong>Keep track of metrics</strong></h4>
<p>Postman displays some information like views and imports of your documentation collection. Some publishers will add a custom header to requests in their Postman collection for the purpose of inspecting traffic that comes from the Postman client. This gives them more traceability and insights into how users are interacting with their endpoints from Postman.</p>
<h4 id="heading-helpful-error-messages">✅ <strong>Helpful error messages</strong></h4>
<p>Publishers have developed clever ways to provide feedback to users who are learning their APIs. Some use helpful error messages returned from the server to guide users along their journey. Others rely on Postman log statements or tests to interpret the client request or standard server response and prompt users to update their API call appropriately.</p>
<h4 id="heading-visualize-the-api-response">✅ <strong>Visualize the API response</strong></h4>
<p>Another way you can make each API request more informative is to use the <a target="_blank" href="https://learning.postman.com/docs/sending-requests/visualizer/">Postman Visualizer</a> to visualize the response or provide more detail about what actions can be taken next by the API consumer. Providing built-in visualizations and responses can guide consumers through the API’s highlights, making it more of a hands-on journey.</p>
<h3 id="heading-more-examples-of-good-documentation">More examples of good documentation</h3>
<p>If you’re looking for benchmarks of good documentation collections, check out these stars:</p>
<h4 id="heading-ping-identity"><strong>Ping Identity</strong></h4>
<p>Ping Identity has a number of public APIs listed on their <a target="_blank" href="https://explore.postman.com/263615">Ping Identity team profile page</a>. In the <a target="_blank" href="https://documenter.getpostman.com/view/1848580/T17Q6jdj">PingOne Platform APIs</a> collection, endpoints are organized neatly into folders, markdown tables summarize required and optional variables, and technical diagrams provide a general overview for readers.</p>
<h4 id="heading-dropbox"><strong>Dropbox</strong></h4>
<p>Dropbox has a single documentation collection with <a target="_blank" href="https://documenter.getpostman.com/view/12072907/T1DjjKE7">workflows for team admins</a> listed on their <a target="_blank" href="https://explore.postman.com/43fWSHmB4AFWXr">Dropbox team profile page</a>. This collection is unique in that it’s not intended for API reference, but rather for Dropbox team admins to execute specific workflows and tasks. The collection is kind of like an admin panel or internal tool, executing scripts in Postman.</p>
<h4 id="heading-twitter">Twitter</h4>
<p>Twitter has two profile pages for their <a target="_blank" href="https://explore.postman.com/356847">Developer Labs</a> and <a target="_blank" href="https://explore.postman.com/TwitterAdsAPI">Twitter Ads</a> teams. For the <a target="_blank" href="https://documenter.getpostman.com/view/9956214/T1LMiT5U">Twitter API v2</a>, they’ve included examples demonstrating practical scenarios like <code>429 Rate limit exceeded</code> and <code>200 Request Tweet fields</code>. When you import this collection, you can also see a collection-level script that runs before every request in the collection to retrieve a Bearer token from the client credentials that you provide in your environment file.</p>
<h4 id="heading-rich-data-services">Rich Data Services</h4>
<p>Rich Data Services provides a wealth of information with their data APIs, providing all the information you need to <a target="_blank" href="https://documenter.getpostman.com/view/2220438/SzYevv9u?version=latest">understand what is being offered with their COVID-19 APIs</a>. Notice that every API request has a visualization that guides you through how to use each individual API.</p>
<p>Many of the better practices we’ve talked about are universal truths about docs, whether or not you’re documenting your APIs with Postman. If you’ve read this far, chances are you’re thinking about investing in proper onboarding and developer education for your APIs.</p>
<p>Come on over and <a target="_blank" href="https://learning.postman.com/docs/publishing-your-api/add-api-network/">join the Postman API Network</a>. Or dig deeper into documentation best practices and check out this post I wrote about <a target="_blank" href="https://medium.com/better-practices/the-ultimate-api-publishers-guide-be74a2692326">The Ultimate API Publisher’s Guide</a>. If you’re doing something neat with API documentation, let us know in a comment below so that we can share it with the rest of the Postman community.</p>
]]></content:encoded></item><item><title><![CDATA[Starlink Satellite SMS Notifications With Python, Kubernetes, and Twilio]]></title><description><![CDATA[Set up a CronJob to check for satellites
Photo by Phil Botha on Unsplash
SpaceX is launching thousands of Starlink satellites to assemble a giant interconnected constellation in space. If you look up at just the right time, you might be lucky enough ...]]></description><link>https://blog.joycejetson.com/starlink-satellite-sms-notifications-with-python-kubernetes-and-twilio-9acc8eba4f9e</link><guid isPermaLink="true">https://blog.joycejetson.com/starlink-satellite-sms-notifications-with-python-kubernetes-and-twilio-9acc8eba4f9e</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Sat, 22 Aug 2020 01:41:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163503754/a9d3f728-0a62-4373-bc23-efb8933fe93e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-set-up-a-cronjob-to-check-for-satellites">Set up a CronJob to check for satellites</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@philbotha?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Phil Botha</a> on <a target="_blank" href="https://unsplash.com/s/photos/star?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>SpaceX is launching thousands of <a target="_blank" href="https://www.starlink.com/">Starlink</a> satellites to assemble a giant interconnected constellation in space. If you look up at just the right time, you might be lucky enough to spot some. But how can you know ahead of time when a satellite is going to pass overhead?</p>
<p>You don’t have to count on luck to see these tiny silver ants parading across the night sky. This tutorial shows you how to set up a scheduled job to check if a satellite approaches and send an SMS alert out to notify you.</p>
<h3 id="heading-tutorial-requirements">Tutorial Requirements</h3>
<ul>
<li>Python version 3</li>
<li>A personal phone number to receive SMS notifications</li>
<li><a target="_blank" href="http://www.twilio.com/referral/geBKT7">A freeTwilio account</a> and a <a target="_blank" href="https://www.twilio.com/user/account/phone-numbers/incoming">Twilio phone number</a> to send SMS notifications</li>
<li>A free <a target="_blank" href="https://hub.docker.com/">Docker Hub</a> account, <a target="_blank" href="https://docs.docker.com/desktop/">Docker Desktop</a> (for Mac or Windows) or <a target="_blank" href="https://docs.docker.com/engine/install/">Docker Engine</a> (for Linux) to build and share containerized applications</li>
<li>A free <a target="_blank" href="https://kubesail.com/">KubeSail account</a> to deploy your code to a Kubernetes cluster</li>
</ul>
<h3 id="heading-set-up-the-python-virtual-environment">Set up the Python virtual environment</h3>
<p>Make a new project directory, and change into the directory from the command line.</p>
<p>$ mkdir starlink-alert<br />$ cd starlink-alert</p>
<p>Create a virtual environment called <code>venv</code>. Activate the virtual environment, and then install the required Python packages inside the virtual environment. If you’re on Unix or Mac operating systems, enter these commands in a terminal.</p>
<p>$ python3 -m venv venv<br />$ source venv/bin/activate<br />(venv) $ pip install twilio python-dotenv datetime pytz skyfield</p>
<p>If you’re on a Windows machine, enter these commands in a command prompt window.</p>
<p>$ python -m venv venv<br />$ venv\Scripts\activate<br />(venv) $ pip install twilio python-dotenv datetime pytz skyfield</p>
<p>The Python packages we’re using are:</p>
<ul>
<li><a target="_blank" href="https://github.com/twilio/twilio-python">Twilio’s Python Library</a> — a Python module for communicating with the Twilio API</li>
<li><a target="_blank" href="https://pypi.org/project/python-dotenv/">python-dotenv</a> — to manage environment variables</li>
<li><a target="_blank" href="https://docs.python.org/3/library/datetime.html">datetime</a> and <a target="_blank" href="http://pytz.sourceforge.net/">pytz</a> — to handle dates, times, and timezones</li>
<li><a target="_blank" href="https://rhodesmill.org/skyfield/">skyfield</a> — to compute positions for the satellites in orbit around the Earth</li>
</ul>
<h3 id="heading-write-the-python-script">Write the Python script</h3>
<p>The purpose of the script is to check if a visible satellite is approaching a given city location. If so, your Twilio phone number sends an SMS alert to your personal phone number.</p>
<p>Copy the following code into a file called <code>tracker.py</code>:</p>
<p>import os<br />import math<br />from dotenv import load_dotenv<br />load_dotenv()<br />from skyfield.api import Topos, load<br />from datetime import timedelta<br />from pytz import timezone<br />from twilio.rest import Client</p>
<p># load the satellite dataset from Celestrak<br />starlink_url = 'https://celestrak.com/NORAD/elements/starlink.txt'<br />starlinks = load.tle_file(starlink_url)<br />print ('Loaded', len(starlinks), 'satellites')</p>
<p># update city location and timezone<br />location = Topos('37.7749 N', '122.4194 W')<br />tz = timezone('US/Pacific')</p>
<p># establish time window of opportunity<br />ts = load.timescale()<br />t0 = ts.now()<br />t1 = ts.from_datetime(t0.utc_datetime()+ timedelta(hours=2))</p>
<p># loop through satellites to find next sighting<br />first_sighting = {}<br />for satellite in starlinks:</p>
<h1 id="heading-filter-out-farthest-satellites-and-nan-elevation">filter out farthest satellites and NaN elevation</h1>
<p>   elevation = satellite.at(t0).subpoint().elevation.km<br />   isNan = math.isnan(elevation)<br />   if elevation &gt; 400 or isNan: continue<br />   print ('considering: {} at {}km'.format(<br />       satellite.name,<br />       round(elevation)<br />   ))</p>
<h1 id="heading-find-and-loop-through-rise-set-events">find and loop through rise / set events</h1>
<p>   t, events = satellite.find_events(location, t0, t1, altitude_degrees=30.0)<br />   for ti, event in zip(t, events):  </p>
<h1 id="heading-check-if-satellite-visible-to-a-ground-observer">check if satellite visible to a ground observer</h1>
<p>       eph = load('de421.bsp')<br />       sunlit = satellite.at(t1).is_sunlit(eph)<br />       if not sunlit: continue</p>
<h1 id="heading-filter-by-moment-of-greatest-altitude-culminate">filter by moment of greatest altitude - culminate</h1>
<p>       name = ('rise above 30°', 'culminate', 'set below 30°')[event]<br />       if (name != 'culminate'): continue  </p>
<h1 id="heading-find-earliest-time-for-next-sighting">find earliest time for next sighting</h1>
<p>       if (not first_sighting) or (ti.utc &lt; first_sighting['time']):<br />           first_sighting['time_object'] = ti<br />           first_sighting['time'] = ti.utc<br />           first_sighting['satellite'] = satellite</p>
<p>if (first_sighting): </p>
<h1 id="heading-create-body-for-sms">create body for SMS</h1>
<p>   next_sighting = ('next sighting: {} {}'.format(<br />       first_sighting['satellite'].name,<br />       first_sighting['time_object'].astimezone(tz).strftime('%Y-%m-%d %H:%M')<br />   ))</p>
<h1 id="heading-send-sms-via-twilio-if-upcoming-sighting">send SMS via Twilio if upcoming sighting</h1>
<p>   account_sid = os.environ.get('TWILIO_ACCOUNT_SID')<br />   auth_token = os.environ.get('TWILIO_AUTH_TOKEN')<br />   client = Client(account_sid, auth_token)</p>
<p>   message = client.messages.create(<br />       body=next_sighting,<br />       from_=os.environ.get('TWILIO_PHONE_NUMBER'),<br />       to=os.environ.get('MY_PHONE_NUMBER')<br />   )</p>
<p>   print ('Message sent:', message.sid, next_sighting)</p>
<p>else:</p>
<p>   print ('No upcoming sightings')</p>
<p>Update variables <code>location</code> and <code>tz</code> on rows 16 to 17 with your own geographic coordinates and timezone. You can find your latitude and longitude <a target="_blank" href="https://www.latlong.net/">here</a>. See all the timezones by running the following code in a Python shell. Once you find the timezone that applies to your location, exit the Python shell.</p>
<p>(venv) $ python<br />&gt;&gt;&gt; import pytz<br />&gt;&gt;&gt; pytz.all_timezones<br />&gt;&gt;&gt; exit()</p>
<p>The <code>tracker.py</code> script relies on a Python package called Skyfield to handle some of the complex space computations. The script loads the satellite dataset, looping through the satellites to find the next good sighting. Skyfield figures out when a satellite rises and sets near you and sees if the satellite is sunlit for maximum visibility. If there are any sightings predicted within the next two hours, Twilio sends the details with an SMS to your phone number.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163500754/411ebbee-f975-491e-98c2-44a85e7c59e8.jpeg" alt /></p>
<p>The Starlink 3 train rides across the early morning sky, photo by <a target="_blank" href="https://unsplash.com/@forestkatsch?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Forest Katsch</a> on <a target="_blank" href="https://unsplash.com/s/photos/starlink?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>To enable the Twilio SMS, store your credentials and other configuration information in a file called <code>.env</code> (notice the dot in front of this filename).</p>
<p>TWILIO_ACCOUNT_SID=<br />TWILIO_AUTH_TOKEN=<br />TWILIO_PHONE_NUMBER=<br />MY_PHONE_NUMBER=</p>
<p>To find your Twilio Account SID and Auth Token, log into the Twilio Console, then click on “Settings” in the sidebar and scroll down to “API Credentials”. You will also need your Twilio phone number to send the SMS.</p>
<p>Save your updates to the <code>.env</code> file, and then run the script from the command line. If you’re running the script during the day, you might determine a satellite is passing overhead, but not be able to see it very well in the daylight. Once you set up a CronJob, you can specify when to run the script for maximum satellite visibility, like at dusk or dawn.</p>
<p>(venv) $ python tracker.py</p>
<p>After you try the script and confirm that it is working, create a requirements file to store the dependencies, so that we can install them in the next step.</p>
<p>(venv) $ pip freeze &gt; requirements.txt</p>
<p>Now, let’s create a Docker image to run the script.</p>
<h3 id="heading-create-a-docker-image-and-push-to-docker-hub">Create a Docker image and push to Docker Hub</h3>
<p>Make sure Docker is installed and running on your machine. Add the following code in a file called <code>Dockerfile</code> (notice there’s no file extension) that describes how to build our image.</p>
<p># creates a layer from the python:3 Docker image<br />FROM python:3</p>
<p># copy and install dependencies<br />COPY requirements.txt /<br />RUN pip install -r requirements.txt</p>
<p># add script<br />COPY tracker.py /</p>
<p># define the command to run the script<br />CMD [ "python", "./tracker.py" ]</p>
<p>Next, we are going to build and run a Docker image for the Python script from the terminal. In the following commands, the image we are building is called <code>python-starlink</code> and the container is called <code>starlink_test</code>. Since we don’t want to include our environment variables in the container for security reasons, we run the container using the <code>--env-file</code> flag in the command line. If you’re on a Linux operating system, precede these <code>docker</code> commands with <code>sudo</code> or <a target="_blank" href="https://docs.docker.com/engine/install/linux-postinstall/">create a docker group</a>.</p>
<p>$ docker build --tag python-starlink .<br />$ docker run --name starlink_test --env-file=.env --rm python-starlink</p>
<p>Once you verify that the container runs successfully, share the Docker image on the <a target="_blank" href="https://hub.docker.com/">Docker Hub</a> registry so it can be accessed and run from the cloud. Log into your Docker Hub account from the command line with <code>docker login</code>. Then create a repository and push your image to Docker Hub using the following commands:</p>
<p>$ docker tag python-starlink /python-starlink:latest<br />$ docker push /python-starlink:latest</p>
<p>In the above commands, <code>Your Docker ID</code> is the username you have registered with Docker Hub.</p>
<p>In the next step, let’s schedule a Kubernetes CronJob to run the Python script.</p>
<h3 id="heading-deploy-a-cronjob-on-kubernetes">Deploy a CronJob on Kubernetes</h3>
<p>Make sure you are logged into <a target="_blank" href="https://kubesail.com/">KubeSail</a>. KubeSail has public YAML examples. I made a CronJob template called <code>[satellites](https://kubesail.com/template/loopDelicious/satellites)</code> that has two kinds of Kubernetes resources:</p>
<ul>
<li><a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/secret/">Secrets</a> to securely store environment variables</li>
<li><a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/">CronJob</a> to complete a task on a schedule</li>
</ul>
<p>Go to the <code>[satellites](https://kubesail.com/template/loopDelicious/satellites)</code> template. Under “Required Variables”, replace the default <code>DOCKER-IMAGE</code> with the base image you just pushed to Docker Hub. Then input the remaining environment variables.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163501654/f5ef77d9-6d99-4aba-b76a-1c065d09fa46.png" alt /></p>
<p>If you want to inspect the YAML, click “Edit Yaml” to expand the code editor and review the underlying configuration for each resource. This YAML describes the resource <code>CronJob</code>.</p>
<p>apiVersion: batch/v1beta1<br />kind: CronJob<br />metadata:<br />  name: starlink<br />  labels:<br />    app: starlink<br />spec:<br />  schedule: "0/30 19-21 * * *"<br />  jobTemplate:<br />    spec:<br />      template:<br />        spec:<br />           restartPolicy: Never<br />          containers:  </p>
<ul>
<li>name: starlink-tracker<br />image: "{{DOCKER-IMAGE|joycelin79/python-starlink:latest}}"<br />envFrom:  <ul>
<li>secretRef:<br />  name: starlink-secret<br />imagePullPolicy: Always<br />successfulJobsHistoryLimit: 3<br />failedJobsHistoryLimit: 1</li>
</ul>
</li>
</ul>
<p>This YAML describes the resource <code>Secret</code> to store our environment variables.</p>
<p>apiVersion: v1<br />kind: Secret<br />metadata:<br />  name: starlink-secret<br />  labels:<br />    app: starlink<br />stringData:<br />  TWILIO_ACCOUNT_SID: "{{TWILIO-ACCOUNT-SID}}"<br />  TWILIO_AUTH_TOKEN: "{{TWILIO-ACCOUNT-SID}}"<br />  TWILIO_PHONE_NUMBER: "{{TWILIO-PHONE-NUMBER}}"<br />  MY_PHONE_NUMBER: "{{MY-PHONE-NUMBER}}"</p>
<p>When you’re ready, hit “Launch Template” to deploy a cluster to your Kubernetes namespace on KubeSail.</p>
<p>In the sidebar under “Resources”, you can see all the resources running in this Kubernetes context including the scheduled jobs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163502464/c821c2cc-4abe-4b62-bfcd-e3607e5e09a8.png" alt /></p>
<p>This is also where you can update the deployment. For example, update your environment variables in the <code>Secret</code> resource. To trigger a job every minute while you’re testing, update the YAML configuration for the <code>CronJob</code> resource and set the <code>schedule</code> to <code>"* * * * *"</code>(surrounded in double-quotes) and <strong>Apply</strong> your changes.</p>
<p>To edit the underlying Python script, save the changes locally in <code>tracker.py</code>. Then build and push the updated image to Docker Hub as we did before. The Kubernetes CronJob in KubeSail automatically pulls the latest version in Docker Hub because we specified <code>imagePullPolicy: Always</code> in our container configuration.</p>
<p>And that’s it!</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Creating an SMS notification is pretty straightforward. There’s a bunch of ways to do this — and now you know how to schedule a CronJob on Kubernetes.</p>
<p>For further exploration, you can:</p>
<ul>
<li><strong>Adjust the criteria:</strong> Each batch of Starlink satellites spreads out over time traveling to a higher elevation. If you want to increase the sensitivity of your tracker to see more satellites, adjust the elevation in your script. Or update the Cron schedule to run <a target="_blank" href="https://www.space.com/6870-spot-satellites.html">when satellites are most visible from the ground</a> — at dusk and dawn.</li>
<li><strong>Change the deployment</strong>: Set up a different Kubernetes context in KubeSail to deploy the CronJob to a cluster running locally or on another cloud provider. Or experiment with <a target="_blank" href="https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/">other CronJob options in Kubernetes</a>.</li>
<li><strong>Track something else</strong>: If satellites aren’t your thing, swap it out for <a target="_blank" href="https://celestrak.com/">a new dataset of celestial bodies</a>.</li>
</ul>
<p>Let me know if you spot something out of this world!</p>
]]></content:encoded></item><item><title><![CDATA[Run a Minecraft server for free on Kubernetes]]></title><description><![CDATA[Simplify deployment for multiplayer Minecraft on a self-hosted Raspberry Pi server using Kubernetes
Photo by Nina PhotoLab on Unsplash
Just like Minecraft is more fun when a friend shows you how to make torches and avoid creepers, Kubernetes is also ...]]></description><link>https://blog.joycejetson.com/run-a-minecraft-server-for-free-on-kubernetes-ac82a892969e</link><guid isPermaLink="true">https://blog.joycejetson.com/run-a-minecraft-server-for-free-on-kubernetes-ac82a892969e</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Wed, 29 Jul 2020 00:21:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163619398/0bd159a4-8e31-475b-941b-29d6e8d33edf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-simplify-deployment-for-multiplayer-minecraft-on-a-self-hosted-raspberry-pi-server-using-kubernetes">Simplify deployment for multiplayer Minecraft on a self-hosted Raspberry Pi server using Kubernetes</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@nina_eyes?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Nina PhotoLab</a> on <a target="_blank" href="https://unsplash.com/s/photos/minecraft?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>Just like Minecraft is more fun when a friend shows you how to make torches and avoid creepers, Kubernetes is also less scary with someone to guide the way.</p>
<p>The Minecraft wiki has lots of pointers for <a target="_blank" href="https://minecraft.gamepedia.com/Tutorials/Setting_up_a_server">setting up your own server</a>. But it doesn’t say how to do it with Kubernetes. I recently learned how easy it is <a target="_blank" href="https://medium.com/@joycelin.codes/ddclient-c9a6ac1d8f81?source=friends_link&amp;sk=71085ae2ef2612b40cda0130496d1410">to deploy an app to a local Raspberry Pi with Kubernetes</a>.</p>
<p>Let’s try it again — this time to run a free Minecraft server on Kubernetes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163599469/c46ae036-1d62-4d83-9c67-a151ce3bf78b.jpeg" alt /></p>
<p>Running a Minecraft server on Kubernetes? Piece of cake!</p>
<h3 id="heading-why-kubernetes-instead-of-just-docker">Why Kubernetes instead of just Docker?</h3>
<p>At a busy airport, air traffic controllers manage the flow of aircraft into and out of the airport airspace.</p>
<ul>
<li><strong>Aircraft</strong> transport passengers and cargo from one city to another. The pilots don’t know much about how the airport is managed. They don’t worry about the other aircraft because they rely on air traffic controllers to keep them safe and moving.</li>
<li><a target="_blank" href="https://www.bls.gov/ooh/transportation-and-material-moving/air-traffic-controllers.htm#tab-2"><strong>Air traffic controllers</strong></a> guide pilots during takeoff and landing and monitor aircraft as they travel through the skies. They’re not opinionated about the aircraft and don’t mind any loose chickens running through the aisles 🐔</li>
</ul>
<p>At a less busy airport, you might not need a controller to manage the safety and efficiency of the aircraft. But having one makes operations run smoothly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163600810/b7cc7c9e-0029-4b84-baae-4fca35b557d3.jpeg" alt /></p>
<p>There’s a similar relationship between Docker and Kubernetes. Docker containers package software. Kubernetes is the orchestration system coordinating the behavior of those containers.</p>
<p>There’s a separation of concerns — so your containers don’t care <strong><em>where</em></strong> they run, and the orchestration system doesn’t care <strong><em>what</em></strong> is running inside those containers. If you want a refresher, I’ve previously written an intro to <a target="_blank" href="https://medium.com/better-practices/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9">the basics</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163602116/6ba5c067-8f47-45f7-a113-e6e83524c663.png" alt /></p>
<p>separation of concerns between Docker and Kubernetes</p>
<p>Kubernetes has a reputation of being “hard”. So why go through the trouble of using it on top of Docker for a simple game server? Even if you run a single app with a single data store, as we’ll do today, Kubernetes can simplify deployment.</p>
<p>The friendly, but independent, relationship between Docker and Kubernetes gives us the flexibility to run our app the way we want. For example, I plan to deploy a lightweight C++ version of Minecraft. Later on, I can update my app to the default Java Minecraft server by swapping out the image of the deployment.</p>
<p>Let’s run Minecraft for free by deploying with Kubernetes on a self-hosted Raspberry Pi server.</p>
<h3 id="heading-a-recipe-for-deploying-minecraft-on-kubernetes-with-kubesail">A recipe for deploying Minecraft on Kubernetes with KubeSail</h3>
<p>The Minecraft wiki lists a bunch of tips for <a target="_blank" href="https://minecraft.gamepedia.com/Tutorials/Setting_up_a_server">setting up your own server</a>. The game developers behind Minecraft offer <a target="_blank" href="https://minecraft.gamepedia.com/Server">a free Java version of server software</a>. The open-source community has developed a <a target="_blank" href="https://cuberite.org/">C++ version</a> that’s more lightweight so we can run it on a Raspberry Pi.</p>
<p>Let’s roll our own Minecraft server using Kubernetes.</p>
<ul>
<li>Step 0 — <a class="post-section-overview" href="#4b39">Pre-requisites</a></li>
<li>Step 1 — <a class="post-section-overview" href="#616a">Add a cluster to the Raspberry Pi</a></li>
<li>Step 2 — <a class="post-section-overview" href="#de71">Fork a public template</a></li>
<li>Step 3 — <a class="post-section-overview" href="#6086">Deploy on Kubernetes</a></li>
<li>Step 4 — <a class="post-section-overview" href="#8faf">Connect to the Minecraft server</a></li>
</ul>
<p>Let’s set up a server today!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163603240/9dfca273-915e-4bd7-a7e5-1c2a95c97805.png" alt /></p>
<p>run a Minecraft server on a single-node cluster on Raspberry Pi</p>
<h3 id="heading-step-0-pre-requisites">Step 0: pre-requisites</h3>
<h4 id="heading-kubesail">KubeSail</h4>
<p>Sign up for a <a target="_blank" href="https://kubesail.com/">free KubeSail account</a> — to deploy and manage the apps on our cluster.</p>
<h4 id="heading-kubernetes">Kubernetes</h4>
<p>Decide where to run your Kubernetes cluster. I’m using a $35 <a target="_blank" href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/">Raspberry Pi 4.</a> But you can also use a spare machine if it has enough input/output (I/O) performance to run Minecraft.</p>
<h3 id="heading-step-1-add-a-cluster-to-the-raspberry-pi">Step 1: add a cluster to the Raspberry Pi</h3>
<p>I already have a <a target="_blank" href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/">Raspberry Pi 4</a> to run a Kubernetes cluster. <a target="_blank" href="https://kubesail.com/blog/microk8s-raspberry-pi">This very good tutorial</a> shows us how to set up a cluster on a new Raspberry Pi.</p>
<ul>
<li>Flash an operating system, like <a target="_blank" href="https://ubuntu.com/desktop">Ubuntu</a>, onto an SD card</li>
<li>Enable <a target="_blank" href="https://www.ssh.com/ssh/server">Secure Shell (SSH)</a> to operate a headless Raspberry Pi without a separate keyboard and monitor</li>
<li>Connect the Raspberry Pi directly to the ethernet to reduce latency for gaming — or enable Wi-Fi on the SD card</li>
<li>Move the SD card over to the Raspberry Pi</li>
<li>Log in to the Raspberry Pi using SSH</li>
<li>Install <a target="_blank" href="https://microk8s.io/">MicroK8s</a> — a lightweight Kubernetes recommended for IOT apps, so your terminal commands will be <code>microk8s.kubectl</code> instead of <code>kubectl</code></li>
</ul>
<p>To connect the Raspberry Pi to KubeSail, apply the configuration file to your personal namespace from the Raspberry Pi’s command line. This might take a couple of minutes to spin up.</p>
<p>$ sudo microk8s.kubectl apply -f <a target="_blank" href="https://byoc.kubesail.com/loopdelicious.yaml">https://byoc.kubesail.com/.yaml</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163604391/eed8be65-fc12-4102-92a4-d77d6a6c1a34.gif" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163605651/5011f9f7-c475-46a0-9898-d203008c9b44.gif" alt /></p>
<p>1) add a cluster on the Raspberry Pi using `microk8s.kubectl` instead of `kubectl`, and 2) give it a name</p>
<p>The Raspberry Pi is now a single-node Kubernetes cluster!</p>
<p>You can manage this new cluster in the <a target="_blank" href="https://kubesail.com/clusters">KubeSail dashboard</a>. Find the new cluster, give it a name, and then select <strong>Namespaces</strong> from the sub-menu. This is where you can add a new <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/">Kubernetes namespace</a>, like one called <code>games</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163607084/fbe91542-b66d-45a1-ad48-2a916a90558a.png" alt /></p>
<p>Add a new namespace called `games`</p>
<p>Now we have a <a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#context">Kubernetes context</a> consisting of a cluster, a namespace, and a user — everything that we need to set up our deployment.</p>
<h3 id="heading-step-2-fork-a-public-template">Step 2: fork a public template</h3>
<p>KubeSail has <a target="_blank" href="https://kubesail.com/templates">a bunch of Kubernetes templates</a> to browse YAML examples and customize your own deployments.</p>
<p>Under <strong>Templates</strong>, I made this one <a target="_blank" href="https://kubesail.com/template/loopDelicious/minecraft-raspberry-pi">for Minecraft on Raspberry Pi</a>. If you’re not using a Raspberry Pi, use <a target="_blank" href="https://kubesail.com/template/loopDelicious/minecraft">this template</a> instead.</p>
<blockquote>
<p><a target="_blank" href="https://kubesail.com/template/loopDelicious/minecraft-raspberry-pi"><strong><em>minecraft-raspberry-pi</em></strong></a><em>: Minecraft server with a Persistent Volume Claim to store your world data, on Raspberry Pi 🍓. This template also runs on any board with an</em> <strong><em>arm64 CPU*</em></strong>.*</p>
</blockquote>
<p>The <code>minecraft-raspberry-pi</code> template has two kinds of Kubernetes resources.</p>
<ul>
<li><a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">Deployment</a> — to describe how an application is deployed</li>
<li><a target="_blank" href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims">Persistent Volume Claim</a> — a request for a particular type of storage</li>
</ul>
<p><a target="_blank" href="https://kubesail.com/template/loopDelicious/minecraft-raspberry-pi"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163608821/5a1553de-dfa5-4e68-9e28-458491ea95d1.png" alt /></a></p>
<p>fork the minecraft-raspberry-pi template</p>
<p><strong>Fork</strong> the template. You can rename it, and also toggle the new template’s setting to <strong>Private</strong> if you don’t want the template to be listed publicly as one of your own.</p>
<h4 id="heading-the-yaml-explained">The YAML explained</h4>
<p>This section explains some of the underlying YAML for these resources if you want to make any adjustments. Feel free to skip ahead to the next step.</p>
<p>In your new KubeSail template, click the <strong>Edit Yaml</strong> button to open the YAML editor on the right side of the page. Find the <code>Deployment</code> document tab in the YAML editor, and notice some details.</p>
<ul>
<li><code>[**replicas**](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#replicas)</code>: to specify the number of pods to run</li>
<li><code>[**image**](https://kubernetes.io/docs/concepts/containers/images/)</code>: the base Docker image for the container is <code>[joycelin79/cuberite](https://hub.docker.com/r/joycelin79/cuberite)</code>, a C++ version of Minecraft (instead of the default Java) that is more lightweight for the Raspberry Pi or any machine with an arm64 CPU</li>
<li><code>[**volumes**](https://kubernetes.io/docs/concepts/storage/volumes/)</code>: there’s a single volume, or data store, that points to our second resource which is a <code>PersistentVolumeClaim</code></li>
<li><code>[**volumeMounts**](https://kubernetes.io/docs/concepts/storage/volumes/#background)</code>: uses <a target="_blank" href="https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath">subpaths</a> to specify where to mount the volumes into the container according to how the base image is structured</li>
<li><code>[**ports**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#containerport-v1-core)</code>: exposes the port by setting the <code>hostPort</code> and <code>containerPort</code> — these two ports should be the same value, the default Minecraft port <code>25565</code></li>
<li><code>[**resources**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/)</code>: allocates your cluster’s memory to run your game smoothly, you may need to increase this amount, but most game servers should run below 1 CPU and 2Gi of memory</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163610586/7d9bcbf5-78b6-40e0-9f37-3b9f544b8d4a.png" alt /></p>
<p>Review the deployment details</p>
<p>Find the <code>PersistentVolumeClaim</code> document tab in the YAML editor. This claim asks the cluster for a particular type of storage, to be provisioned as a <code>PersistentVolume</code>.</p>
<ul>
<li><code>**name**</code>: points back to the volume specified in the <code>Deployment</code> document</li>
<li><code>[**resources**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/)</code>: this is a request for resources for the volume, or the data stored, and 2Gi should be enough for the Minecraft world.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163612229/828e2cde-de1f-4746-9df8-fe0d0a587242.png" alt /></p>
<p>Review PersistentVolumeClaim</p>
<p>The <code>PersistentVolume</code> in this deployment allows us to save the state of the Minecraft world so that we can quit our game and keep all of our precious minerals when the server reboots <strong>⛏</strong>💎</p>
<h3 id="heading-step-3-deploy-on-kubernetes">Step 3: deploy on Kubernetes</h3>
<p>We’re ready to deploy our app on Kubernetes!</p>
<p>In the dropdown menu next to the <strong>Launch Template</strong> button, select the <a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#context">Kubernetes context</a> from Step 1.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163614055/65a185a0-4453-4b2d-8385-12ce27f12e3c.png" alt /></p>
<p>Select a Kubernetes context to deploy the app</p>
<p>Hit <strong>Launch Template</strong>, and KubeSail will deploy Minecraft. In this example, I deploy to the <code>games</code> namespace on my <code>Raspberry Pi</code> cluster.</p>
<p>Our Minecraft server is alive!</p>
<h3 id="heading-step-4-connect-to-the-minecraft-server">Step 4: Connect to the Minecraft server</h3>
<p>To <a target="_blank" href="https://help.minecraft.net/hc/en-us/articles/360035131391-How-do-I-play-multiplayer-">connect to the Minecraft server</a>, start Minecraft on the machine where you want to play. Select <strong>Multiplayer</strong> from the main menu. Click the <strong>Add Server</strong> button, and enter the IP or web address of the Raspberry Pi server. If you’re on the same local network, you should see the server suggested in the local list.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163615529/5b1d97bb-8cc6-49e4-8666-15e0fe958525.png" alt /></p>
<p>scanning for games on the local network</p>
<p>If you want to allow access to the Minecraft server via the internet, set up port forwarding to point port <code>25565</code> to the IP of your Raspberry Pi. If you need a refresher, here is a tutorial <a target="_blank" href="https://www.howtogeek.com/66214/how-to-forward-ports-on-your-router/">to forward ports on your router</a>.</p>
<p>Provide this public IP to friends you invite to multiplayer Minecraft. Or you can set up an A record with your DNS provider that points to your home network <a target="_blank" href="https://medium.com/@joycelin.codes/ddclient-c9a6ac1d8f81?source=friends_link&amp;sk=71085ae2ef2612b40cda0130496d1410">like we did previously</a>, so friends can input a URL instead of an IP address.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163617184/29cd8d1b-f460-478a-b551-e788bf25e9bc.png" alt /></p>
<p>Players need to run the same version of Minecraft as the server. As of the writing of this article, the latest version of <a target="_blank" href="https://cuberite.org/">cuberite</a> is 1.12, so players should set their Minecraft version to 1.12.</p>
<p>So that’s it!</p>
<p>We set up a Minecraft server on Raspberry Pi using Kubernetes with a few terminal commands and clicks. Hosting a game server from your living room is free and easy. With the time I saved setting up a Minecraft server, I now have more time to spend on mining precious minerals <strong>⛏</strong></p>
<blockquote>
<p><em>🤓</em> <strong><em>Fun Fact:</em></strong> <em>If my IP address changes while I’m away from home, I might have trouble accessing the game server or any other self-hosted services. Check out this other tutorial I wrote for</em> <a target="_blank" href="https://medium.com/@joycelin.codes/ddclient-c9a6ac1d8f81?source=friends_link&amp;sk=71085ae2ef2612b40cda0130496d1410"><em>setting up a dynamic DNS service</em></a><em>, also on Raspberry Pi using Kubernetes!</em></p>
</blockquote>
<h3 id="heading-final-thoughts-on-deploying-with-kubernetes">Final thoughts on deploying with Kubernetes</h3>
<p>When people talk about Kubernetes, they picture huge companies with tons of traffic hitting their services. My little game server certainly doesn’t need Kubernetes for any advanced capabilities. But Kubernetes can also make deployment easier. I’ve done the “hard part” by configuring the Minecraft server to run on Kubernetes. And now if I want to run Kubernetes on a different cluster, I switch the context in KubeSail to deploy my changes with a single click.</p>
<p>Most people also picture Kubernetes running on a managed cloud provider, which can get expensive. But now we know <a target="_blank" href="https://medium.com/@joycelin.codes/ddclient-c9a6ac1d8f81?source=friends_link&amp;sk=71085ae2ef2612b40cda0130496d1410">how to run a cluster for free on a local machine</a> like a Raspberry Pi.</p>
<p>There’s a bunch of reasons why people use Kubernetes. For this game server, I’m using Kubernetes to <strong>simplify deployment</strong> and because it’s <strong>free</strong> to run on a self-hosted server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163618462/d74677ed-5bad-47a9-b367-35e471a5a500.jpeg" alt /></p>
<p>Try it yourself, and let me know what you think!</p>
]]></content:encoded></item><item><title><![CDATA[How Postman Engineering does microservices]]></title><description><![CDATA[A microservices update about domain-driven squads, CDC testing, and happily ever after
A couple years ago, Postman CTO and co-founder Ankit Sobti shared Postman’s struggle to escape from a microservices dependency hell. If you want to learn more abou...]]></description><link>https://blog.joycejetson.com/how-postman-engineering-does-microservices-aa026a3d682d</link><guid isPermaLink="true">https://blog.joycejetson.com/how-postman-engineering-does-microservices-aa026a3d682d</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Mon, 20 Jul 2020 22:51:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163524138/6cfb0000-f762-415f-b482-e89dc48f7033.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-a-microservices-update-about-domain-driven-squads-cdc-testing-and-happily-ever-after">A microservices update about domain-driven squads, CDC testing, and happily ever after</h4>
<p>A couple years ago, Postman CTO and co-founder Ankit Sobti shared Postman’s struggle to <a target="_blank" href="https://medium.com/better-practices/conquering-the-microservices-dependency-hell-at-postman-with-postman-part-1-introduction-a1ae019bb934">escape from a microservices dependency hell</a>. If you want to learn more about how and why Postman Engineering ventured into microservices, check out <a target="_blank" href="https://medium.com/better-practices/conquering-the-microservices-dependency-hell-at-postman-with-postman-part-1-introduction-a1ae019bb934">Ankit’s story</a>.</p>
<p>This is an update — here’s how Postman Engineering does microservices today.</p>
<h3 id="heading-who-is-postman-engineering">Who is Postman Engineering?</h3>
<p>Postman Engineering has 100+ engineers working across eight locations around the world. The company just <a target="_blank" href="https://blog.postman.com/postmans-series-c-funding-and-the-future-of-apis">announced a Series C</a> round of funding, so things are bound to evolve as with any growing startup.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163505979/de32695c-2edb-460b-be2a-5c5571cb4637.png" alt /></p>
<p>the sheer beauty of Postman Engineering</p>
<p>Let’s dive into how these teams are organized. As we’ll soon see, this really impacts the microservices implementation.</p>
<h3 id="heading-with-a-microservice-architecture-how-do-you-organize-your-teams">With a microservice architecture, how do you organize your teams?</h3>
<p>According to Conway’s Law, software starts looking like the organizations that create them. How people communicate, collaborate, and even their tooling has an impact. And the way information flows between related teams influences the output.</p>
<blockquote>
<p><strong><em>Any organization… will produce a design whose structure is a copy of the organization’s communication structure.</em></strong></p>
<p><strong><em>—</em></strong> <a target="_blank" href="https://en.wikipedia.org/wiki/Conway%27s_law#:~:text=From%20Wikipedia%2C%20the%20free%20encyclopedia,introduced%20the%20idea%20in%201967."><strong><em>Conway’s law</em></strong></a></p>
</blockquote>
<p>This is one reason why organizations like Amazon and Netflix work in small, independent teams. It enables <a target="_blank" href="https://medium.com/better-practices/api-first-software-development-for-modern-organizations-fdbfba9a66d3">API-first design and development</a>. And is represented as the well-known microservices deathstar.</p>
<p><a target="_blank" href="https://dzone.com/articles/navigating-the-microservice-deathstar-with-deployh"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163507178/96ffca5d-52fe-472c-a9c3-a2f98deb73c2.png" alt /></a></p>
<p>microservices deathstar</p>
<p>You can observe Conway’s Law by comparing products from teams grouped by function, by product, or by workflow.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163508586/e8090a5c-a837-42c2-baff-3e0ed1907d15.png" alt /></p>
<p>teams grouped by function, by product, or by workflow</p>
<p>How can you take advantage of this phenomenon?</p>
<p>The <a target="_blank" href="https://www.thoughtworks.com/radar/techniques/inverse-conway-maneuver">Inverse Conway Maneuver</a> proposes that you can change your organizational structure in order to change the technical structure that you desire. By dictating how your organization communicates and collaborates, you begin converging on your ideal shape.</p>
<p>Keeping this in mind, development teams at Postman are called squads. Squads operate on <a target="_blank" href="https://en.wikipedia.org/wiki/Domain-driven_design">domain-driven design</a> (DDD) principles, which free up each squad to focus on its core domain.</p>
<p>For example, one squad owns the Identity domain. The Identity squad produces services like <strong>Create a User</strong> and <strong>Authenticate a User</strong>, among others.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163509777/ca767202-a76c-427e-97a0-9e12b2d91164.png" alt /></p>
<p>examples of services produced by the squad owning the Identity domain</p>
<p>Across our company, there’s 12 squads that produce 40 services for Postman engineering. For the most part, each squad independently manages their roadmap and sprints. They have some freedom to choose their tools and configure their work processes.</p>
<p>Although squads are focused on their specific service, they are cross-functional, with dedicated members from design, product, engineering, security, quality, technical writing, and developer relations (that’s me!).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163510950/46d644d5-7472-4f08-9f78-0c991792f296.png" alt /></p>
<p>cross-functional squad focused on a domain</p>
<p>There’s many ways to implement microservices, but here’s how Postman engineering does it.</p>
<h3 id="heading-with-a-microservice-architecture-how-do-you-create-and-maintain-new-services">With a microservice architecture, how do you create and maintain new services?</h3>
<p>Imagine the Identity squad wants to produce a new service — to authenticate an existing user.</p>
<h4 id="heading-step-1-create-a-team-workspace"><strong>Step 1 | Create a team workspace</strong></h4>
<p>In Postman, the Identity service owner is the <strong>producer</strong> of this new service. This producer creates a team workspace as the single source of truth for the new service.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163512600/f03074b6-22e3-44ee-9ea5-235fd2847b64.png" alt /></p>
<p>a team workspace is the single source of truth for a service</p>
<p>A <a target="_blank" href="https://learning.postman.com/docs/postman/workspaces/intro-to-workspaces/">workspace</a> is the foundation for collaboration in Postman. As we’ll soon see, the workspace contains the expected behavior of the service. Unit and integration tests live here. And it’s the central thread for all the communication during and after development.</p>
<h4 id="heading-step-2-draft-a-blueprint-collection-to-describe-use-cases"><strong>Step 2 | Draft a blueprint collection to describe use cases</strong></h4>
<p>Within the new workspace, the Identity service owner drafts a <a target="_blank" href="https://learning.postman.com/docs/postman/collections/intro-to-collections/">collection</a> to describe their service. This collection is like a blueprint with proposed <a target="_blank" href="https://learning.postman.com/docs/postman/collections/examples/">examples</a> of a request and potential server responses to describe various use cases. In fact, the name of the collection includes <code>#blueprint</code> as a tag indicating its purpose.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163514354/11a27a7e-a0fd-47a0-a25b-71e05f2a2710.png" alt /></p>
<p>start with a proposed blueprint of the new service</p>
<h4 id="heading-step-3-negotiate-how-the-proposed-service-will-function"><strong>Step 3 | Negotiate how the proposed service will function</strong></h4>
<p>The blueprint collection is a proposal for the service. Potential consumers of the service weigh in on the design, either offline or via threaded <a target="_blank" href="https://learning.postman.com/docs/postman/collections/commenting-on-collections/">comments</a> in the app, to shape what the service will become.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163516069/16fb7648-5890-4300-aaff-3ff15326bfdc.png" alt /></p>
<p>threaded comments to negotiate the proposed service</p>
<h4 id="heading-step-4-parallel-development-with-mocks"><strong>Step 4 | Parallel development with mocks</strong></h4>
<p>Once all stakeholders successfully negotiate the design of the service, the collection becomes an agreement, or contract, for the new service. Those examples of requests and responses inform <a target="_blank" href="https://learning.postman.com/docs/postman/mock-servers/intro-to-mock-servers/">mock servers</a> that enable parallel development.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163518000/693fbded-094d-4a73-9b3f-5bfdf49d7e69.png" alt /></p>
<p>paired requests and responses inform mocks which enable parallel development</p>
<p>The mock is a contract between the producer and consumers of this service. Both parties can start developing their code at the same time. Tests are written. Documentation begins. All this activity occurs in parallel and is driven by an agreed-upon vision of the new service.</p>
<h3 id="heading-with-a-microservice-architecture-how-do-we-know-when-theres-a-breaking-change">With a microservice architecture, how do we know when there’s a breaking change?</h3>
<p>When we’re ready to deploy the service, we test to ensure that no workflow is broken. One of the most powerful tools that Postman engineering has adopted to manage microservices is <a target="_blank" href="https://medium.com/better-practices/consumer-driven-contract-testing-using-postman-f3580dba5370">consumer-driven contract (CDC) tests</a>.</p>
<h4 id="heading-cdc-testing"><strong>CDC testing</strong></h4>
<p>In the previous section, we talked about how the service owner relies on the blueprint collection to propose, negotiate, and then establish how their service will be used.</p>
<p>Once that contract is agreed upon, consumers write tests using the mocks as a reference point. The consumers only test the endpoints and properties that they need, saving the tests in a collection. Once again, the name of these collections include <code>#contract</code> as a tag indicating its purpose. These test collections are maintained within the producer’s team workspace.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163519513/eef903d5-875b-4f29-9223-8c9b3aa7e44e.png" alt /></p>
<p>consumer writes tests that are run as part of the producer’s CI pipeline</p>
<p>When the producer is ready to deploy their service, the consumer’s contract tests are run against the code as part of the continuous integration (CI) pipeline.</p>
<p>The service owner pulls all the collections within the team workspace using the <a target="_blank" href="https://api.getpostman.com/">Postman API</a>, looking for any collections with the <code>#contract</code> tag to run. They use Docker to configure their own environments and <a target="_blank" href="https://medium.com/postman-engineering/continuous-deployment-with-postman-collections-e2fb0b5d2235">deploy their code in the CI/CD pipeline</a>, and rely on <a target="_blank" href="https://github.com/postmanlabs/newman">Newman</a> to run the collections in the container.</p>
<p>The code changes deploy only if the contract tests pass.</p>
<h4 id="heading-continuous-testing"><strong>Continuous testing</strong></h4>
<p>In addition to running contract tests on demand as part of the CI pipeline, Postman Engineering runs a plethora of other tests on a regular basis.</p>
<p>Our engineers schedule <a target="_blank" href="https://learning.postman.com/docs/postman/monitors/intro-monitors/">monitors</a> that run test collections from Postman servers. These alerts and summaries are piped into Slack and email to keep tabs on the service throughout the day.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163521159/82383601-974c-45c1-95b9-2f1509b65668.png" alt /></p>
<p>continue running health and security checks on monitors</p>
<p>So Postman engineers rely on tests that run on demand and continuously. Incorporating CDC testing in the CI pipeline allows service owners to deploy updates with confidence that they’re not breaking somebody else’s code. Continuously running other tests on monitors also ensures nothing is broken after deployment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163523083/ec117f26-add4-4e79-80bd-16b4d5b062e9.png" alt /></p>
<p>1) Newman to run tests on demand at build time, and 2) Monitors to run tests on a scheduled cadence</p>
<p>All of this informs an ongoing feedback loop that allows the team to continue evolving and updating their services.</p>
<h3 id="heading-is-that-happily-ever-after">Is that happily ever after?</h3>
<p>No blog post about microservices will ever conclude with a tidy bow. All architectures are a continuously evolving work in progress.</p>
<p>As you can probably imagine, Postman engineering uses the Postman product quite a bit. Which means that we’re the first canaries in the coal mine. If something doesn’t work smoothly or it can be done better, we have the opportunity to feel the pain first. This allows us to iterate quickly on new features.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>This was a peek at how Postman is working with microservices today. We’re continuing to address some challenges.</p>
<ul>
<li>Dependencies on other squads require additional coordination. One squad’s roadmap might be blocked by another squad’s progress, or at least be subject to their service levels.</li>
<li>Squads are a relatively new concept at Postman, and each squad is independently figuring out what processes work best.</li>
<li>In domain-driven design, domains require constant evaluation. For example, squads focused on large domains that require a large share of responsibilities debate the trade-offs between managing a microservice vs. a <a target="_blank" href="https://en.wikipedia.org/wiki/Monorepo">monorepo</a> vs. a monolith.</li>
</ul>
<p>If you want to learn more about microservices, then check out Ankit’s <a target="_blank" href="https://medium.com/better-practices/conquering-the-microservices-dependency-hell-at-postman-with-postman-part-1-introduction-a1ae019bb934">original blog series</a> about Postman’s initial foray into the microservice architecture. And keep your eyes peeled. We hope to share more updates and stories from the trenches soon.</p>
]]></content:encoded></item><item><title><![CDATA[Enable public access to connected devices in your local network]]></title><description><![CDATA[Three options for public access to a Philips Hue light — go ahead, turn on the lights in my kitchen
In a recent Livestream with my teammate Arlemi, we unboxed some lights and messed around with the Philips Hue Lights API. We figured out how to turn o...]]></description><link>https://blog.joycejetson.com/enable-public-access-to-connected-devices-in-your-local-network-c15338da5a3</link><guid isPermaLink="true">https://blog.joycejetson.com/enable-public-access-to-connected-devices-in-your-local-network-c15338da5a3</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Tue, 07 Jul 2020 14:43:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163537597/2fb8896f-1bbc-432e-ba35-3cf9bbb0d7e0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-three-options-for-public-access-to-a-philips-hue-light-go-ahead-turn-on-the-lights-in-my-kitchen">Three options for public access to a Philips Hue light — go ahead, turn on the lights in my kitchen</h4>
<p>In a recent Livestream with my teammate Arlemi, we unboxed some lights and messed around with the <a target="_blank" href="https://developers.meethue.com/">Philips Hue Lights API</a>. We figured out how to turn on the light and change the colors using an API.</p>
<p>Then Arlemi queried a <a target="_blank" href="https://openweathermap.org/">weather API</a> — he wanted to update the light based on the weather forecast.</p>
<iframe src="https://www.youtube.com/embed/Nu0oMwld5Pk?feature=oembed" width="700" height="393"></iframe>

<p>the original events inspiring this project</p>
<p>But the light was with me in San Francisco. And Arlemi was in London. So I was the only one who could update the device during the Livestream.</p>
<p>So the challenge began: how could I let Arlemi, and the viewers, change the lights in my home from the comfort of their own pajamas?</p>
<blockquote>
<p><strong><em>Dear impatient readers*</em></strong>: If you don’t care how I did it, skip ahead to the end, and you too can turn on the lights in my kitchen<em> **</em>💡<em>*</em></p>
</blockquote>
<h3 id="heading-why-cant-anyone-else-turn-on-the-lights">Why can’t anyone else turn on the lights?</h3>
<p>You can log in to the Philips Hue mobile app with your Philips Hue account for remote access to your lights.</p>
<p>To use the Philips Hue Lights API directly, there’s a couple of options. For example, if I’m sending these API calls from <a target="_blank" href="https://www.postman.com/">Postman</a> on my laptop there are really only two ways to do it.</p>
<h4 id="heading-local-area-network"><strong>Local Area Network</strong></h4>
<p>I can send the request from within the same local network. Since my laptop and lights are connected to the same home WiFi, I can use Postman to hit the API. But if I go across the street and use my neighbor’s WiFi, then I’m no longer on the same local network.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163526279/51681046-f92d-44c0-98eb-02074284525b.png" alt /></p>
<p><strong>Local Area Network</strong>: devices connected to the same network can access the light</p>
<p>So unless I’m connected to my local network, I won’t be able to reach my lights without providing additional information.</p>
<h4 id="heading-remote-access"><strong>Remote access</strong></h4>
<p>The Philips Hue Lights API allows me to give additional information to authorize remote access, so my lights can be accessed from a different network.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163527523/f4cf66c3-fd0e-40f5-a8b7-368a783e45d3.png" alt /></p>
<p><strong>Remote access</strong>: additional info required to authorize</p>
<p>But I don’t want to share my private account information with anyone else.</p>
<p>Let’s walk through a few ways to enable public access to our light, without sharing personal credentials.</p>
<ul>
<li><a class="post-section-overview" href="#7790"><strong>Port forwarding</strong></a> — the most straightforward option, but don’t do it</li>
<li><a class="post-section-overview" href="#1cd0"><strong>Proxy in the cloud</strong></a> — place a proxy in front of your light, in the cloud</li>
<li><a class="post-section-overview" href="#a3db"><strong>Proxy in the local network</strong></a> — place a proxy in front of your light, in the local network</li>
</ul>
<h3 id="heading-option-1-port-forwarding">Option 1 — port forwarding</h3>
<p>The most straightforward option is to set up <a target="_blank" href="https://whatismyipaddress.com/port-forwarding">port forwarding</a> for your connected light. Port forwarding enables external requests to your public IP on a specified port to be forwarded to a connected device.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163528645/6b4615b8-a539-4d75-a4de-f3c8b08cf967.png" alt /></p>
<p><strong>Port forwarding</strong>: light is exposed directly to the internet</p>
<p><strong>Don’t do this.</strong> Bots and malicious attackers scan IP addresses for exposed and vulnerable devices. And if my Philips Hue light has a vulnerability, an attacker can infiltrate my connected device and access other clients connected to my local network.</p>
<p>Also, you tell the users your public IP address for your home, which can reveal some personal details like your general location.</p>
<p>Next, let’s buffer against potential attacks and obscure our home IP.</p>
<h3 id="heading-option-2-proxy-in-the-cloud">Option 2 — proxy in the cloud</h3>
<p>This option places a proxy in the cloud between users and the connected device. This buffers against some unwanted attention. By directing requests through an app, we can build custom checkpoints like validating user inputs or rate-limiting into our app.</p>
<p><a target="_blank" href="https://github.com/loopDelicious/hue-go"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163530193/a089f816-814a-4ce6-a27b-1384d0dc9e31.png" alt /></a></p>
<p>validate user inputs and rate limiting</p>
<p>Deploy your app on a cloud hosting provider like Digital Ocean or Heroku. This means you can invite users to send requests to the app hosted on the cloud, instead of your home IP address.</p>
<p>Now we control traffic from our friendly users. But we still need to set up port forwarding to route traffic from our proxy, so our light is still exposed to the internet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163531416/00eb5872-ed4a-434d-a6f6-7c10c15215bd.png" alt /></p>
<p><strong>Proxy in the cloud</strong>: place a proxy in front of the light</p>
<p>Even though you’re now handling legitimate requests from your users more cautiously, the light is still exposed. There’s nothing standing between potential attackers and the light.</p>
<p>Next, let’s thwart attackers by moving the proxy inside our local network.</p>
<h3 id="heading-option-3-proxy-in-the-local-network">Option 3 — proxy in the local network</h3>
<p>The only improvement with this option is the placement of the proxy in the local network. If we move the same proxy from the cloud to the local network, we handle potential attackers more effectively.</p>
<p>This time we set up port forwarding to route traffic <strong><em>to our proxy.</em></strong> Attackers can still hit our public IP, but now we have a barrier between the light and the internet.</p>
<p>Once again, we control the data passed through and returned, but this time <strong><em>for every user</em></strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163532454/d081548f-8787-4d0e-94fd-8e98ccd12ebc.png" alt /></p>
<p><strong>Proxy in the local network</strong>: move the proxy inside</p>
<h3 id="heading-tradeoffs-and-additional-considerations">Tradeoffs and additional considerations</h3>
<p>We talked about three options to open up your connected device to the public, and a few more considerations to further fortify connected devices. As always, the option you choose will depend on your specific situation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163533789/1a43edaf-fa85-4e11-812a-f8a0c5dcb10f.png" alt /></p>
<p>pros and cons for each option to enable public access to a connected device</p>
<h4 id="heading-cdn"><strong>CDN</strong></h4>
<p>You can use a <strong>content delivery network (CDN)</strong> in front of any of these three options to obscure your home IP address. A CDN provider like <a target="_blank" href="https://www.cloudflare.com/ddos/#:~:text=All%20Cloudflare%20plans%20offer%20unlimited,associated%20with%20a%20distributed%20attack.">Cloudflare</a> also offers free protection against distributed denial of service (DDOS) attacks to throttle an intentional, or unintentional, surge in traffic.</p>
<blockquote>
<p><strong><em>Rate limiting*</em></strong>: You can add rate limits at the infrastructure-level or application-level. Check out my tutorial<em> [</em>to build application-level rate limits with Node and Redis<em>](https://codeburst.io/api-rate-limiting-with-node-and-redis-95354259c768)</em>.*</p>
</blockquote>
<h4 id="heading-nat-traversal"><strong>NAT traversal</strong></h4>
<p>You can use a gateway to maintain a <strong>network address translation (NAT)</strong> connection by opening a two-way tunnel between a cloud proxy and your home server. This means you don’t need to configure your router for port forwarding and is secure from attackers who scan IPs.</p>
<h4 id="heading-dynamic-dns">Dynamic DNS</h4>
<p>You can set up a <strong>dynamic DNS (DDNS)</strong> service for any option that requires router configuration for port forwarding. Check out my tutorial for <a target="_blank" href="https://codeburst.io/ddclient-c9a6ac1d8f81">using a free DDNS client like ddclient</a> to automatically update your DNS record when your IP address changes, so access to your home server is maintained.</p>
<h3 id="heading-heres-what-i-did"><strong>Here’s what I did</strong></h3>
<p>I wanted my Philips Hue light to be accessible to Livestream viewers. So I ran an Express server on a Raspberry Pi in my local network (option 3). I used <a target="_blank" href="https://www.cloudflare.com/">Cloudflare</a> for DNS and <a target="_blank" href="https://kubesail.com/">KubeSail</a> for NAT traversal so that I didn’t need port forwarding and could direct users to a public domain: <code>[https://light.meowsergirl.com](https://light.meowsergirl.com)</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163535152/c27bcb51-0e55-43db-93eb-01a99fa2a667.png" alt /></p>
<p>here’s what I did</p>
<h3 id="heading-go-ahead-turn-on-the-lights-in-my-kitchen">Go ahead, turn on the lights in my kitchen</h3>
<p>Now, as promised, go ahead and turn on the lights in my kitchen.</p>
<ul>
<li><a target="_blank" href="https://explore.postman.com/templates/10360/turn-on-the-hue-light-in-joyces-kitchen"><strong>Example API calls in Postman</strong></a> — to update the lights in my kitchen</li>
<li><a target="_blank" href="https://github.com/loopDelicious/hue-go"><strong>Code sample in GitHub</strong></a> — to enable public access to your own connected devices</li>
</ul>
<p><a target="_blank" href="https://explore.postman.com/templates/10360/turn-on-the-hue-light-in-joyces-kitchen"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163536516/4bc5bd43-0ef3-4b2a-9a6c-3a607787e018.png" alt /></a></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Turning on these lights is more de-light-ful when you can see them. So <a target="_blank" href="https://www.twitch.tv/getpostman">follow Postman on Twitch</a> and tune in to a livestream to see the effects of your API calls in realtime. Thanks for reading, I hope you found this entertaining!</p>
]]></content:encoded></item><item><title><![CDATA[API rate limiting with Node and Redis]]></title><description><![CDATA[Slow your roll by building a simple rate limiter to improve the availability of your API-based services
Photo by Ludovic Charlet on Unsplash
Rate limiting can protect and improve the availability of your API-based services. If you’re talking to an AP...]]></description><link>https://blog.joycejetson.com/api-rate-limiting-with-node-and-redis-95354259c768</link><guid isPermaLink="true">https://blog.joycejetson.com/api-rate-limiting-with-node-and-redis-95354259c768</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Mon, 29 Jun 2020 13:49:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163546369/c2071e04-52a8-4154-bdbb-bf21dbc5adcd.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-slow-your-roll-by-building-a-simple-rate-limiter-to-improve-the-availability-of-your-api-based-services">Slow your roll by building a simple rate limiter to improve the availability of your API-based services</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@ludo_photos?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ludovic Charlet</a> on <a target="_blank" href="/s/photos/limit?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>Rate limiting can protect and improve the availability of your API-based services. If you’re talking to an API and receive the HTTP <strong>429 Too Many Requests</strong> response status code, you’ve been rate limited. That means you’ve exceeded the number of requests allowed within a given period of time. Slow your roll and wait a bit, before trying again.</p>
<h3 id="heading-why-rate-limit">Why rate limit?</h3>
<p>When you’re thinking about limiting your own API-based service, you need to balance tradeoffs between user experience, security, and performance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163539500/7aab6a1f-f153-4b71-a8a7-3e2766a81611.png" alt /></p>
<p>The most common reason to control the flow of data is to maintain availability for your API-based services. But there are security benefits too. A single unintentional, or intentional, surge in inbound traffic can tie up valuable resources and impact the availability for other users.</p>
<p>By controlling the rate of incoming requests, you can:</p>
<ul>
<li>protect services and resources from being overwhelmed</li>
<li>slow down brute-force attacks</li>
<li>prevent distributed denial-of-service (DDOS) attacks</li>
</ul>
<h3 id="heading-how-can-you-implement-rate-limiting">How can you implement rate limiting?</h3>
<p>Rate limiting can be implemented at the client-level, application-level, infrastructure-level, or anywhere in between. There are a few ways to control inbound traffic to your API service.</p>
<ul>
<li><strong>By user</strong> — track calls made by a user with an API key, access token, or IP address</li>
<li><strong>By geography</strong> — such as decreasing rate limits at peak times of the day for each geographic region</li>
<li><strong>By server</strong> —if you have multiple servers handling different calls to your API, you might implement stricter rate limits for access to more expensive resources</li>
</ul>
<p>You can use any one (or even a combination of) these types of rate limiting.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163540709/f7cff77d-bc55-4511-8532-ca1218cb171d.png" alt /></p>
<p>No matter how you choose to implement it, the goal of rate limiting is to establish a checkpoint that either <strong>rejects</strong> or <strong>passes through</strong> requests to access your resources. Many programming languages and frameworks have inbuilt capabilities or middleware to do this. There are also options for various rate limiting algorithms.</p>
<p>This is one way to make your own rate limiter with Node and Redis:</p>
<ol>
<li>Create a Node app</li>
<li>Add a rate limiter with Redis</li>
<li>Test in Postman</li>
</ol>
<blockquote>
<p><strong><em>💻 Check out</em></strong> <a target="_blank" href="https://github.com/loopDelicious/rate-limiter"><strong><em>the code sample on GitHub</em></strong></a><strong><em>.</em></strong></p>
</blockquote>
<p>Before you begin, make sure you have <a target="_blank" href="https://nodejs.org/en/">Node</a> and <a target="_blank" href="https://redis.io/download">Redis</a> installed on your machine.</p>
<h3 id="heading-step-1-create-a-node-app">Step 1: Create a Node app</h3>
<p>Set up a new Node app from the command line. Walkthrough the CLI prompts, or add the <code>--yes</code> flag to accept the default options.</p>
<p>$ npm init --yes</p>
<p>Create a file called <code>index.js</code> for your entry point if you accepted the default option during the project setup.</p>
<p>$ touch index.js</p>
<p>Install the <a target="_blank" href="https://expressjs.com/">Express</a> web framework, and initialize the server in <code>index.js</code>.</p>
<p><em>const</em> express = require('express')</p>
<p><em>const</em> app = express()</p>
<p><em>const</em> port = process.env.PORT || 3000</p>
<p>app.get('/', (<em>req</em>, <em>res</em>) <em>\=&gt;</em> <em>res</em>.send('Hello World!'))</p>
<p>app.listen(port, () <em>\=&gt;</em> console.log(`Example app listening at http://localhost:${port}`))</p>
<p>Start the server from the command line.</p>
<p>$ node index.js</p>
<p>Back in <code>index.js</code>, create a route to first check the rate limit, and then allow access to resources if the user is not over the limit.</p>
<p>app.post('/', async (<em>req</em>, <em>res</em>) <em>\=&gt;</em> {</p>
<p> <em>async function</em> isOverLimit(<em>ip)</em> {</p>
<p>    // to define</p>
<p>  }</p>
<p>  // check rate limit</p>
<p> <em>let</em> overLimit = await isOverLimit(<em>req</em>.ip)</p>
<p>  if (overLimit) {</p>
<p> <em>res</em>.status(429).send('Too many requests - try again later')</p>
<p>    return</p>
<p>  }</p>
<p>  // allow access to resources</p>
<p> <em>res</em>.send("Accessed the precious resources!")</p>
<p>})</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163541714/e0b8d3b5-df1b-4c67-9743-2c85c2b94630.png" alt /></p>
<p>application-level rate limiting</p>
<p>In the next step, we’ll define the rate limiter function <code>isOverLimit</code>.</p>
<h3 id="heading-step-2-add-a-rate-limiter-with-redis">Step 2: Add a rate limiter with Redis</h3>
<p>Redis is an in-memory key-value data store, so it can retrieve data very quickly. It’s also pretty straightforward <a target="_blank" href="https://redis.io/commands/incr/#pattern-rate-limiter-1">to implement rate limiting with Redis</a>.</p>
<ul>
<li>Store a key like a user’s IP address</li>
<li>Increment the number of calls made from that IP</li>
<li>Expire the record after a specified timeframe</li>
</ul>
<p>The rate limiting algorithm shown below is an example of a <strong>sliding window counter</strong>. A user who submits a modest number of calls, or spaces them out over time, never reaches a rate limit. A user who exceeds the maximum requests within a 10-second window must wait for enough time to pass to resume their requests.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163542843/7defaa7e-d938-490d-a56d-b3678694c601.png" alt /></p>
<p>rate limiting algorithm: sliding window counter</p>
<p>Install a Redis client for Node called <a target="_blank" href="https://github.com/luin/ioredis">ioredis</a> from the command line.</p>
<p>$ npm install ioredis</p>
<p>Start the Redis server locally.</p>
<p>$ redis-server</p>
<p>Then require and initialize the Redis client in <code>index.js</code>.</p>
<p><em>const</em> <em>redis</em> = require('ioredis')</p>
<p><em>const</em> client = redis.createClient({</p>
<p>  port: process.env.REDIS_PORT || 6379,</p>
<p>  host: process.env.REDIS_HOST || 'localhost',</p>
<p>})</p>
<p>client.on('connect', <em>function</em> () {</p>
<p>  console.log('connected');</p>
<p>});</p>
<p>Define the <code>isOverLimit</code> function that we started writing in the previous step, by following this pattern from Redis <a target="_blank" href="https://redis.io/commands/incr/#pattern-rate-limiter-1">to keep a counter by IP</a>.</p>
<p>async <em>function</em> isOverLimit(<em>ip</em>) {</p>
<p> <em>let</em> res</p>
<p>  try {</p>
<p>    res = await client.incr(<em>ip</em>)</p>
<p>  } catch (err) {</p>
<p>    console.error('isOverLimit: could not increment key')</p>
<p>    throw err</p>
<p>  }</p>
<p>  console.log(`${<em>ip</em>} has value: ${res}`)</p>
<p>  if (res &gt; 10) {</p>
<p>    return true</p>
<p>  }</p>
<p>  client.expire(<em>ip</em>, 10)</p>
<p>}</p>
<p>And that’s our rate limiter.</p>
<p>When a user makes a call to the API, we check Redis to see if the user is over the limit. If they are, the API immediately returns the HTTP 429 status code with the message <code>Too many requests — try again later</code>. If the user is within the limit, we proceed to the next code block where we can allow access to protected resources like a database.</p>
<p>During the rate limit check, we find the user’s record in Redis and increment the count of their requests. If there’s no record of the user in Redis, then we create a new record. And lastly, each record will expire within 10 seconds of the latest activity.</p>
<p>In the next step, let’s make sure our rate limiter is working correctly.</p>
<h3 id="heading-step-3-test-in-postman">Step 3: Test in Postman</h3>
<p>Save your changes, and restart the server. We’ll use <a target="_blank" href="https://www.postman.com/">Postman</a> to send <code>POST</code> requests to our API server running locally at <code>http://localhost:3000</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163544163/b0e83c97-a7d5-4f0e-9978-37ac9c627089.png" alt /></p>
<p>within rate limit</p>
<p>Continue sending requests in rapid succession to hit your rate limit.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163545019/0d424d12-7c12-40c4-8620-c2c18a9d3465.gif" alt /></p>
<p>exceeds rate limit — HTTP 429 too many requests</p>
<h3 id="heading-final-thoughts-about-rate-limiting">Final thoughts about rate limiting</h3>
<p>This was a simple example of a rate limiter with Node and Redis. This is just the start. There’s a bunch of strategies and tools available to structure and implement your rate limits. And there are other enhancements to explore with this example, like:</p>
<ul>
<li>Letting the user know how much time they should wait before trying again, either in the response body or as a <code>Retry-after</code> header</li>
<li>Logging the requests reaching the rate limit, for insight into user behavior and to alert of malicious attacks</li>
<li>Trying a different rate limiting algorithm or other middleware</li>
</ul>
<p>Remember, when you’re exploring API limits you’re balancing tradeoffs between performance, security, and user experience. Your ideal solution for rate limiting will change over time along with these considerations.</p>
]]></content:encoded></item><item><title><![CDATA[Set up a free Dynamic DNS service with ddclient on Kubernetes]]></title><description><![CDATA[Don’t gamble accessing self-hosted services on a Raspberry Pi when you’re away from home and your IP changes
Photo by NASA on Unsplash
Most internet service providers (ISPs) give residential customers a dynamic IP address. They pull from a pool of IP...]]></description><link>https://blog.joycejetson.com/ddclient-c9a6ac1d8f81</link><guid isPermaLink="true">https://blog.joycejetson.com/ddclient-c9a6ac1d8f81</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Tue, 12 May 2020 03:48:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163638674/78d706d1-5a16-41c0-b69c-028375edb7f6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-dont-gamble-accessing-self-hosted-services-on-a-raspberry-pi-when-youre-away-from-home-and-your-ip-changes">Don’t gamble accessing self-hosted services on a Raspberry Pi when you’re away from home and your IP changes</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@nasa?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">NASA</a> on <a target="_blank" href="https://unsplash.com/s/photos/internet?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>Most internet service providers (ISPs) give residential customers a dynamic IP address. They pull from a pool of IP addresses and allocate one to a home. Since the IP address might change in a few months or even in a few hours, it can be hard to consistently access your personal computer when you’re away from home.</p>
<p>Setting up a <strong>dynamic DNS (DDNS)</strong> service gives you reliable access to self-hosted services, like a personal website, a Minecraft server, or just your home computer. If you point a hostname to your home network, you can have Kubernetes update the DNS record when your IP inevitably changes.</p>
<h3 id="heading-what-is-dynamic-dns">What is Dynamic DNS?</h3>
<p>Since most residential customers have dynamic IPs, there’s a few options to manage a changing IP address.</p>
<ul>
<li><strong>Static IP</strong>: if your ISP offers this option, get a dedicated IP address so it never changes</li>
<li><strong>Router</strong>: if your router has a dynamic DNS option, configure DDNS on your router to always maintain an active connection</li>
<li><strong>DDNS services</strong>: <a target="_blank" href="https://support.cloudflare.com/hc/en-us/articles/360020524512-Manage-dynamic-IPs-in-Cloudflare-DNS-programmatically">Cloudflare recommends a few options</a>, such as updating your IP using a dynamic DNS client application</li>
</ul>
<p>Making sure your IP is up to date, or remains fixed, guarantees reliable access to your self-hosted services.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163621190/1dbea9e9-b967-4d03-b08c-967d06d9dd3c.jpeg" alt /></p>
<p>Don’t gamble on accessing your self-hosted services when you’re away from home</p>
<p>For example, I have a self-hosted Minecraft server on a Raspberry Pi at home. I want to set up DDNS so that I can access this game server even if the IP changes while I’m out of town.</p>
<h3 id="heading-how-can-we-run-a-dynamic-dns-service">How can we run a dynamic DNS service?</h3>
<p>Let’s use a dynamic DNS client application called <a target="_blank" href="https://ddclient.net/">ddclient</a>. Services like these keep an eye on your IP address. When the IP changes, the service automatically updates your DNS record using the DNS provider’s API.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163622351/8bd884ef-421a-4dc9-a80c-38830f0ceb49.jpeg" alt /></p>
<p>DDNS client apps like <a target="_blank" href="https://ddclient.net/">ddclient</a> periodically check your public IP for changes</p>
<p>If you’d like to learn how to set up your DNS records, take a spin through <a target="_blank" href="https://blog.jswart.xyz/posts/cloudflare-dynamic-dns">this very good tutorial</a> that walks through how to register a domain and run ddclient using Docker on its own.</p>
<p>In this tutorial, let’s run ddclient on Kubernetes.</p>
<blockquote>
<p><strong><em>Wait, wait… You’re using</em> Kubernetes <em>to run a self-hosted app?!</em></strong></p>
<p><strong><em>Isn’t this overkill?</em></strong></p>
<p><strong><em>— anyone reading this</em></strong></p>
</blockquote>
<h3 id="heading-why-use-kubernetes-in-addition-to-docker">Why use Kubernetes in addition to Docker?</h3>
<p>Docker containers are useful for packaging and running software in a way that’s predictable and consistent. While I’ve previously talked about using Kubernetes <a target="_blank" href="https://medium.com/better-practices/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9">to reduce the complexity of managing containers and to scale services</a>, we can also use Kubernetes to simplify the deployment process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163623326/18c3b5c7-50f0-4b2d-9774-a16e10f60750.jpeg" alt /></p>
<p>Docker for packaging software, and Kubernetes for deploying it</p>
<p>My self-hosted apps will never have Netflix- or Slack-level traffic. But if we can use Kubernetes to ease the pain of deployment, for free, then why not?</p>
<p>There’s a bit of a learning curve with Kubernetes, but a bunch of new tools are making it easier than ever to get started.</p>
<p>Let’s forge ahead.</p>
<h3 id="heading-where-can-i-deploy-a-kubernetes-cluster">Where can I deploy a Kubernetes cluster?</h3>
<p>When I think about deploying on Kubernetes, I imagine working with a managed cloud service, like when we <a target="_blank" href="https://medium.com/better-practices/chaos-d3ef238ec328">previously deployed a cluster on Amazon EKS</a>.</p>
<p>But Kubernetes can also run on a local machine, like a Raspberry Pi at home.</p>
<blockquote>
<p><strong><em>You can deploy a Kubernetes cluster on a local machine, cloud, on-prem datacenter; or choose a managed Kubernetes cluster. You can also create custom solutions across a wide range of cloud providers, or bare metal environments.</em></strong></p>
<p><strong><em>—</em></strong> <a target="_blank" href="https://kubernetes.io/docs/setup/"><strong><em>Kubernetes docs</em></strong></a></p>
</blockquote>
<p>A cluster running on a self-hosted Raspberry Pi server is perfect for my own DDNS and gaming needs. Setting up Kubernetes on a local machine is also a great way to learn Kubernetes without racking up cloud costs.</p>
<p>Let’s deploy ddclient on Kubernetes running on a local Raspberry Pi. To do this, we’ll use <a target="_blank" href="https://kubesail.com/resources">KubeSail</a>, which can deploy on any type of cluster.</p>
<h3 id="heading-a-recipe-for-deploying-ddclient-on-kubernetes-with-kubesail">A recipe for deploying ddclient on Kubernetes with KubeSail</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163624666/87e08f2b-cf5c-4d34-b5f9-6e818eae1dcb.png" alt /></p>
<p>automatically update IP using ddclient</p>
<p>The ddclient app keeps an eye on our IP address. When the IP changes, ddclient automatically updates our DNS record using the Cloudflare API. Ddclient works with <a target="_blank" href="https://github.com/ddclient/ddclient">a bunch of DNS providers</a> to keep DNS records up to date, but we’ll use <a target="_blank" href="https://www.cloudflare.com/">Cloudflare</a>.</p>
<ul>
<li>Step 0 — <a class="post-section-overview" href="#a036">Pre-requisites</a></li>
<li>Step 1 — <a class="post-section-overview" href="#8e66">Add a cluster to the Raspberry Pi</a></li>
<li>Step 2 — <a class="post-section-overview" href="#b373">Fork a public template</a></li>
<li>Step 3 — <a class="post-section-overview" href="#36c0">Update your DNS secrets</a></li>
<li>Step 4 — <a class="post-section-overview" href="#9cc3">Update the deployment details</a> (skip)</li>
<li>Step 5 — <a class="post-section-overview" href="#675e">Deploy on Kubernetes</a></li>
</ul>
<p>Let’s get started.</p>
<h3 id="heading-0-pre-requisites">0 | Pre-requisites</h3>
<p>Do this stuff first.</p>
<h4 id="heading-kubesail"><strong>KubeSail</strong></h4>
<p>Sign up for a <a target="_blank" href="https://kubesail.com/">free KubeSail account</a> — we’ll use their tools to manage the apps on our Raspberry Pi.</p>
<h4 id="heading-dns-server"><strong>DNS server</strong></h4>
<p>You’ll need to own your own domain and be able <a target="_blank" href="https://support.cloudflare.com/hc/en-us/articles/205195708-Changing-your-domain-nameservers-to-Cloudflare">to change your domain’s nameservers</a>. I’m using a <a target="_blank" href="https://www.cloudflare.com/">free Cloudflare account</a> to route my web traffic through the Cloudflare network.</p>
<h4 id="heading-kubernetes"><strong>Kubernetes</strong></h4>
<p>Decide where to run your Kubernetes cluster. I’m using a Raspberry Pi. The DDNS application should be running on the same home network as your self-hosted services, since the app works by checking its own network IP.</p>
<h3 id="heading-1-add-a-cluster-to-the-raspberry-pi">1 | Add a cluster to the Raspberry Pi</h3>
<p>I’m using a <a target="_blank" href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/">Raspberry Pi 4</a> to run my Kubernetes cluster. <a target="_blank" href="https://kubesail.com/blog/microk8s-raspberry-pi">This very good tutorial</a> shows us how to set up a cluster on a new Raspberry Pi.</p>
<ul>
<li>Flash an operating system onto an SD card — I used <a target="_blank" href="https://ubuntu.com/desktop">Ubuntu</a></li>
<li>Enable <a target="_blank" href="https://www.ssh.com/ssh/server">Secure Shell (SSH)</a> to operate a headless Raspberry Pi — or use a separate keyboard and monitor</li>
<li>Enable Wi-Fi also on the SD card — or I plugged directly into ethernet</li>
<li>Insert the SD card into the Raspberry Pi</li>
<li>Log in to the Raspberry Pi using SSH</li>
<li>Install <a target="_blank" href="https://microk8s.io/">MicroK8s</a> — a lightweight Kubernetes recommended for IOT apps, so your commands will use <code>microk8s.kubectl</code> instead of just <code>kubectl</code></li>
</ul>
<p>To connect the Raspberry Pi to KubeSail, apply the configuration file to your namespace from the Raspberry Pi’s command line.</p>
<p>$ sudo microk8s.kubectl apply -f https://byoc.kubesail.com/.yaml</p>
<p>The Raspberry Pi is now a single-node Kubernetes cluster!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163625727/83bbc77f-2ef4-4fe9-a8df-97735517abc2.jpeg" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163626568/4a71c962-95fd-4163-980b-6eddee574814.gif" alt /></p>
<p>The Raspberry Pi is now a single-node Kubernetes cluster!</p>
<p>The Raspberry Pi will appear in the <a target="_blank" href="https://kubesail.com/clusters">KubeSail clusters dashboard</a> after a minute or so. In the dashboard under <strong>Clusters</strong>, select the new cluster and give it a name. Then select <strong>Namespaces</strong> from the sub-menu. This is where you can add a new <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/">Kubernetes namespace</a>, or use a default namespace called <code>default</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163628351/fa05accf-ad66-4a4e-b523-5d362b16abcc.png" alt /></p>
<p>Add a new namespace, or use the default</p>
<p>So now we have a cluster, a namespace, and a user —all the parameters required for our <a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#context">Kubernetes context</a>.</p>
<h3 id="heading-2-fork-a-public-template"><strong>2 | Fork a public template</strong></h3>
<p>I previously talked about <a target="_blank" href="https://medium.com/better-practices/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9">the basic concepts behind Docker and Kubernetes</a>. <a target="_blank" href="https://yaml.org/">YAML</a> is used to write instructions to deploy and manage your containers.</p>
<p>If you’re just learning Kubernetes, or getting started with a new project, KubeSail lists <a target="_blank" href="https://kubesail.com/templates">community examples</a>. You can browse these examples, and cobble together relevant YAML samples to customize your own Kubernetes apps.</p>
<p>Under <strong>Templates</strong>, I made this one <a target="_blank" href="https://kubesail.com/template/loopDelicious/ddclient">for ddclient</a>.</p>
<blockquote>
<p><a target="_blank" href="https://kubesail.com/template/loopDelicious/ddclient"><strong><em>ddclient</em></strong></a><strong><em>:</em></strong> <em>ddclient for dynamic DNS updating for self-hosted services at a residential network</em> <strong><em>🌐</em></strong></p>
</blockquote>
<p>The ddclient template has two kinds of Kubernetes resources.</p>
<ul>
<li><a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/secret/">Secret</a> — to store your confidential information</li>
<li><a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">Deployment</a> — to describe how your application is deployed</li>
</ul>
<p><a target="_blank" href="https://kubesail.com/template/loopDelicious/ddclient"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163629413/6a587060-1ada-45e4-8ff9-2179168d4a88.png" alt /></a></p>
<p>fork the ddclient template</p>
<p>Fork the template on <a target="_blank" href="https://kubesail.com/template/loopDelicious/ddclient">this page</a>. Then toggle the new template’s setting to <strong>Private</strong> because we’ll add our secrets in the next step.</p>
<h3 id="heading-3-update-your-dns-secrets"><strong>3 | Update your DNS secrets</strong></h3>
<p>If you haven’t already done so, add an A record to Cloudflare that points to your home network. For now, this can point to any IP, such as <code>1.1.1.1</code> because ddclient will update the IP to the correct address when we deploy it later.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163631083/52e61b57-73dc-4210-8673-1dada7bd4985.png" alt /></p>
<p>add an A record for the home network</p>
<p>Here’s the data you need from Cloudflare.</p>
<ul>
<li><code>zone</code> — your domain name like <code>example.com</code></li>
<li><code>login</code> — your Cloudflare account email address</li>
<li><code>password</code> — your global API key from under <strong>API Tokens</strong> on <a target="_blank" href="https://dash.cloudflare.com/profile">your Cloudflare profile</a></li>
<li>the line beneath <code>password</code> — full domain name to keep updated, including subdomain like <code>home.example.com</code></li>
</ul>
<p>Back in your new private KubeSail template, click the <strong>Edit Yaml</strong> button to open the YAML editor on the right side of the page.</p>
<p>There’s a couple ways <a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/overview/">to decouple Kubernetes configuration details</a>. Using a <a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/secret/">Kubernetes Secret</a> will store your confidential data, and inject the data into your containers only when it’s needed.</p>
<p>Find the <code>Secret</code> document tab in the YAML editor, and update your Cloudflare credentials beneath <code>ddclient.conf</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163632343/decb9890-ea88-418e-8bfc-7928a030b9ba.png" alt /></p>
<p>Update your Cloudflare credentials in the `Secret` document</p>
<p>Here’s some other interesting details in the <code>ddclient.conf</code>.</p>
<ul>
<li><code>**daemon**</code>: ddclient will run this process every 300 seconds (five minutes)</li>
<li><code>**web**</code><strong>:</strong> dclient will check if the IP address has changed, using this web service: <a target="_blank" href="https://domains.google.com/checkip">https://domains.google.com/checkip</a></li>
</ul>
<p>When you’re done, save the template.</p>
<h3 id="heading-4-update-the-deployment-details-skip">4 | Update the deployment details (skip)</h3>
<p>You don’t have to do anything here, but it’s helpful to understand some of the underlying YAML for this resource.</p>
<h4 id="heading-the-yaml-explained">The YAML explained</h4>
<p>Find the <code>Deployment</code> document tab in the YAML editor, and notice the interesting bits.</p>
<ul>
<li><code>[**volumes**](https://kubernetes.io/docs/concepts/storage/volumes/)</code>: there’s a single <a target="_blank" href="https://kubernetes.io/docs/concepts/storage/volumes/">Kubernetes volume</a>, or data store, that points to our secrets from the last step</li>
<li><code>[**image**](https://kubernetes.io/docs/concepts/containers/images/)</code>: the base Docker image for our containerized application is <code>[linuxserver/ddclient](https://hub.docker.com/r/linuxserver/ddclient)</code> from the smart people at Linux Server</li>
<li><code>[**resources**](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)</code>: the request for how much CPU or memory a container needs to run ddclient as a fairly lightweight Perl program</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163634008/73980ea1-17ee-468c-bdb4-2aa1d33aa9c1.png" alt /></p>
<p>Review the deployment details</p>
<p>If you make any changes, remember to save the template.</p>
<h3 id="heading-5-deploy-on-kubernetes"><strong>5 | Deploy on Kubernetes</strong></h3>
<p>We’re ready to deploy our app on Kubernetes! This part is easy peasy lemon squeezy since we already added a Kubernetes cluster and namespace in <a class="post-section-overview" href="#8e66">the first step</a>.</p>
<p>In the dropdown menu next to the <strong>Launch Template</strong> button, select a <a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#context">Kubernetes context</a> to deploy our app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163635319/73c2778d-0a60-4ba6-a82c-5ac8ed6c647a.png" alt /></p>
<p>Hit <strong>Launch Template</strong>, and KubeSail will deploy ddclient.</p>
<p>In the example below, I deploy to the <code>default</code> namespace on my <code>Raspberry Pi</code> cluster.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163636348/ba197933-5d9e-4d45-97b5-62c032b5e1ee.gif" alt /></p>
<p>deploy to the `default` namespace on the `Raspberry Pi` cluster</p>
<p>You can see success notifications and logs under your deployment details.</p>
<h4 id="heading-verify-ddclient-is-working">Verify ddclient is working</h4>
<p>Once your app is finished deploying, return to Cloudflare to verify that ddclient updated <code>1.1.1.1</code> to our actual network IP. Every five minutes, ddclient will check if our network IP has changed.</p>
<p>Besides the initial update, there’s one more check to verify that ddclient is working correctly. Once again, change the IP of your home network’s A record in Cloudflare to <code>1.1.1.1</code>. Turn off your internet router long enough to ensure your ISP allocates a new IP address. I left my router unplugged overnight. In the morning when I powered up my router, I verified that ddclient updated my IP in Cloudflare.</p>
<p>In summary, we deployed ddclient on Kubernetes. Every five minutes, ddclient will check the IP address of the Raspberry Pi. If there’s been a change to the IP, ddclient will update our DNS record using the Cloudflare API.</p>
<p>Doing this, allows me to continue playing Minecraft on my Raspberry Pi when I’m away from home, and my ISP changes my IP unexpectedly.</p>
<blockquote>
<p><em>🤓</em> <strong><em>Fun Fact:</em></strong> <em>The Raspberry Pi at home hosts both ddclient and my Minecraft server. While both servers don’t need to run on the same cluster, they should be in the same home network since ddclient works by checking its own network IP. Stay tuned to learn how to set up a Minecraft server on Raspberry Pi using Kubernetes.</em></p>
</blockquote>
<h3 id="heading-final-thoughts-on-deploying-on-kubernetes">Final thoughts on deploying on Kubernetes</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163637580/2a8c4adc-54a8-4d62-a051-630f20df8ef4.jpeg" alt="I don’t always deploy on kubernetes, but when i do, it’s a real cluster" /></p>
<h4 id="heading-kubernetes-for-simplifying-deployments">Kubernetes for simplifying deployments</h4>
<p>Deploying projects is something I do very rarely. So when I do, it takes a while to dust off the cobwebs, and it’s pretty slow going.</p>
<p>Even though Kubernetes is best known for complex container orchestration at massive scale, it can also <strong><em>simplify</em></strong> modest deployments.</p>
<h4 id="heading-share-your-templates">Share your templates</h4>
<p>I’m new to Kubernetes. So as a n00b does, I hack on something until it works. For this project, starting with other people’s YAML examples was super helpful. This <a target="_blank" href="https://blog.jswart.xyz/posts/cloudflare-dynamic-dns/">great blog post</a>, other <a target="_blank" href="https://kubesail.com/templates">public templates</a>, and <a target="_blank" href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#create-a-configmap">these code samples</a> saved me a ton of time.</p>
<p>If you come up with something that works for you, share it with the rest of us as a <a target="_blank" href="https://kubesail.com/templates">public template</a> 🙏</p>
]]></content:encoded></item><item><title><![CDATA[Adding an Octopus to the Zsh Prompt]]></title><description><![CDATA[Transition from bash to zsh with custom settings, conditional emojis, and git prompt
Photo by Serena Repice Lentini on Unsplash
For my last Mac, I had a friendly hamster face emoji in my terminal bash prompt. After I recently upgraded to a new Mac, I...]]></description><link>https://blog.joycejetson.com/adding-an-octopus-to-the-zsh-prompt-56edf2e9bcad</link><guid isPermaLink="true">https://blog.joycejetson.com/adding-an-octopus-to-the-zsh-prompt-56edf2e9bcad</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Sun, 05 Apr 2020 22:56:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163473860/7bf22ad8-d646-48be-9435-52c27da0a1c1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-transition-from-bash-to-zsh-with-custom-settings-conditional-emojis-and-git-prompt">Transition from bash to zsh with custom settings, conditional emojis, and git prompt</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@serenarepice?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Serena Repice Lentini</a> on <a target="_blank" href="https://unsplash.com/s/photos/octopus?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>For my last Mac, I had a friendly <a target="_blank" href="https://medium.com/@joycelin.codes/adding-a-hamster-face-to-the-bash-prompt-547a2edad567">hamster face emoji in my terminal bash prompt</a>. After I recently upgraded to a new Mac, I discovered Apple has replaced bash with zsh as the default shell, beginning with macOS Catalina.</p>
<blockquote>
<p><a target="_blank" href="https://support.apple.com/en-us/HT208050">Starting with macOS Catalina, your Mac uses zsh as the default login shell and interactive shell.</a></p>
</blockquote>
<p>You can still switch back to bash, for now, but the trend is moving to zsh as the command-line interpreter for the login shell and interactive shell.</p>
<p>Here’s how you can add an Octopus emoji and other custom items to your zsh prompt to make life in your terminal more hospitable.</p>
<h3 id="heading-change-your-default-shell">Change your default shell</h3>
<p>If you aren’t already using <a target="_blank" href="https://www.zsh.org/">zsh</a> in your terminal, change the shell by updating the shell path to <code>/bin/zsh</code>, with the following terminal command.</p>
<p>$ chsh -s /bin/zsh</p>
<h3 id="heading-switch-to-a-zsh-prompt">Switch to a zsh prompt</h3>
<p>Zsh recognizes a different set of prompt specifiers than bash, so you may need to modify some settings previously used in your bash profile.</p>
<p>If you’re starting from scratch, here’s 3 steps to add a custom prompt with an emoji as well as other information about the current git repository.</p>
<h4 id="heading-step-1-install-oh-my-zsh">Step 1: install oh-my-zsh</h4>
<p>Install <a target="_blank" href="https://github.com/ohmyzsh/ohmyzsh">Oh My Zsh</a>, an open source framework for managing your <a target="_blank" href="https://www.zsh.org/">zsh</a> configuration, by running this curl command in your terminal.</p>
<p>$ sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"</p>
<h4 id="heading-step-2-update-your-theme-and-plugins">Step 2: update your theme and plugins</h4>
<p>Use your favorite text editor to open your <code>~/.zshrc</code> config file located in your <code>$HOME</code> directory.</p>
<p>$ code ~/.zshrc</p>
<p>This config file is where you can update your theme for a different look and feel by selecting one of the <a target="_blank" href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes">many available themes</a>, or leave it the default theme.</p>
<p># in ~/.zshrc<br /># pick theme<br />ZSH_THEME="robbyrussell"</p>
<p>You can also add a plugin to this config file by selecting a few of the <a target="_blank" href="https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins">many available plugins</a>, like <code>[git-prompt](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git-prompt)</code> to display information about the current directory.</p>
<p># in ~/.zshrc<br /># add plugin<br />plugins=(<br />  git-prompt<br />)</p>
<h4 id="heading-step-3-customize-the-prompt">Step 3: customize the prompt</h4>
<p>Use your favorite text editor to open your oh my zhs theme to further customize your terminal prompt.</p>
<p>$ code ~/.oh-my-zsh/themes/robbyrussell.zsh-theme</p>
<p>Tweak the theme by updating various parts of the <code>PROMPT</code> string. You can use a <a target="_blank" href="https://zsh-prompt-generator.site/">zsh prompt generator</a> to easily configure, bold, or colorize more elements. Paste in your own emoji, or use <strong>Ctrl + Cmd + Space</strong> on Mac to open up the emoji keyboard.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163471010/2909bc6e-24af-4da5-a963-164344d2de8f.png" alt /></p>
<p>customize prompt with emoji and git status</p>
<p>Another option is to add a conditional emoji based on the success of the previous command. In this example, an Octopus will display in the prompt if the preceding command succeeds, otherwise a Dinosaur.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163472501/9a379e07-1d33-4ea6-bf94-dc92f1f70554.png" alt /></p>
<p>customize with conditional emojis</p>
<p>Save your changes, and open a new terminal tab to inspect your newest Octopus friend 🐙!</p>
]]></content:encoded></item><item><title><![CDATA[How to book a campsite in Yosemite valley]]></title><description><![CDATA[Building your own bot to co-opt natural resources
When I first moved to San Francisco from Denver several years ago, I traded in most of my outdoorsy activities for techie ones. But camping in Yosemite has been on my wish list. Year after year, I not...]]></description><link>https://blog.joycejetson.com/how-to-book-a-campsite-in-yosemite-valley-fe18ad5d4d63</link><guid isPermaLink="true">https://blog.joycejetson.com/how-to-book-a-campsite-in-yosemite-valley-fe18ad5d4d63</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Sun, 15 Mar 2020 15:34:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163562415/9f6bf8af-ca46-4ba4-9325-18c11a2cc60e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-building-your-own-bot-to-co-opt-natural-resources">Building your own bot to co-opt natural resources</h4>
<p>When I first moved to San Francisco from Denver several years ago, I traded in most of my outdoorsy activities for techie ones. But camping in Yosemite has been on my wish list. Year after year, I notice that it’s really tough to reserve a spot. So I’ve still never been.</p>
<p>There’s <a target="_blank" href="https://www.kqed.org/news/11450483/cant-get-that-camping-spot-it-could-be-bots">a bit of an issue</a> with reserving a campsite at Yosemite, but in this case, my techie self can help out my outdoorsy self.</p>
<h3 id="heading-the-problem">The problem</h3>
<p>In 2018, a bunch of state and federal park services launched an online reservation system, <a target="_blank" href="https://www.recreation.gov/">Recreation.gov</a>, allowing users to book picnic spots and campsites across America.</p>
<p>Located in California, Yosemite National Park is one of the most popular destinations that you can book through this website. It’s so popular that Yosemite releases a new block of campsites four months in advance.</p>
<p>On the 15th of every month at 7:00 a.m. Pacific Time, eager campers will scramble to book a spot at one of the prime campsites in Yosemite valley closest to the most iconic landmarks in the park.</p>
<blockquote>
<p>Seconds make the difference between getting your reservation or not.</p>
<p>— <a target="_blank" href="https://www.recreation.gov/articles/list/tips-for-yosemite-reservations/281">RECREATION.GOV</a></p>
</blockquote>
<p>The competition is fierce. Thousands will try to reserve a few select spots, and the campsites will be fully booked within 20 minutes. How is this humanly possible?</p>
<p>There are bots among us.</p>
<h3 id="heading-enter-the-bots">Enter the bots</h3>
<p>A quick search in GitHub reveals scripts developed to gain an advantage in booking one of these in-demand campsites.</p>
<ul>
<li>A Python script <a target="_blank" href="https://github.com/bri-bri/yosemite-camping">to scrape campground availability</a></li>
<li>Another one using Selenium <a target="_blank" href="https://github.com/webrender/campsite-checker">to automate the process of browsing the website</a></li>
</ul>
<p>There’s also paid services (like <a target="_blank" href="https://reserve.wanderinglabs.com/">this one</a> and <a target="_blank" href="https://campnab.com/">that one</a>) that offers to monitor the reservation website and alert you of cancellations.</p>
<p>Another quick search in your favorite search engine reveals articles and forum chatter about the dastardly nature of these bots, with discussion about the unfairness of it all. People are frustrated with the reservations processes going back several years.</p>
<p>Let’s dig deeper into what happens when reserving a campsite.</p>
<h3 id="heading-breaking-down-a-campsite-reservation">Breaking down a campsite reservation</h3>
<p>Go to <a target="_blank" href="https://www.recreation.gov/">Recreation.gov</a> in your browser. Open your browser’s DevTools and head over to the <strong>Network</strong> tab to see all of the network calls sent to the servers as you browse the site.</p>
<h4 id="heading-checking-availability"><strong>Checking availability</strong></h4>
<p>On the website, select your preferred campground, and then hit <strong>View by Availability</strong>. In DevTools under <strong>Network</strong>, you’ll see a request submitted to an endpoint called <code>/availability</code>. Right click on this request, and select “Copy as cURL” to copy it to your clipboard.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163548336/ce35ae74-a215-41c6-abc9-f3d560a9e58c.png" alt /></p>
<p>copy as cURL</p>
<p>We’ve previously used Postman <a target="_blank" href="https://medium.com/better-practices/reverse-engineering-an-api-403fae885303">to reverse engineer an API</a>. Let’s switch over to <a target="_blank" href="https://www.postman.com/">Postman</a> now to inspect what’s happening and modify what we send to Recreation.gov’s servers.</p>
<p>Paste the cURL from your clipboard <a target="_blank" href="https://learning.postman.com/docs/postman/collections/data-formats/#importing-postman-data">to import it into Postman as raw text</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163550236/500fdd2f-3686-426e-8e63-55e0fd5c6f50.png" alt /></p>
<p>import cURL as raw text</p>
<p>This <code>GET</code> request does not require authorization, and retrieves the availability of all campsites for your selected campground. We can further inspect the headers and other components of this request.</p>
<p>Hit <strong>Send</strong>, and inspect the response.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163551911/98a164cf-ad29-44a9-9d99-02ad06f13c2b.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163553258/7bd86c6d-3195-47a3-9b57-31274a67829c.png" alt /></p>
<p>inspect elements like request headers and response body</p>
<p>This shows us what’s happening in the background as we browse the website.</p>
<h4 id="heading-booking-a-reservation"><strong>Booking a reservation</strong></h4>
<p>Back on the website, click “Book Now” to temporarily call dibs on a campsite for a specific date. Once you do this, you’ll have 15 minutes to complete the reservation before that spot is released back into inventory.</p>
<p>In DevTools under <strong>Network</strong>, you’ll see a request submitted to an endpoint called <code>/multi</code>. Import the request into Postman like we did before.</p>
<p>Under <strong>Headers</strong>, we see this <code>POST</code> request requires a Bearer token as an <code>authorization</code> header. Under <strong>Body</strong>, we see a JSON object with our reservation information.</p>
<p>Hit <strong>Send</strong>. The Recreation.gov servers already received a request submitted from the browser, and now we’re trying to submit the exact same request from the Postman client.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163554612/1e1099c0-31f3-4752-8007-5fbd3851d2ea.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163555974/5725351c-8b68-4761-a695-803ca5346b0d.png" alt /></p>
<p>Well, that’s not going to work. But we understand a little more about what the Recreation.gov servers are expecting from the client, so we can begin building our bot.</p>
<h3 id="heading-build-your-own-bot">Build your own bot</h3>
<p>If you’re technically savvy and can write a bit of code, you can build your own bot with some googling and ingenuity. Really, there’s a few ways to get this done.</p>
<p>As you write your own bot, or use someone else’s, here’s some things to keep in mind.</p>
<h4 id="heading-reuse-and-recycle"><strong>Reuse and recycle</strong></h4>
<p>There’s several public solutions available as starters for various parts of the booking process. For example, you may find an app to intercept web requests and allow you to modify the payload before submitting a reservation. You can also choose to script any or all aspects of the reservation process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163557038/1f8e5560-cc8f-4fa5-b705-e3719bbc0d05.jpeg" alt /></p>
<h4 id="heading-customize-your-criteria"><strong>Customize your criteria</strong></h4>
<p>Your strategy is completely up to you and your preference of campsites, dates, and other criteria. For example, someone may only be available for one week in the month of May while someone else may be flexible on dates but only want to stay in the Upper Pines camping area.</p>
<h4 id="heading-speed-is-of-the-essence"><strong>Speed is of the essence</strong></h4>
<p>Automation does not imply speed. You can automate a task to accomplish something very slowly. Optimize your program to run in an efficient manner allowing you to compete against other bots. For example, limiting your search to a few campsites takes less time than searching all the campsites in the campground.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163558822/76b23c19-e8da-47f2-8b69-69427dac7c8d.png" alt /></p>
<p>complete your reservation within the 15 minute window</p>
<h3 id="heading-is-this-fair">Is this fair?</h3>
<p>It’s <a target="_blank" href="https://www.kqed.org/news/11450483/cant-get-that-camping-spot-it-could-be-bots">not illegal</a>. But legal standards are not the same as ethical standards, which are established by societal norms.</p>
<h4 id="heading-what-is-fair"><strong>What is fair</strong></h4>
<p>Recreation.gov promotes the <a target="_blank" href="https://www.recreation.gov/use-our-data">programmatic use of their data</a> via a public API. While it provides a lot of information, you can’t see campsite availability or book a reservation. Their website also uses an open JSON API to display information like availability, so that your program can access the same information that a human sees while browsing the website.</p>
<h4 id="heading-what-is-not-fair"><strong>What is not fair</strong></h4>
<p>If you’re planning on reselling your camping spot, this is prohibited by most state and national parks. However, prosecutors typically go after folks who are commercially profiting or harming the website.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163559798/368490de-5001-4927-a70b-91b7217a580f.jpeg" alt /></p>
<p>For just booking your own reservations, I couldn’t find anything on the current Recreation.gov website that explicitly prohibits the use of bots. However, I came across a number of comments online expressing frustration toward these bots. People think using a bot is “wrong”, “dishonest”, and “unfair”. Some comments go further, piling on a disgust of computers, technology, and tech workers.</p>
<p>Bots are simply programs created by humans. They can be helpful and automate a lot of tedious tasks. They can also be a nuisance and used for nefarious purposes. What they ultimately do, is up to the human writing the program.</p>
<blockquote>
<p><em>With great power, comes great responsibility</em></p>
<p><em>-Uncle Ben</em></p>
</blockquote>
<h3 id="heading-final-thoughts">Final thoughts</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163561069/eaf04a52-373a-4037-b8a9-18ce61e730f5.jpeg" alt /></p>
<p>It’s an interesting discussion about ethics, but I just want to go camping. It would be lovely if the National Park Service came up with a fair process that was also sustainable for our public parks, and everyone could camp freely without writing a bot.</p>
<p>For those who want to book a campsite in the Yosemite valley, the conversation about fairness focuses on how public access to natural resources has been co-opted by the technologically literate. Indeed the digital divide still exists even though <a target="_blank" href="https://www.internetsociety.org/globalinternetreport/">more people now have access to the internet and technical resources</a>.</p>
<p>I’m privileged because I know how to use technology to my advantage. Like most people, I rely on free resources and public communities to improve my technological literacy. If you want to learn how to do something, you can do it. The circle of life involves consuming, and then sharing, technical knowledge in forums and articles like this one.</p>
]]></content:encoded></item><item><title><![CDATA[Bringing law and order to APIs with OpenAPI Specifications]]></title><description><![CDATA[A better way to build and manage APIs using schemas, descriptions, and style guides
Photo by Lenny Kuhne on Unsplash
A specification is a technical document that tells you how a thing works.
If you’re building cars, a specification tells you how a ca...]]></description><link>https://blog.joycejetson.com/api-specifications-d87588ac874</link><guid isPermaLink="true">https://blog.joycejetson.com/api-specifications-d87588ac874</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Fri, 15 Nov 2019 19:17:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163682217/082458f4-ec60-4006-8fd0-e5c0a2d9f51a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-a-better-way-to-build-and-manage-apis-using-schemas-descriptions-and-style-guides">A better way to build and manage APIs using schemas, descriptions, and style guides</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@lennykuhne?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Lenny Kuhne</a> on <a target="_blank" href="https://unsplash.com/s/photos/assembly-line?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>A specification is a technical document that tells you how a thing works.</p>
<p>If you’re building cars, a specification tells you how a car works. It includes the most important details and perhaps a list of requirements that the end product should fulfill. Once the car gets built, the owner’s manual shows a driver how to operate and maintain the car.</p>
<p>Similarly, if you’re building APIs, a specification tells you how an API works, along with the most important details. The documentation shows a consumer how to work with the API.</p>
<p>We’ve previously talked about <a target="_blank" href="https://medium.com/better-practices/api-first-software-development-for-modern-organizations-fdbfba9a66d3">software development in an API-first world</a> and also how <a target="_blank" href="https://medium.com/better-practices/design-apis-like-you-design-user-experience-a7adeb2ee90f">to design APIs like you design user experience</a>.</p>
<p>Now let’s see how API descriptions help us build and manage APIs.</p>
<h3 id="heading-a-brief-history-of-api-descriptions">A brief history of API descriptions</h3>
<p>Since the beginning of APIs, various specification formats have evolved in an effort to standardize the way we describe them.</p>
<ul>
<li><strong>Web Services Description Language</strong> (<a target="_blank" href="https://www.w3.org/TR/2001/NOTE-wsdl-20010315">WSDL</a>) was created by Ariba, IBM, and Microsoft as a machine-readable way to describe services in 2001.</li>
<li><strong>Web Application Description Language</strong> (<a target="_blank" href="https://www.w3.org/Submission/wadl/">WADL</a>) was from Sun Microsystems as a RESTful equivalent to WSDL in 2009.</li>
<li><a target="_blank" href="https://swagger.io/docs/specification/2-0/basic-structure/"><strong>Swagger</strong></a> was a project from 2011, acquired by SmartBear, then donated to the Linux Foundation’s Open API Initiative, eventually to be renamed OpenAPI Specification.</li>
<li><strong>RESTful API Modeling Language</strong> (<a target="_blank" href="https://raml.org/">RAML</a>) was from MuleSoft and a group of other enterprise companies in 2013 to focus on API Design.</li>
<li><strong>OpenAPI Specification</strong> (<a target="_blank" href="https://www.openapis.org/">OAS</a>) is currently the market leader in specification formats and supported by a number of large enterprises.</li>
</ul>
<p>These are a few of the formats that gained popularity in recent years. Their goals are all to standardize the way in which you describe your resources, and they’re all useful in different ways for developing APIs.</p>
<p>And the evolution continues. For example, some community members want to introduce more human-readable elements, describe more use cases for the end consumer, and find other ways to govern API design and development in a scalable manner.</p>
<h3 id="heading-some-confusing-terms">Some confusing terms</h3>
<p>In addition to a continually evolving landscape, there’s a bunch of ambiguous terminology. Industry experts don’t entirely agree on the terms, and they’re often used interchangeably when they really don’t mean the same thing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163661047/3c7293d3-4613-4c9f-bbbf-1963ccb5a17e.png" alt /></p>
<p>it’s time to get pedantic</p>
<h4 id="heading-schemas-this-is-how-data-looks"><strong>Schemas</strong> — this is how data looks</h4>
<p>Schemas include metadata referring to your data models and provide information about the resource representations that your API accepts or returns. For example, <a target="_blank" href="https://json-schema.org/">JSON Schema</a> is a specification declaring the proper structure of JavaScript Object Notation (JSON) data used frequently with web APIs, and is used to validate the correct format for the body of a request or response.</p>
<h4 id="heading-api-description-formats-this-is-a-way-to-describe-apis"><strong>API description formats</strong> — this is a way to describe APIs</h4>
<p>These formats are sometimes called API specification formats, and are usually based on a specification format (such as OpenAPI Specification) that combines a schema language (such as JSON Schema) and other information to describe endpoints, headers, and all the stuff that’s not in the body (that’s covered in a schema).</p>
<h4 id="heading-api-description-document-this-is-how-a-particular-api-works"><strong>API description document — this is how a particular API works</strong></h4>
<p>These documents are sometimes called API specifications, and is a file that contains all the stuff from your description format fleshed out with information related to your actual API. This file describes how the API works. It can be used as a contract to programmatically build workflows useful for API development, such as tests or documentation.</p>
<h4 id="heading-api-documentation-this-is-how-to-use-a-particular-api"><strong>API documentation — this is how to use a particular API</strong></h4>
<p>Documentation talks about how to use an API, and will typically include a technical reference as well as functional guides for how to interact with the API across various use cases. An API consumer who reads the API documentation should understand how to use the API.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163662116/4c793281-6edd-4c4d-91bd-910d4cc2a45f.jpeg" alt /></p>
<p>There are meaningful differences between all of these concepts. But once again, experts don’t always agree on these meanings, and they’re frequently referred to interchangeably or ambiguously. For example, when someone says “API specification”, they could be referring to either the format for describing APIs, the file intended to drive API development, or the file generated to document an API.</p>
<p>The important thing is to understand these basic concepts, and then determine what is helpful for your organization’s desired workflow.</p>
<p>If your head hurts from reading this, so does mine. Let’s forge ahead and walk through a couple examples.</p>
<h3 id="heading-example-1-building-blocks">Example #1: Building blocks</h3>
<p>From the building blocks of modern software to the building blocks of life — let’s talk about APIs and DNA.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163663392/1c89ae9e-d343-407f-9cc4-a2c71fdf5928.png" alt /></p>
<p>DNA is the blueprint for every living organism</p>
<p>In biochemistry, DNA is the blueprint for every living organism. A <strong>schema</strong> establishes the rules for how biological molecules pair together to form chemical strands of a double helix 🧬</p>
<p>The human genome is a <strong>description format</strong> offering a complete genetic blueprint for building human beings. This mapping provides detailed information about the structure, organization, and function of the complete set of human genes.</p>
<p>My personal DNA sequence can be captured in a <strong>description file</strong>. My DNA follows the general rules of DNA, particularly that of a human’s DNA, and not an alligator or mushroom 🐊🍄</p>
<p>My <strong>documentation</strong> helps others understand how to interact with me. I must be fed 4–5 times a day, and I’ll get grumpy if you talk to me while I’m busy working with my headphones on.</p>
<p>Let’s walk through one more example — this time with our friendly, neighborhood <a target="_blank" href="https://www.getpostman.com/">Postman</a>.</p>
<h3 id="heading-example-2-postman-collections-to-describe-an-api">Example #2: Postman collections to describe an API</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163664537/946e3312-e40d-4b13-9a9b-10904e483770.png" alt /></p>
<p>A Postman collection can be used as an API description format, API description document, or API documentation — depending on the context</p>
<p>The <a target="_blank" href="https://learning.getpostman.com/docs/postman/collections/intro-to-collections/">concept of a Postman collection</a> is an <strong>API description format</strong> (or API specification format), in the sense that it’s how you can describe an API. The underlying JSON <a target="_blank" href="https://schema.getpostman.com/">representation of a collection</a> must be formatted a certain way as dictated by a <strong>schema</strong> to ensure the collection is valid.</p>
<p>Now, imagine <a target="_blank" href="https://explore.postman.com/team/TwitterAdsAPI">Twitter has an API</a>. When Twitter uses a Postman collection to describe how their particular API works, Twitter’s collection becomes an <strong>API description document</strong> (or API specification). Maybe the Twitter team includes a few different examples to demonstrate authorization use cases, or <a target="_blank" href="https://learning.getpostman.com/docs/postman/scripts/intro-to-scripts/">adds some code to their collection</a> to show off different workflows.</p>
<p>As an API description document (or API specification), Twitter’s Postman collection can now be used to generate <a target="_blank" href="https://learning.getpostman.com/docs/postman/sending-api-requests/generate-code-snippets/">code samples</a>, <a target="_blank" href="https://learning.getpostman.com/docs/postman/mock-servers/intro-to-mock-servers/">virtualized services</a>, or <a target="_blank" href="https://learning.getpostman.com/docs/postman/api-documentation/intro-to-api-documentation/"><strong>API documentation</strong></a> to help developers learn how to use their API.</p>
<p>Ok , enough with the examples — it’s time to get tactical!</p>
<h3 id="heading-test-apis-and-lint-specifications-with-openapi-specification-newman-and-spectral">Test APIs and lint specifications with OpenAPI Specification, Newman, and Spectral</h3>
<p>Just like a clothing lint roller creates a more uniform and consistent appearance by removing bits of fuzz and fur from all of your surfaces, a code linter does the same.</p>
<p>You may have used a code linter to ensure that your code is error-free, readable, and contains impeccable syntax for whatever programming language you’re using.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163665632/4faf92e8-98ab-4dcd-9917-2c2884c12723.png" alt /></p>
<p>We’ve already talked about <a target="_blank" href="https://documenter.getpostman.com/view/1559645/RzZFCGFR">writing tests in Postman</a> and <a target="_blank" href="https://medium.com/better-practices/from-manual-to-automated-testing-the-roadblocks-and-the-journey-6333dfacc5ae">different ways to automate your testing</a>. Now let’s use an API specifications linter and create a custom style guide to bring law and order to our untamed APIs.</p>
<p>We can either run these checks locally from the command line, automatically <a target="_blank" href="https://medium.com/better-practices/git-hooks-for-automation-135c62bca7d7">using git hooks</a>, or as a build step during our continuous integration workflow.</p>
<p>Let’s run tests and lint specifications in our CI pipeline.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163667189/4e0c0ace-fe57-4cce-a125-3bf29b5ce4c9.png" alt /></p>
<p>Let’s run tests and lint specifications in our CI workflow</p>
<h3 id="heading-step-0-pre-requisites">Step 0: Pre-requisites</h3>
<p>If you want to skip to the punchline, go ahead and <a target="_blank" href="https://github.com/postmanlabs/spectral-postman">clone this example</a>, and follow <a target="_blank" href="https://github.com/postmanlabs/spectral-postman/blob/master/README.md">the README</a> to try it out locally. Otherwise, follow these pre-requisites.</p>
<ol>
<li>You’ll need a Postman account to use the <a target="_blank" href="https://docs.api.getpostman.com">Postman API</a> to programmatically access data stored in your Postman account. Skip this step if you’re working with standalone files of your Postman collection, environment, and OpenAPI specification.</li>
<li>Make sure you have <a target="_blank" href="https://nodejs.org/en/download/">Node.js</a> and a package manager like <a target="_blank" href="https://www.npmjs.com/package/download">npm</a> installed on your machine. Then, start a new project and install your dependencies locally.</li>
</ol>
<p>$ npm init<br />$ npm install newman @stoplight/spectral</p>
<blockquote>
<p><a target="_blank" href="https://github.com/postmanlabs/newman">Newman</a> — an open-source library by Postman for running Postman collections and tests</p>
<p><a target="_blank" href="https://github.com/stoplightio/spectral">Spectral</a> — an open-source JSON / YAML linter that supports OpenAPI Specification and JSON Schema</p>
</blockquote>
<h4 id="heading-step-1-lint-an-openapi-specification-file-locally">Step 1: Lint an OpenAPI specification file locally</h4>
<p><a target="_blank" href="https://github.com/postmanlabs/spectral-postman/blob/master/cosmos.yaml">Download this OpenAPI specification file</a> to your project directory. In your terminal, use Spectral to lint this specification file, and then decide which errors or warnings you want to fix.</p>
<p><code>$ ./node_modules/.bin/spectral lint cosmos.yaml</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163668547/a61e0b20-bb05-4abb-b9b7-75e35e7d58f2.gif" alt /></p>
<p>Run the lint check using Spectral from the command line</p>
<p>There’s a number of options <a target="_blank" href="https://stoplight.io/p/docs/gh/stoplightio/spectral/docs/getting-started/installation.md">for installing Spectral</a>, and depending on how you’ve completed the installation or have Node set up, you may need <a target="_blank" href="https://github.com/nodeschool/discussions/wiki/Installing-global-node-modules-%28Linux-and-Mac%29">to fiddle with it</a>. If you plan to use Spectral across multiple projects, install it globally to run:</p>
<p><code>$ spectral lint cosmos.yaml</code></p>
<h4 id="heading-step-2-generate-a-postman-collection-from-the-oas-file">Step 2: Generate a Postman collection from the OAS file</h4>
<p>In the Postman app, sign in to your Postman account, and then <a target="_blank" href="https://learning.getpostman.com/docs/postman/design-and-develop-apis/managing-apis/">import the specification file</a> as an API. Give this new API a name, select <code>OpenAPI 3.0</code> and <code>YAML</code> from the options, and then hit <strong>Save</strong>.</p>
<p>Now you can automatically <a target="_blank" href="https://learning.getpostman.com/docs/postman/design-and-develop-apis/the-api-workflow/#generating-a-collection-from-a-schema">generate a Postman collection from your specification file</a>. For now, we’ll just write API tests. But remember, you can also generate <a target="_blank" href="https://learning.getpostman.com/docs/postman/api-documentation/intro-to-api-documentation/">documentation</a>, <a target="_blank" href="https://learning.getpostman.com/docs/postman/sending-api-requests/generate-code-snippets/">code samples</a>, <a target="_blank" href="https://learning.getpostman.com/docs/postman/monitors/intro-monitors/">monitors</a>, or even <a target="_blank" href="https://learning.getpostman.com/docs/postman/mock-servers/intro-to-mock-servers/">virtualize mock services</a> in Postman.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163670398/f6e56b82-26da-4147-b519-d72eaf14f69e.gif" alt /></p>
<p>Import an OAS 3.0 specification and <a target="_blank" href="https://learning.getpostman.com/docs/postman/design-and-develop-apis/the-api-workflow/#generating-a-collection-from-a-schema">generate a Postman collection</a></p>
<blockquote>
<p><strong><em>💡 POSTMAN TIP*</em></strong>:<em> [</em>Import your specification file<em>](https://learning.getpostman.com/docs/postman/design-and-develop-apis/the-api-workflow/#importing-a-file) </em>into the Postman app to<em> [</em>generate a collection<em>](https://learning.getpostman.com/docs/postman/design-and-develop-apis/the-api-workflow/#generating-a-collection-from-a-schema)</em>. The collection is the foundation for creating<em> [</em>documentation<em>](https://learning.getpostman.com/docs/postman/api-documentation/intro-to-api-documentation/)</em>,<em> [</em>code samples<em>](https://learning.getpostman.com/docs/postman/sending-api-requests/generate-code-snippets/)</em>,<em> [</em>monitors<em>](https://learning.getpostman.com/docs/postman/monitors/intro-monitors/)</em>, or<em> [</em>mock services<em>](https://learning.getpostman.com/docs/postman/mock-servers/intro-to-mock-servers/) </em>in Postman.*</p>
</blockquote>
<p>You’ll notice this newly generated collection describes the API just like the OAS file does, but it’s not quite actionable yet.</p>
<p>Create <a target="_blank" href="https://learning.getpostman.com/docs/postman/environments-and-globals/manage-environments/">a new Postman environment</a> with a key <code>baseUrl</code> and the value <code>[https://e8c086f7-a5c9-4752-b81f-bfac0d0dc5d2.mock.pstmn.i](https://e8c086f7-a5c9-4752-b81f-bfac0d0dc5d2.mock.pstmn.io,)o</code>.</p>
<p>Now you can submit your first request — go ahead and try it out!</p>
<h4 id="heading-step-3-write-some-postman-tests">Step 3: Write some Postman tests</h4>
<p>We won’t make any changes in this folder so that you can refer back to it. Instead, duplicate this folder to add some tests.</p>
<p>Under the <strong>Tests</strong> tab, add a few tests using the snippets on the right or writing your own from scratch. For the first request <code>[GET List all cosmos](https://documenter.getpostman.com/view/1559645/SW7T7WmM?version=latest#3a5e52d8-969b-46e9-88a2-d1213aa96aca)</code>, let’s also randomly pick one of the items returned in the response, parse the ID, and then save that information as an environment variable so we can use it in the next request. Remember to hit <strong>Send</strong> to execute this code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163672309/cde03591-acc5-4cf3-9eea-7bcbff20f3e0.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163673929/c4ccdcc0-6622-4391-817b-062151f71cb4.png" alt /></p>
<p>Under the <strong>Tests</strong> tab, <a target="_blank" href="https://learning.getpostman.com/docs/postman/scripts/test-scripts/">write Postman tests</a> and save data as an environment variable to be used later</p>
<p>In the next request <code>[GET Info for a specific constellation](https://documenter.getpostman.com/view/1559645/SW7T7WmM?version=latest#96cd8068-7d50-4d94-b221-4be0ee36f4bb)</code>, look under the <strong>Params</strong> tab and change the value of the <code>cosmoId</code> key from <code>&lt;string&gt;</code> to <code>{{constellationId}}</code>. This is the name of the environment variable that you set from the previous response, allowing this data to be accessed for this request.</p>
<h4 id="heading-step-4-run-the-postman-tests-locally">Step 4: Run the Postman tests locally</h4>
<p>In the Postman app, we can run all of our Postman tests using <a target="_blank" href="https://learning.getpostman.com/docs/postman/collection-runs/starting-a-collection-run/">the collection runner</a>. Another option is to <a target="_blank" href="https://learning.getpostman.com/docs/postman/collections/data-formats/#collections">export the collection</a> and environment as JSON files to run tests from the command line using Newman.</p>
<p>$ newman run Cosmos.postman_collection.json -e cosmos.postman_environment.json</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163674974/a023882e-c072-4558-aad5-834d69566e6e.gif" alt /></p>
<p>Run the API tests using Newman from the command line</p>
<h4 id="heading-step-5-run-tests-and-lint-specifications-in-cicd">Step 5: Run tests and lint specifications in CI/CD</h4>
<p>Instead of running our checks locally, let’s add it to our continuous integration pipeline. We’ll use a bash script, but you can execute this in any manner that you like. Create a new folder called <code>bin/</code> to hold a new executable file called <code>deploy.sh</code>.</p>
<p>Once again, we’ll use Newman to run our collection and Spectral to lint our specification. Last time, we used static files located within our project directory, but a <em>better</em> practice is to pass these elements as a URL. Using the <a target="_blank" href="https://docs.api.getpostman.com">Postman API</a> to dynamically retrieve the latest versions, means that we can make changes in Postman without needing to re-export the latest files.</p>
<p>Here’s an example of how you can structure your deploy script:</p>
<p><a target="_blank" href="https://github.com/postmanlabs/spectral-postman/blob/master/bin/deploy.sh"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163677271/3d0fcdb9-7d64-48dd-927a-03474eb3d726.png" alt /></a></p>
<p>Run API tests and lint API specifications in a continuous integration workflow, like <a target="_blank" href="https://github.com/postmanlabs/spectral-postman/blob/master/bin/deploy.sh"><strong>this example script</strong></a></p>
<blockquote>
<p><strong><em>💡 POSTMAN TIP*</em></strong>: Instead of exporting and then referencing static files, use the<em> [</em>Postman API<em>](https://docs.api.getpostman.com) </em>to dynamically retrieve the latest version of your collection, environment, or specification, and then pass these elements as a URL.*</p>
</blockquote>
<p>Once you’ve written the script, remember to add the path of the deploy script file to your <code>package.json</code> file.</p>
<p><em>...<br />"scripts"</em>: {</p>
<p> <em>"deploy"</em>: "./bin/deploy.sh"</p>
<p>},</p>
<p>...</p>
<p>Then you can run your deploy script from the command line.</p>
<p>$ npm run deploy</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163678286/4793546c-fe46-4fb1-ac68-98bdaa1d0729.gif" alt /></p>
<p>If you’re using a tool <a target="_blank" href="https://learning.getpostman.com/docs/postman/collection-runs/integration-with-jenkins/">like Jenkins</a> or <a target="_blank" href="https://learning.getpostman.com/docs/postman/collection-runs/integration-with-travis/">Travis CI</a> to manage your Continuous Integration / Continuous Deployment (CI/CD) pipeline, simply add a build step to execute this command.</p>
<p>If we experience any failures or errors, our code won’t deploy.</p>
<h4 id="heading-step-6-create-a-custom-style-guide">Step 6: Create a custom style guide</h4>
<p>We’re testing. We’re linting. These are all good things!</p>
<p>But hold up. Just like how tests are only as good as we make them, linting is only as good as the rules we’ve defined.</p>
<p>If you work on a team, there’s probably style preferences and code requirements that everyone abides by. When pull requests are submitted, deviations are hopefully caught in code review, but frequently they’re missed. And I can already see there’s default lint warnings that I have no intention of ever addressing.</p>
<p>Let’s make a style guide by creating a new file called <code>.spectral.yaml</code> where we will define our <a target="_blank" href="https://stoplight.io/p/docs/gh/stoplightio/spectral/docs/getting-started/rulesets.md">custom rules</a> to use with Spectral. For example, I want all of our URL paths to be <code>camelCase</code>, and not some ridiculous <code>kebab-case</code>!</p>
<p><a target="_blank" href="https://github.com/postmanlabs/spectral-postman/blob/master/.spectral.yaml"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163680197/6f857793-ee67-4665-ae37-233c4acc481f.png" alt /></a></p>
<p>Create a style guide with your own custom linting rules, like <a target="_blank" href="https://github.com/postmanlabs/spectral-postman/blob/master/.spectral.yaml">this example</a></p>
<p>Style guides ensure that everyone agrees to specified conventions. Creating a style guide in this manner also provides an easy way to enforce these conventions.</p>
<h3 id="heading-a-final-thought-about-api-descriptions-and-linting">A final thought about API descriptions and linting</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163681321/55d901ce-a12d-46ca-8ab2-634a43b0bedf.jpeg" alt /></p>
<p>Using an API specification can be useful to standardize how data is exchanged between services. Furthermore, it can be useful to standardize how information is relayed between collaborating teams and throughout various phases of development.</p>
<p>Using a specifications linter allows you to save time otherwise spent on manual reviews. Creating a custom style guide allows you to align your team’s opinions about API design and documentation. And perhaps even more importantly, it’s also an easy way to automatically enforce these rules and govern the API development process.</p>
<blockquote>
<p>Don’t waste customers time forcing them to try and figure out your inconsistencies.</p>
<p>Don’t waste all API developers time learning to memorizing style guides.</p>
<p>Don’t waste the API governance teams time reviewing APIs manually.</p>
<p>Don’t waste everyone’s time fixing inconsistencies in production later.</p>
<p>- <a target="_blank" href="https://twitter.com/philsturgeon">Phil Sturgeon</a>, <a target="_blank" href="https://apisyouwonthate.com/blog/automated-style-guides-for-rest-graphql-and-grpc">APIs you won’t hate</a></p>
</blockquote>
<p>As with all of these better practices, the important thing is to understand the possible solutions, and then determine what is most helpful to achieve your organization’s desired workflow.</p>
]]></content:encoded></item><item><title><![CDATA[Learn how your Kubernetes clusters respond to failure using Gremlin and Grafana]]></title><description><![CDATA[Building resilient APIs with chaos engineering
I don’t deal with failure well. But I’ve gotten better at it because I fail a lot. In fact, the more I fail, the better I anticipate all the ways I can possibly crash and burn and shore up those vulnerab...]]></description><link>https://blog.joycejetson.com/chaos-d3ef238ec328</link><guid isPermaLink="true">https://blog.joycejetson.com/chaos-d3ef238ec328</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Tue, 20 Aug 2019 18:35:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163710425/91884ba9-034b-4b9b-ad23-b28282289885.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-building-resilient-apis-with-chaos-engineering">Building resilient APIs with chaos engineering</h4>
<p>I don’t deal with failure well. But I’ve gotten better at it because I fail a lot. In fact, the more I fail, the better I anticipate all the ways I can possibly crash and burn and shore up those vulnerabilities.</p>
<p>This anticipation <em>could</em> keep me up at night, but I’m stronger for it instead.</p>
<p>On <a target="_blank" href="https://medium.com/better-practices"><em>Better Practices</em></a>, we’ve previously talked about how working in the cloud is growing increasingly complex as teams continue to adopt microservice and distributed architectures. Some approaches are to <a target="_blank" href="https://medium.com/better-practices/api-first-software-development-for-modern-organizations-fdbfba9a66d3">enable flexibility with an API-first approach</a> or to <a target="_blank" href="https://medium.com/better-practices/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9">increase velocity by using containers and an orchestration engine</a>.</p>
<p>Another approach is with chaos engineering.</p>
<p>Distributed systems are inherently chaotic, and a number of organizations are embracing this chaos as they move to the cloud. They intentionally inject failure into their system in order to identify previously unknown vulnerabilities.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163684800/fe18e2c6-359e-45c8-8374-9bdff7960b0a.png" alt /></p>
<p>What happens when one of your dependencies fail?</p>
<p>What happens when one of your dependencies fail? By proactively controlling the conditions of a failure, you can learn from your system’s response on your own terms, instead of during an unanticipated outage.</p>
<h3 id="heading-what-is-chaos-engineering">What is Chaos engineering?</h3>
<p>When Netflix famously transitioned from a monolithic architecture over to a distributed cloud architecture, they worried about <a target="_blank" href="https://medium.com/netflix-techblog/lessons-netflix-learned-from-the-aws-outage-deefe5fd0c04">how potential downtime would impact their users</a>. The Netflix team introduced <a target="_blank" href="https://github.com/Netflix/chaosmonkey">Chaos Monkey</a> to pseudo-randomly kill instances in order to simulate random server failure.</p>
<p>They wanted to make sure they could survive this type of failure and better understand the impact of such a failure on their customers. The goal was to fortify their distributed systems to expect and tolerate failure from other systems on which they depend.</p>
<p><a target="_blank" href="https://www.oreilly.com/ideas/chaos-engineering"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163685732/2f7f96ac-5119-409b-8c69-facc6b384436.jpeg" alt /></a></p>
<blockquote>
<p><a target="_blank" href="https://youtu.be/9MvcXO4L4Tk">[Chaos engineering] incentivizes engineers to build their services to anticipate that some servers will suddenly go away… so they have to build their services to be redundant, highly available, and fault tolerant.</a></p>
<p><a target="_blank" href="https://twitter.com/caseyrosenthal?">-Casey Rosenthal</a>, CEO at <a target="_blank" href="https://www.verica.io/">Verica</a></p>
</blockquote>
<p>Shortly thereafter, the Netflix team introduced a virtual <a target="_blank" href="https://medium.com/netflix-techblog/the-netflix-simian-army-16e57fbab116">Simian Army</a>, with each new Monkey tasked with inducing another type of failure — such as degrading a service or killing an entire region. Since then, the chaos community has developed <a target="_blank" href="https://github.com/dastergon/awesome-chaos-engineering">a number of tools</a> to more precisely cause chaos in a controlled manner.</p>
<p>Today, there’s a number of companies who have embraced <a target="_blank" href="https://principlesofchaos.org/">the principles of chaos engineering</a>. Some teams might focus on failure injection testing or disaster recovery training, while adopting only the tools and practices that work for their specific goals.</p>
<p>Across all of these programs, a disciplined approach teaches them how to improve their systems so they can better tolerate future, <em>unplanned</em> failures.</p>
<blockquote>
<p>Why worry about something that isn’t going to happen?</p>
<p>- <a target="_blank" href="https://www.hbo.com/chernobyl">HBO miniseries “Chernobyl”</a></p>
</blockquote>
<h3 id="heading-why-look-for-trouble">Why look for trouble?</h3>
<p>A chaos experiment is like running a fire drill. Imagine that you’ve already created an emergency protocol in case of a fire, sent it out to everyone, and you test the fire alarm once a month to make sure it’s functioning.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163686718/c672b92d-3325-4ae1-a2be-c978cf87dd11.jpeg" alt /></p>
<p>Now what happens when you run the fire drill? You might discover that there’s a few rooms where the alarm can’t be heard, most people don’t remember where they’re supposed to meet, while others ignore the drill and stay at their desks.</p>
<p>By proactively testing how a system responds to failure conditions, you can identify and fix failures before they become public-facing outages. Failures in production are costly, so Chaos Engineering lets you validate what you think will happen with what is actually happening in your systems.</p>
<p>“Breaking things on purpose” in order to build more resilient systems prepares your team in the event of an earthquake, a zombie attack, or whatever else comes your way.</p>
<h3 id="heading-who-is-responsible-for-chaos-engineering">Who is responsible for Chaos engineering?</h3>
<p>In a microservice architecture, the engineers building the services frequently have responsibility for deployment and uptime. In an organization with a traditional DevOps team, those DevOps engineers may own these service levels. Some companies have specialized teams of Site Reliability Engineers (SRE) or Production Engineers (PE) tasked with continuous improvement and production support.</p>
<p>Initially, the people with the highest motivation to implement chaos engineering are those who feel the pain of a failure in production, like the ones on call.</p>
<blockquote>
<p>I started doing [chaos engineering] so I would get woken up less in the middle of the night and better understand my software.</p>
<p><em>It boils down to who gets paged — if that’s an SRE or Ops team, they have the most incentive to start doing this work and making their lives better.</em></p>
<p><em>—</em> <a target="_blank" href="https://twitter.com/koltonandrus"><em>Kolton Andrus</em></a><em>, CEO at</em> <a target="_blank" href="https://www.gremlin.com/"><em>Gremlin</em></a></p>
</blockquote>
<p>Other people with a vested interest are the ones tasked with incident management or post-mortem analysis. The difference here is that incident management is a reactive process with steps taken to prevent reoccurrence. With chaos engineering, your experiments are conducted proactively by anticipating what <em>could</em> go wrong.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163688101/70acc4d2-fff8-4a0c-bef2-24ab8105a3d3.jpeg" alt /></p>
<p>Right now, the vast majority of people implementing chaos engineering tend to be quality-driven and production-focused operations engineers.</p>
<p>However, it also makes sense to introduce the responsibility of resiliency earlier in the development cycle, when the cost of bugs is lowest, to reduce financial and other consequences in production. As such, there’s an emerging trend of testers who focus on production testing in addition to traditional pre-release testing.</p>
<p>So who owns Chaos?</p>
<ul>
<li><strong>Specialized roles</strong> — Site Reliability Engineers (SRE), Production Engineers (PE)</li>
<li><strong>Functional teams</strong> — DevOps, Test and Quality Assurance (QA), Research and Development (R&amp;D)</li>
<li><strong>Domain knowledge experts</strong> — Traffic, database, data, storage</li>
</ul>
<p>The initial owners of chaos engineering will be determined by your team’s current infrastructure, talent, and goals. Furthermore, this responsibility may shift as more organizations migrate to the cloud, and chaos engineering becomes more mainstream and begins to augment traditional testing.</p>
<h3 id="heading-how-can-you-start-a-chaos-program">How can you start a chaos program?</h3>
<p>You don’t need a special job title or even Netflix-level traffic to begin dabbling in chaos. The chaos community has developed a <a target="_blank" href="https://github.com/dastergon/awesome-chaos-engineering">number of shared resources</a> to help advance this emerging discipline. Organizations like <a target="_blank" href="https://cloud.google.com/solutions/dr-scenarios-planning-guide">Google</a>, <a target="_blank" href="https://www.twilio.com/blog/2017/11/chaos-engineering-ratequeue-ha.html">Twilio</a>, <a target="_blank" href="https://www.pagerduty.com/blog/chaoscat-automating-fault-injection/">PagerDuty</a>, and many more have adopted their own approaches to chaos engineering.</p>
<p>In some cases, it’s a curious tester who kicks off a single chaos experiment after notifying the rest of her team. Maybe it’s a handful of engineers huddled together to plan their failures during a <a target="_blank" href="https://aws.amazon.com/gameday/">gameday</a>. Or it’s a directive from senior management to scope out a chaos program after one particularly costly outage.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163689351/bf47976e-9ffd-4fb6-8f19-a87251a5bf4a.jpeg" alt /></p>
<p>Once again, the implementation you choose will be determined by your team’s current infrastructure, talent, and goals.</p>
<blockquote>
<p><a target="_blank" href="https://www.linkedin.com/pulse/would-chaos-any-othername-casey-rosenthal/">Perhaps aggregate bits and pieces from different [resilience engineering] frameworks that appeal to you, and then create a practice around it. You’ll likely be the first person to create a similar practice in your particular context.</a></p>
<p><a target="_blank" href="https://www.linkedin.com/pulse/would-chaos-any-othername-casey-rosenthal/">I wish the best of luck to you in that undertaking, but I wouldn’t wager that you get it right on your first try. Or your second.</a></p>
<p>-<a target="_blank" href="https://twitter.com/caseyrosenthal?">Casey Rosenthal</a>, CEO at <a target="_blank" href="https://www.verica.io/">Verica</a></p>
</blockquote>
<p>A common pitfall is not clearly communicating the reasons why you are adopting chaos engineering practices in the first place. When the rest of the organization doesn’t yet understand or believe in the benefit, there’s going to be fear and confusion. Worse yet, there’s the perception that you’re just breaking stuff randomly and without a legitimate hypothesis.</p>
<h3 id="heading-how-do-you-run-a-chaos-experiment">How do you run a chaos experiment?</h3>
<p>While there’s many ways to run your chaos experiments, most processes echo the scientific method with a continuous cycle of hypothesis and experimentation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163690879/51ecfaf1-19e9-4eef-8256-65b62f2bdbb6.png" alt /></p>
<p>Make improvements, and automate the experiments to run continuously</p>
<p><strong>Plan an experiment.</strong> First, create a hypothesis about the steady-state behavior of your systems. Focus on if your systems <em>do</em> work, not <em>how</em> they work. Then think about what could go wrong. Perhaps a server goes down (as they do). Maybe it’s your third-party payment system, a specific cluster, or an entire region that’s experiencing an outage.</p>
<p><strong>Start small</strong>. Initiate an attack that’s small enough to give you information about how your systems react in a production environment. You can’t always predict how users will behave. Instead of testing code in an isolated environment, <a target="_blank" href="https://techbeacon.com/app-dev-testing/test-production-yes-you-can-you-should">test a complete system in production</a> comprised of users, code, environment, infrastructure, a singular point in time, and more.</p>
<p><strong>Measure the impact</strong>. Observe the impact of your attack by comparing it to your steady-state metrics to reveal any known and unknown issues. At this point, you can either turn up the juice on your attack or roll it back if there were unintended and potentially harmful side effects.</p>
<p><strong>Learn more about your systems.</strong> Validate or update your hypothesis, and shore up your vulnerabilities. Make these improvements, and then be prepared to automate your experiments to run continuously.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163692098/6243d956-5b0e-4a7e-8bc8-525fcea68c9b.png" alt /></p>
<p>Just like a fire drill, your team is developing a muscle memory by practicing how to respond when the stakes are controlled, instead of practicing during an actual emergency. By methodically performing these automated tests, you can learn more about your systems’ real-world behavior.</p>
<p>If you’re just getting your feet wet with chaos engineering, consider starting with your APIs. We’ve previously talked about using APIs <a target="_blank" href="https://medium.com/better-practices/dont-get-techcrunched-performance-testing-for-your-http-apis-3196e40f6b70">to create additional load</a> or <a target="_blank" href="https://medium.com/better-practices/reverse-engineering-an-api-403fae885303">security injections and other user behavior</a>. Now you can test your fallbacks by simulating the outage of external third-party APIs or killing your own internal APIs.</p>
<blockquote>
<p><a target="_blank" href="https://www.gremlin.com/blog/making-your-apis-more-resilient-with-gremlin/">When a company measures their critical services, APIs are often considered second-class citizens.</a></p>
<p><a target="_blank" href="https://www.gremlin.com/blog/making-your-apis-more-resilient-with-gremlin/">But APIs are a core part of an organization’s infrastructure, and not understanding their weaknesses can lead to performance issues and downtime.</a></p>
<p>- <a target="_blank" href="https://twitter.com/tammybutow">Tammy Butow</a>, Principal Site Reliability Engineer at <a target="_blank" href="https://www.gremlin.com/">Gremlin</a></p>
</blockquote>
<p>One way to experience an API outage is by simply unplugging a server. But what if the servers aren’t yours, or they’re hard to reach? Or you realize you’ve unplugged the wrong machine? Oops. You can’t just plug it back in and expect service to resume right away. <strong>Don’t do that</strong>.</p>
<p>Another way to experience an API outage is by using <a target="_blank" href="https://learning.getpostman.com/docs/postman/mock_servers/intro_to_mock_servers">a Postman mock</a> to return a 500 internal server error. This works, but it’s still just a simulation. While we can simulate outages in a test environment, there’s only one way to capture the unquantifiable conditions that cannot be replicated in an isolated test environment.</p>
<p>Eventually we want to break stuff in production 😈</p>
<h3 id="heading-a-postman-recipe-for-creating-chaos-with-amazon-eks-and-gremlin">A Postman recipe for creating chaos with Amazon EKS and Gremlin</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163693349/f56ee4e8-65d0-44ba-bbc8-b8daf70a7938.png" alt /></p>
<p>Let’s start with an example e-commerce app where users can browse items, add them to the cart, and purchase them. Then we’ll shut down a container and see what hijinks ensue.</p>
<ul>
<li><strong>Trigger:</strong> <a target="_blank" href="https://www.gremlin.com/">Gremlin</a> is a failure-as-a-service and offers a free version with limited attack types. We’ll be using Postman with the Gremlin API to trigger our attacks. <em>Spoiler alert</em> . . . this is so we can easily automate these chaos tests with our continuous integration pipeline.</li>
<li><strong>Target:</strong> We’ve previously talked about <a target="_blank" href="https://medium.com/better-practices/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9">deploying scalable apps with Docker and Kubernetes</a>. <a target="_blank" href="https://aws.amazon.com/eks/">Amazon EKS</a> is a managed Kubernetes service that runs on AWS. It ain’t cheap. If you’re already running on hosts, containers, or another cloud platform, swap out EKS with your own target.</li>
<li><strong>Observability:</strong> We’ll use <a target="_blank" href="https://prometheus.io/">Prometheus</a> as our time-series database and <a target="_blank" href="https://grafana.com/">Grafana</a> to visualize the effects of our attacks. Both are open-source and have a free version. If you’re already using something else for steady-state monitoring, swap out Prometheus and Grafana with your own toolset.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163694724/22fad454-33aa-43d7-a7c5-97a1cdd57af8.png" alt /></p>
<p>a Postman recipe for creating chaos</p>
<h4 id="heading-set-up-gremlin-and-create-a-kubernetes-cluster-on-eks">Set up Gremlin and create a Kubernetes cluster on EKS</h4>
<p>If you want to jump to the end, go ahead and <a target="_blank" href="https://github.com/postmanlabs/kubernetes-chaos">clone this example</a>. Otherwise, let’s begin with <a target="_blank" href="https://www.gremlin.com/community/tutorials/how-to-install-and-use-gremlin-with-eks/">this helpful guide to install Gremlin to use with Amazon EKS</a>. You’ll need an AWS account, the AWS CLI configured to use <code>eksctl</code> to create the EKS cluster, and a Gremlin account.</p>
<ul>
<li>Step 0 — <a target="_blank" href="https://www.gremlin.com/community/tutorials/how-to-install-and-use-gremlin-with-eks/#step-0---verify-your-account-aws-cli-installation">Verify your account AWS CLI Installation</a></li>
<li>Step 1 — <a target="_blank" href="https://www.gremlin.com/community/tutorials/how-to-install-and-use-gremlin-with-eks/#step-1---create-an-eks-cluster-using-eksctl">Create an EKS cluster using eksctl</a></li>
<li>Step 2 — <a target="_blank" href="https://www.gremlin.com/community/tutorials/how-to-install-and-use-gremlin-with-eks/#step-2---load-up-the-kubeconfig-for-the-cluster">Load up the kubeconfig for the cluster</a></li>
<li>Step 3 — <a target="_blank" href="https://www.gremlin.com/community/tutorials/how-to-install-and-use-gremlin-with-eks/#step-2---deploy-kubernetes-dashboard">Deploy Kubernetes Dashboard</a></li>
<li>Step 4 — <a target="_blank" href="https://www.gremlin.com/community/tutorials/how-to-install-and-use-gremlin-with-eks/#step-4---deploy-a-microservice-demo-application">Deploy a Microservice Demo application</a></li>
<li>Step 5 — <a target="_blank" href="https://www.gremlin.com/community/tutorials/how-to-install-and-use-gremlin-with-eks/#step-5---run-a-shutdown-container-attack-using-gremlin">Run a Shutdown Container Attack using Gremlin</a> (skip)</li>
</ul>
<p>After that, you should have a sample app deployed on AWS EKS and Gremlin running on your <a target="_blank" href="https://github.com/kubernetes/dashboard">Kubernetes dashboard</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163696252/9022b19b-7937-4036-95d3-daea6ab2a86c.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163697829/a81706ff-472c-4d37-8fdf-d66b0299b216.png" alt /></p>
<p>1) Sample app deployed in EKS, and 2) Gremlin installed using Kubernetes Dashboard</p>
<h4 id="heading-set-up-grafana-and-prometheus">Set up Grafana and Prometheus</h4>
<p>If you’re still with me, let’s set up <a target="_blank" href="https://medium.com/htc-research-engineering-blog/monitoring-kubernetes-clusters-with-grafana-e2a413febefd">Monitoring Kubernetes Clusters with Grafana</a>. This particular guide starts with Google Kubernetes Engine (GKE) instead of EKS, but most of the remaining steps are the same after you create your cluster.</p>
<ul>
<li>Step 0 — Create a GKE cluster (skip)</li>
<li>Step 1 — Lots and lots and lots of yaml configuration</li>
<li>Step 2 — Configure your cluster settings on Grafana (skip)</li>
</ul>
<p>Instead of configuring your cluster settings on Grafana, you can simply import an existing dashboard if your monitoring tools are running on your cluster. Check out the README in <a target="_blank" href="https://github.com/postmanlabs/kubernetes-chaos">the sample repo</a> for more details on how to manage external access to the apps running inside the cluster.</p>
<p>After that, you should be able to observe the steady-state metrics of all the nodes in your cluster.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163699490/ba72ffc0-1a57-47ed-985d-2e4085530378.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163701205/6f1d16f1-1a78-4596-82d3-516b56e46e8b.png" alt /></p>
<p>1) Add a datasource of Prometheus type, and 2) import dashboard 3131 for an overview of all nodes in your cluster</p>
<h4 id="heading-programmatically-manage-your-chaos-experiments">Programmatically manage your chaos experiments</h4>
<p>A <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/pods/pod/">Kubernetes pod</a> is composed of one or more containers that share a network stack. If we attack a single container within a pod, the impact should be observed for all containers collocated within that pod. Optionally, we can further specify container ports to restrict the impact of our attack.</p>
<p>In the last step of the Gremlin tutorial, we shut down a container using Gremlin’s UI. We could also use an API to run our attacks so that we can programmatically manage our chaos experiments.</p>
<p>Let’s use Postman to shut down a single container via the <a target="_blank" href="https://www.gremlin.com/docs/api-reference/overview/">Gremlin API</a>.</p>
<p>In the Postman app, <a target="_blank" href="https://learning.getpostman.com/docs/postman/launching_postman/newbutton/#templates">import the template</a> <code>Chaos engineering</code> which includes a corresponding environment <code>chaosEngineering</code>. Check out the <a target="_blank" href="https://documenter.getpostman.com/view/1559645/SVfH1sqD">Chaos engineering documentation</a> for step-by-step instructions.</p>
<p><a target="_blank" href="https://app.getpostman.com/run-collection/b07acbdc8e6f2d2b59f8#?env%5BchaosEngineering%5D=W3sia2V5IjoibW9ja191cmwiLCJ2YWx1ZSI6Imh0dHBzOi8vYmQwMTVmMWUtNjQwMS00MzdkLTliYjYtYTk4NDg4MmVlMzNlLm1vY2sucHN0bW4uaW8iLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6ImdyZW1saW5fYXBpIiwidmFsdWUiOiJodHRwczovL2FwaS5ncmVtbGluLmNvbS92MSIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiZ3JlbWxpbl9hcGlfa2V5IiwidmFsdWUiOiJ5b3VyLWdyZW1saW4tYXBpLWtleSIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoieW91cl9kZXBsb3llZF9hcHBfVVJMIiwidmFsdWUiOiJ5b3VyLWRlcGxveWVkLWFwcC11cmwiLCJlbmFibGVkIjp0cnVlfV0="><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163701913/51679a5e-b416-4573-ad8b-e6602931979f.png" alt /></a></p>
<p>Click this enticing button to import the template</p>
<p>You’ll first need <a target="_blank" href="https://learning.getpostman.com/docs/postman/environments_and_globals/manage_environments/#editing-an-active-environment">to update the Postman environment</a> with your <code>gremlin_api_key</code> and <code>your_deployed_app_url</code>. Then look for the folder called <code>Shut down a container</code>.</p>
<ol>
<li>Get a list of our active containers</li>
<li>Shut down a specified container</li>
<li>Verify the health of our app</li>
<li>Stop the attack (if you need to)</li>
</ol>
<p>Our hypothesis is that if we shut down the container running <code>cartservice</code>, EKS will give us a new one, and we won’t suffer any downtime. However, if we experience unintended effects, let’s be prepared to stop the attack.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163703357/768d0a3c-7813-4f1f-a8f0-0b3e991a0bfe.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163704891/429cdfb8-c8aa-46a0-81fd-2224238d998a.png" alt /></p>
<p>1) Shut down a container using the Gremlin API, and 2) see the effects in your browser</p>
<p>Yikes! When we shut down the cartservice container, we see a 500 error on our shopping cart page. We see this in our browser and also in Postman if we make a <code>GET</code> request to our deployed app’s URL.</p>
<p>If you completed the last step of the Gremlin tutorial, you already know this is because <code>cartservice</code> <a target="_blank" href="https://github.com/GoogleCloudPlatform/microservices-demo/blob/master/kubernetes-manifests/cartservice.yaml">uses Redis</a> instead of Redis Cluster. Now that we have revealed this vulnerability, we can have a broader discussion with other team members about your data solution.</p>
<p>In the meantime, let’s make a <code>DELETE</code> request using the Gremlin API to stop our attack, and add some code to Postman to <em>only</em> stop our attack if we see a 500 internal server error.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163706733/e11623fe-2f22-4186-91fe-4179c2bff0b3.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163708196/ca15fb81-db3d-43ec-9a43-b1b0714591d8.png" alt /></p>
<p>1) Stop the attack if we see a 500 internal server error in Postman, and 2) Run our chaos tests automatically in the collection runner</p>
<p>In this manner, we can use Postman and the Gremlin API to explore what happens when we break a specific part of our system. Beyond manual testing, however, we’ve also seen how to automatically run our integration tests <a target="_blank" href="https://learning.getpostman.com/docs/postman/collection_runs/starting_a_collection_run">using the collection runner</a> and a little bit of code.</p>
<blockquote>
<p><em>🎓</em> <strong><em>Advanced challenge:</em></strong> <em>now that we know how to use the Postman app to manage our chaos experiments, how can we can automate chaos testing with our continuous integration (CI) pipeline or continuous testing process? Here’s</em> <a target="_blank" href="https://gph.is/1sFFzLq"><em>a clue</em></a><em>. And here’s</em> <a target="_blank" href="https://medium.com/better-practices/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9#ed88"><em>a better clue</em></a><em>.</em></p>
</blockquote>
<h3 id="heading-a-final-thought-about-chaos-engineering">A final thought about Chaos Engineering</h3>
<p><strong>So what happens when one of your dependencies fail?</strong> A valuable chaos test will not only teach you about your systems, but also your people. The human response is frequently one of the more difficult aspects to test in a proactive and systematic fashion. It’s probably easier to test the impact of a server crash.</p>
<p>When chaos experiments impact production traffic and users in real life, other teams will be impacted and hopefully notified before any experiments begin. Your team’s ability to communicate and collaborate will inevitably impact the resiliency of your systems.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163709429/9f7dee2e-e35b-40cf-9886-4bbe063a6422.jpeg" alt /></p>
<blockquote>
<p>The biggest limitation in the fear of delivering software faster is the focus on adding more pre-release testing.</p>
<p>Chaos engineering is all about building trust in our resiliency and mean time to recovery. In time, we have less fear that any one change will bring down our products and when issues do occur, we are practiced in triaging and deploying fixes faster, building confidence that we aren’t fragile.</p>
<p>- <a target="_blank" href="https://twitter.com/a_bangser">Abby Bangser</a>, Platform Test Engineer at <a target="_blank" href="https://www.moo.com">MOO</a></p>
</blockquote>
<p>For many teams, chaos engineering will require a mental shift in how failures are perceived in the organization. It’s great to identify a failure and bring it to the attention of the rest of your team. However, it’s even better to create a process that anticipates potential failures, and then reveals new information to help shore up your vulnerabilities.</p>
<p>Chaos engineering is not just about building more resilient software, but also building a culture of resiliency within an organization. A team that truly celebrates failures, instead of hiding them, will enable the broader organization to learn and grow stronger from these experiences.</p>
]]></content:encoded></item><item><title><![CDATA[Deploying a scalable web application with Docker and Kubernetes]]></title><description><![CDATA[Learn how to test and deploy a Node.js app using containers and an orchestration engine

Photo by chuttersnap on Unsplash
As cloud applications grow in complexity, sometimes teams reorganize into a distributed microservice architecture and software d...]]></description><link>https://blog.joycejetson.com/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9</link><guid isPermaLink="true">https://blog.joycejetson.com/deploying-a-scalable-web-application-with-docker-and-kubernetes-a5000a06c4e9</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Mon, 04 Mar 2019 18:18:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163658534/9003531e-fd5b-450d-84ba-18d1fd528105.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-learn-how-to-test-and-deploy-a-nodejs-app-using-containers-and-an-orchestration-engine">Learn how to test and deploy a Node.js app using containers and an orchestration engine</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163640901/e914e807-3c60-4385-b021-dc54a1d970c0.jpeg" alt /></p>
<p>Photo by <a target="_blank" href="https://unsplash.com/photos/eqwFWHfQipg?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">chuttersnap</a> on <a target="_blank" href="https://unsplash.com/photos/uBe2mknURG4?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>As cloud applications grow in complexity, sometimes teams reorganize into a distributed microservice architecture and software delivery cycles get faster. Throughout all of this, DevOps engineers keep looking for ways to streamline and automate the continuous deployment of code.</p>
<p>Some teams use containers, like <a target="_blank" href="https://www.docker.com/">Docker</a>, to simplify and automate the deployment process for their applications. This is an effective way of packaging software in a way that is predictable and consistent. You can expect the software to behave similarly whether you’re on a laptop or in the cloud.</p>
<p>Once you get to a point where you’re running multiple containers across multiple machines, spinning up more instances of your components doesn’t scale linearly and dealing with this growing complexity gets a little hairy. Many teams will address this complexity by also using an orchestration engine, like <a target="_blank" href="https://kubernetes.io/">Kubernetes</a>. Teams are using Kubernetes as a higher-level abstraction to manage Docker container technology and further simplify the pipeline to enable their teams to go faster.</p>
<blockquote>
<p>We’re already seeing tremendous benefits with Kubernetes — improved engineering productivity, faster delivery of applications and a simplified infrastructure.</p>
<p>Teams who were previously limited to 1–2 releases per academic year can now ship code multiple times per day!</p>
<p><a target="_blank" href="https://kubernetes.io/case-studies/pearson/">Chris Jackson, Director for Cloud Platforms &amp; SRE at Pearson</a></p>
</blockquote>
<p>You don’t need to have Google- or Facebook-level traffic to care about making your web applications scalable. You might have a varying number of users, need to accurately predict your infrastructure costs, or just want to manage your systems more efficiently.</p>
<p>To better understand software containers, let’s first talk about physical shipping containers.</p>
<h3 id="heading-why-use-containers"><strong>Why use containers?</strong></h3>
<p>Before someone invented physical shipping containers, dock workers needed specialized skills to handle different types of precious cargo. Physical containers allow us to standardize how our cargo is shipped.</p>
<p>There’s many reasons to use a container to ship something like bundles of firewood, for example.</p>
<ul>
<li><strong>Portability</strong> — your container can be loaded onto any ship, transported by any shipping provider, or even transferred to a truck to travel over the road</li>
</ul>
<p>Photo by <a target="_blank" href="https://unsplash.com/photos/RJjY5Hpnifk?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Erwan Hesry</a> on <a target="_blank" href="https://unsplash.com/search/photos/shipping-container?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<ul>
<li><strong>Modularity</strong> — containers are all the same size and dimension, so the same crane that is used at any port to handle your container of firewood can also be used to load and unload a container of loose chickens 🐔</li>
<li><strong>Security</strong> — your container is isolated from other containers, so that someone shipping fish tanks won’t slosh fish water 🐟 onto your bundle of firewood</li>
<li><strong>Scalability</strong> — your firewood will only take up the space needed, so you can either occupy a small corner of one container or ramp up to reserve a bunch more containers across a fleet of ships</li>
</ul>
<p>Similar to physical shipping containers, software containers are useful for standardization. In this case, software containers standardize IT infrastructure. Containers are a tidy way to package code with their dependencies into building blocks that can be deployed consistently and efficiently.</p>
<ul>
<li><strong>Portability</strong> — a container is decoupled from the host operating system, so that it can run on anything from a laptop to your cloud of choice</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163642293/e9d0595f-d3c1-493c-bc83-d29c61d0936c.jpeg" alt /></p>
<p>Photo by <a target="_blank" href="https://unsplash.com/photos/jUWw_NEXjDw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Markus Spiske</a> on <a target="_blank" href="https://unsplash.com/search/photos/software-container?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<ul>
<li><strong>Modularity</strong> — containers give you the flexibility to create easily interchangeable application stack components, so you have a separation of concerns between components like your web server and your database</li>
<li><strong>Security</strong> — containers are immutable so updates are made by replacing the container in its entirety, making it easy to issue security patches or rollback an update quickly</li>
<li><strong>Scalability</strong> — containerized applications can scale up to handle additional load or ramp down to conserve resources during a lull</li>
</ul>
<h3 id="heading-how-do-containers-work">How do containers work?</h3>
<p>Let’s revisit our physical shipping containers analogy and imagine a busy seaport where ships are coming and going all day long. There’s a <strong><em>container manifest</em></strong> that lists the contents and the loading sequence of everything getting stuffed into the <strong><em>container</em></strong>. The container gets stuffed according to this manifest and then loaded onto a ship. The dock workers will <strong><em>orchestrate</em></strong> the logistics, keeping a schedule of when the containers get loaded and unloaded, managing the arrival and departure of the ships, and coordinating with the freight carriers. At a busy port like this, we’d have some pretty hefty tools to coordinate and govern all of these details.</p>
<p>Now, back to the world of software containers.</p>
<p><a target="_blank" href="https://www.docker.com/why-docker">Docker</a> is one of the most popular, open-source container technologies that allows you to build, run, test, and deploy distributed applications. There’s a lot of terminology, so let’s contain our excitement, and just tackle some of the basics.</p>
<h4 id="heading-container-image">Container image</h4>
<p>This image will inform how a container is instantiated, determining which software components will run and how. You can also create an image from a container, and share these specifications with someone else, so that an app runs the same way on a developer’s laptop as it would in production.</p>
<h4 id="heading-container">Container</h4>
<p>This describes a virtual environment that bundles the application code with all the binaries and libraries that are required to run an application. Since the container includes all of its dependencies, you don’t have to install anything on the host operating system, keeping it separate and pristine.</p>
<h4 id="heading-container-orchestration">Container orchestration</h4>
<p>This refers to coordinating behaviors for containers and between containers, such as scheduling, resource management, and load balancing. In complex or dynamic ecosystems, teams will use an orchestration engine to control, manage, and automate this activity.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163643638/01b862c7-d57e-4c0a-8e63-c27f6904c714.png" alt /></p>
<p>contain your excitement</p>
<p>After the Postman engineering team <a target="_blank" href="https://medium.com/postman-engineering/conquering-the-microservices-dependency-hell-at-postman-with-postman-part-1-introduction-a1ae019bb934">reorganized into a microservice architecture</a>, every service now uses Docker to configure their own environments. Every service owner defines their own Dockerfile from which an image is generated <a target="_blank" href="https://medium.com/postman-engineering/continuous-deployment-with-postman-collections-e2fb0b5d2235">when new code is deployed as part of the CI/CD pipeline</a>. The resulting image is pushed to the team’s container registry, and their Beanstalk environments are configured to pull the image from the registry to run the containers.</p>
<blockquote>
<p><strong>Every service gets the flexibility of configuring how to run their services. So services engineers can focus on building the application while platform engineers can focus on how to build and deploy automatically.</strong></p>
<p><strong>Docker takes over the responsibility of configuring the environment and standardising the deployment pipeline. This gives us faster deployment and scaling time because the build happens only once during CI.</strong></p>
<p><strong>—</strong> <a target="_blank" href="https://medium.com/@saswatds"><strong>Saswat Das</strong></a><strong>, Platform engineer at Postman</strong></p>
</blockquote>
<h3 id="heading-why-use-kubernetes"><strong>Why use Kubernetes?</strong></h3>
<p>With a microservice architecture, a number of services can go into making a single application, and each of these services can live in its own container. Even a simple web application might not live in a single container. You might have one container for the web frontend, one for the backend APIs, and maybe another for data storage. If you start seeing some traffic, you can spin up more instances of your app’s components.</p>
<p>However, simply spinning up more instances doesn’t scale linearly. Containers allow you to scale, but managing these operations at scale can be complicated. When you’re operating at scale, you will be coordinating behavior for containers and between containers.</p>
<p>That’s when an orchestration engine like <a target="_blank" href="https://kubernetes.io/">Kubernetes</a> comes into play. Kubernetes is an open-source, orchestration system for automating deployment, scaling, and management of containerized applications. As a higher-level abstraction to deal with container management, there’s a somewhat steep learning curve to get set up, but then it makes day-to-day life easier.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163644941/0abc358e-89e6-47a0-ab1e-cc8e67d75527.png" alt /></p>
<p>The Kubernetes master is responsible for maintaining the desired state for your cluster</p>
<blockquote>
<p>Kubernetes simplifies the deployment process for your application, and provides tools to make your application super robust.</p>
<p>With Kubernetes, you get rolling deployments with no downtime, service discovery, and the flexibility to change cloud providers easily.</p>
<p>— <a target="_blank" href="https://kubesail.com/">Dan Pastusek, Founder of Kubesail</a></p>
</blockquote>
<h3 id="heading-a-postman-recipe-for-deploying-a-node-application-with-docker-and-kubernetes">A Postman recipe for <strong>deploying a Node application with Docker and Kubernetes</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163646139/aacdf10c-b384-42a7-9964-0b64967e33a2.png" alt /></p>
<p>Let’s try it out! We’ll start with a simple Node app that functions like a URL shortener. In our case, we’ll transform one URL into a different one using cat verbs, cat adjectives, and cat emojis 🐱 — and when you input your custom URL into a browser, you’ll be redirected back to the original website.</p>
<p>The beauty of using containers is that even if I’m developing this app on a machine with my Operating System and a different version of Node, you can rely on my container image to prescribe the exact specifications you’ll need to run the same application seamlessly on your machine, or in the cloud, or wherever you choose to deploy.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163647390/20906ae5-974b-4d8d-bbd6-6185c19c4fdd.png" alt /></p>
<p>Use containers to test and deploy the app</p>
<p>If you want to follow along, go ahead and <a target="_blank" href="https://github.com/postmanlabs/node-doc-kube">clone this example</a>, and follow the README steps to spin up a local version of these APIs.</p>
<ol>
<li>Develop</li>
<li>Test</li>
<li>Deploy</li>
</ol>
<h4 id="heading-develop-the-app">Develop the app</h4>
<p>Let’s start with a Node app using <a target="_blank" href="https://reactjs.org/">React</a> for the frontend and <a target="_blank" href="https://expressjs.com/">Express</a> for the backend. To simplify this demonstration, we won’t be implementing persistent data storage.</p>
<p>The backend boils down to 2 APIs.</p>
<blockquote>
<p>1. Transform the original URL</p>
<p>2. Redirect the new URL back to the original URL</p>
</blockquote>
<p>Even before you begin developing the frontend, you can use Postman as a client to send requests to our local server. It’ll save us time every time we update our payload and inspect the server response.</p>
<p>This is the quintessential use case most people know about when they think of Postman. You probably knew this already. Don’t worry. We’ll learn a few more ways to increase our efficiency with Postman.</p>
<blockquote>
<p><em>💡<strong><strong>POSTMAN TIP</strong></strong>: use a</em> <a target="_blank" href="https://learning.getpostman.com/docs/postman/environments_and_globals/intro_to_environments_and_globals"><em>Postman environment</em></a> <em>to save</em> <strong><em>configuration parameters</em></strong> <em>so you can switch quickly between server setups. For example, I used an environment variable called</em> <code>*url*</code> <em>in my collection and created separate templates for local development and production. Now, selecting the desired Postman environment allows me to toggle between</em> <code>[*http://localhost:5500*](http://localhost:5500)</code> <em>to</em> <code>[*https://cat-kube-stateless-prod-2ea747e90b.kubesail.io*](https://cat-kube-stateless-prod-2ea747e90b.kubesail.io)</code><em>, and other configuration options, more quickly.</em></p>
</blockquote>
<p>Start these endpoints on your local server, and then let’s move over to the Postman app. Find the <a target="_blank" href="https://learning.getpostman.com/docs/postman/launching_postman/newbutton/#templates">Postman template</a> called <strong>catURL</strong> in the Postman app, and then import the example collection and environment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163649209/82ea926f-da1e-40b6-a44d-c27e1923c37c.png" alt /></p>
<p>Import the <strong>catURL</strong> collection and <strong>catURL-local</strong> environment from the Postman <a target="_blank" href="https://learning.getpostman.com/docs/postman/launching_postman/newbutton/#templates">templates</a></p>
<p>We’ll use the <strong>catURL</strong> collection along with the <strong>catURL-local</strong> environment to debug and test our 2 APIs. Read through <a target="_blank" href="https://documenter.getpostman.com/view/1559645/S11HvKXW">the collection documentation</a>, and try it out for yourself.</p>
<h4 id="heading-test-the-app">Test the app</h4>
<p>In this recipe, we won’t cover the basics of <a target="_blank" href="https://medium.com/postman-engineering/acing-your-apis-what-you-need-to-know-for-test-automation-e3fdba3519b9">how to write tests in Postman</a>, or <a target="_blank" href="https://medium.com/postman-engineering/from-manual-to-automated-testing-the-roadblocks-and-the-journey-6333dfacc5ae">how to run these tests in Postman</a>. However, you can see a few tests already written under the Tests tab of the <strong>catURL</strong> collection. Feel free to add your own tests to validate the behavior of our APIs.</p>
<p>Make sure to update your general Postman settings to disallow redirects so that we can inspect our server’s response headers before the redirection. More on how to do that <a target="_blank" href="https://documenter.getpostman.com/view/1559645/S11HvKXW#test-the-redirect">here</a>.</p>
<p>Now that we’ve manually tested our APIs in Postman, or used <a target="_blank" href="https://learning.getpostman.com/docs/postman/collection_runs/starting_a_collection_run">the collection runner</a> as our first step towards automation, let’s use Postman’s open source library <a target="_blank" href="https://github.com/postmanlabs/newman">Newman</a> to run our collection at build time. We have 3 options:</p>
<ul>
<li><strong>Good practice</strong>: test against your APIs running on a local server using static Postman collection and environment <a target="_blank" href="https://learning.getpostman.com/docs/postman/collections/data_formats/#exporting-and-importing-postman-data">JSON files</a> located within the project directory</li>
<li><strong>Better practice</strong>: still testing against your local server, run these tests using the <a target="_blank" href="https://api.getpostman.com/">Postman API</a> to dynamically pull the latest versions of your collection and environment</li>
<li><strong>Even better practice</strong>: still using the Postman API, test against your APIs running on a container hosted by your local server so that your test environment exactly replicates your production environment</li>
</ul>
<p>Let’s try out the last scenario — the even better practice. Add a deployment script that builds and starts our APIs in a local container. If any Postman tests fail, Newman will return an error code to immediately terminate the remainder of the script before any deployment steps are executed.</p>
<p><a target="_blank" href="https://github.com/postmanlabs/node-doc-kube/blob/master/bin/deploy.sh"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163651012/33855a51-4531-495c-af7c-d2335fe9d954.png" alt /></a></p>
<p>If the tests don’t pass, your code doesn’t deploy.</p>
<blockquote>
<p><em>💡<strong><strong>POSTMAN TIP</strong></strong>: use the</em> <a target="_blank" href="https://docs.api.getpostman.com/"><em>Postman API</em></a> <em>to pull the latest version of your collection or environment. Using a static JSON file doesn’t ensure you’re running the latest version of your tests.</em></p>
<p><em>Then, run the collection and environment using</em> <a target="_blank" href="https://github.com/postmanlabs/newman"><em>Newman</em></a> <em>as part of your Continuous Deployment / Continuous Integration (CI/CD) pipeline. The process is the same if you’re using</em> <a target="_blank" href="http://blog.getpostman.com/2015/09/03/how-to-write-powerful-automated-api-tests-with-postman-newman-and-jenkins/"><em>Jenkins</em></a><em>,</em> <a target="_blank" href="http://blog.getpostman.com/2017/08/23/integrate-api-tests-with-postman-newman-and-travis-ci/"><em>Travis CI</em></a><em>, or any similar build system. You will add a build time script telling Newman to run your Postman tests. If the tests don’t pass, your code doesn’t deploy.</em></p>
</blockquote>
<h4 id="heading-deploy-the-app">Deploy the app</h4>
<p>In this example, we will be using Kubernetes to deploy our frontend and backend to separate containers. Consequently, we’ll be describing our deployment steps in separate YAML files. These files will include your container image, resource allocation, the desired number of replicas, and other important information.</p>
<p>In this example, I only designated a single replica of our APIs. However, if I wanted to have 3 replicas, Kubernetes would keep a steady eye on my app instances and replace them if any single one crashed for some reason.</p>
<p><a target="_blank" href="https://github.com/postmanlabs/node-doc-kube/blob/master/deployment-prod.yaml"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163653026/ec2703a8-3453-496a-b69e-828bfc60783b.png" alt /></a></p>
<p>Configuration file for backend deployment</p>
<p>For the deployment, I used a hosted Kubernetes provider called <a target="_blank" href="https://kubesail.com/">Kubesail</a> that creates a free managed namespace. However, the underlying deployment utility <code>[npx deploy-to-kube](https://github.com/kubesail/deploy-to-kube)</code> supports any Kubernetes cluster. By running it inside your app’s directory, this utility will automatically generate a Dockerfile, build and push deployment images, generate Kubernetes configuration files, and trigger a deployment on your Kubernetes cluster.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163654116/4d8bdede-6ced-465f-88ed-5fb21bedc77c.gif" alt /></p>
<p>It’s a litter bit amazing.</p>
<p>Once our app is in production, we can continue testing our production APIs periodically to ensure they’re still functioning properly.</p>
<ul>
<li><strong>Good practice</strong>: on an ad hoc basis, use the Postman <a target="_blank" href="https://learning.getpostman.com/docs/postman/collection_runs/starting_a_collection_run/">collection runner</a> to run the same tests along with a Postman environment that is set up with your production configuration.</li>
<li><strong>Better practice</strong>: set up a <a target="_blank" href="https://learning.getpostman.com/docs/postman/monitors/setting_up_monitor">Postman monitor</a> to schedule your tests on a recurring frequency, or set up a custom cron job using <a target="_blank" href="https://github.com/postmanlabs/newman">Newman</a> to do the same thing.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163656170/618cf579-a7e2-4f24-8a8b-8b7eb279d617.png" alt /></p>
<p>Continue testing your production APIs to ensure they’re functioning properly</p>
<p>In addition to basic monitoring, the Kubernetes community has developed a bunch of <a target="_blank" href="https://github.com/ramitsurana/awesome-kubernetes">open source resources</a> for introspection. Tools like <a target="_blank" href="https://prometheus.io/">Prometheus</a> and <a target="_blank" href="https://istio.io/">Istio</a> provide more advanced features for logging and debugging for your Kubernetes clusters.</p>
<p>In summary, we used a local container to test our Node app, and then Kubernetes to deploy both the frontend and backend on containers in the cloud. Along the way, we used Postman to test our APIs locally, then before releasing our code, and finally once they were in production.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163657452/57c0bcb5-e6d7-4a56-9dc6-c8110d7b6657.png" alt /></p>
<h3 id="heading-a-final-thought-about-containers-and-orchestration">A final thought about containers and orchestration</h3>
<p>In case you missed it, I wanted to highlight the importance of using containers during testing. Container images make it easier to reproduce and run an application that more closely replicates the production environment.</p>
<p>You can use your container images to reliably run your tests against an application in a test environment, like the Postman engineering team does. Containers also allow you to scale up more instances for <a target="_blank" href="https://medium.com/postman-engineering/dont-get-techcrunched-performance-testing-for-your-http-apis-3196e40f6b70">concurrent performance testing</a>. And in the event you’ve released a bug into production, containers make it really easy to quickly roll back an update to a previous version of the application.</p>
<p>There’s a bunch of ways that you can use containers in your development, testing, and deployment processes. The strategy you choose will be determined by your team’s current infrastructure, talent, and goals.</p>
]]></content:encoded></item><item><title><![CDATA[Reverse engineering an API]]></title><description><![CDATA[Gain a deeper understanding of a public or private API, especially for ones that aren’t well-documented
Photo by Lum3n.com from Pexels
When you think about reverse engineering an API, perhaps corporate espionage or something legally or ethically ques...]]></description><link>https://blog.joycejetson.com/reverse-engineering-an-api-403fae885303</link><guid isPermaLink="true">https://blog.joycejetson.com/reverse-engineering-an-api-403fae885303</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Wed, 02 Jan 2019 18:50:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163575455/db87dc18-4794-4dc0-975e-e9bf1024bd11.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-gain-a-deeper-understanding-of-a-public-or-private-api-especially-for-ones-that-arent-well-documented">Gain a deeper understanding of a public or private API, especially for ones that aren’t well-documented</h4>
<p>Photo by Lum3n.com from Pexels</p>
<p>When you think about reverse engineering an API, perhaps corporate espionage or something legally or ethically questionable comes to mind. Hackers gonna hack. However, there’s also legitimate reasons for reverse engineering an API.</p>
<h3 id="heading-why-reverse-engineer-an-api">Why reverse engineer an API</h3>
<p>APIs aren’t always documented. When you’re debugging an API, you can diagnose and resolve issues more quickly when you can visualize all the data that is sent and received. Doing this allows you to gain a deeper understanding of an API.</p>
<blockquote>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Reverse_engineering">Reverse engineering</a>, also called back engineering, is the process by which a man-made object is deconstructed to reveal its designs, architecture, or to extract knowledge from the object.</p>
</blockquote>
<p>Knowing how an API actually behaves enables you to identify flaws and security vulnerabilities <a target="_blank" href="https://medium.freecodecamp.org/reverse-engineering-apis-coffee-meets-bagel-2eda71295613">like accidental data leakage</a>. This also performance tests your API so you can isolate bottlenecks that could benefit from additional caching and compression.</p>
<p>Of course, there’s also selfish reasons for reverse engineering an API.</p>
<h3 id="heading-selfish-reasons-for-reverse-engineering-an-api">Selfish reasons for reverse engineering an API</h3>
<ul>
<li>Accessing a service programmatically <a target="_blank" href="https://blog.tendigi.com/starbucks-should-really-make-their-apis-public-6b64a1c2e923">that doesn’t offer a public API</a></li>
<li>Creating an interface that suits your needs because <a target="_blank" href="https://www.toptal.com/back-end/reverse-engineering-the-private-api-hacking-your-couch">theirs just ain’t cutting it</a></li>
<li>Contribute to a feature that the engineering team is slow 🐌 to deliver</li>
<li>Hack with the hopes that you’ll dazzle the engineering team and they’ll offer you a job</li>
<li><a target="_blank" href="https://news.ycombinator.com/item?id=14758500">Order extra bacon on your pizza</a> when the available app limits you to a sub-optimal amount of bacon</li>
<li>Cheat at games — there’s <a target="_blank" href="https://www.reddit.com/r/REGames/">an entire subreddit dedicated to this</a> among <a target="_blank" href="https://www.reddit.com/r/ReverseEngineering/">others</a></li>
<li>Scale up your catfishing side business by <a target="_blank" href="https://gist.github.com/rtt/10403467">unleashing chatbots on popular dating apps</a></li>
</ul>
<p>When you’re reverse engineering a private API that isn’t yours, make sure to check the terms of service. Some developers wear their cease and desist orders like a badge of honor, but you might get sued or banned from their services.</p>
<h3 id="heading-what-is-an-https-proxy">What is an HTTP/S proxy?</h3>
<p>A <a target="_blank" href="https://en.wikipedia.org/wiki/Proxy_server">web proxy server</a> is like a middleman that sits between your client application and the server. The web proxy is a substitute server that can intercept HTTP traffic between a web browser and the website’s real server.</p>
<blockquote>
<p>It’s all there! Black and white, clear as crystal!</p>
<p>— Willy Wonka, The Chocolate Factory</p>
</blockquote>
<h4 id="heading-reasons-to-use-a-web-proxy">Reasons to use a web proxy</h4>
<ul>
<li>Monitor and eavesdrop on HTTP network traffic by recording and displaying all traffic between your client and server</li>
<li>Hide your public IP address while browsing websites and to access blocked content</li>
<li>Filter or redirect requests to limit access to content or optimize systems performance</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163564759/f89b4462-628e-41d5-97ec-efd48ee81275.png" alt /></p>
<p>Postman is a proxy that captures the HTTP/S request</p>
<h4 id="heading-free-web-proxy-tools">Free web proxy tools</h4>
<ul>
<li><a target="_blank" href="https://www.getpostman.com/"><strong>Postman</strong></a> is a free tool with <a target="_blank" href="http://blog.getpostman.com/2017/09/29/client-proxy-settings-in-postman/">a bunch of different proxies</a>, including <a target="_blank" href="https://learning.getpostman.com/docs/postman/sending_api_requests/capturing_http_requests">a built-in proxy</a> to capture HTTP requests in the native apps for Mac, Windows, or Linux</li>
<li><a target="_blank" href="https://mitmproxy.org/"><strong>Mitproxy</strong></a> is an open-source proxy with a command line interface, web interface, and Python API</li>
<li><a target="_blank" href="https://www.telerik.com/fiddler"><strong>Fiddler</strong></a> is a free web debugging proxy with support for a wide variety of browsers, systems, and platforms</li>
<li><a target="_blank" href="https://portswigger.net/burp/documentation/desktop/tools/proxy"><strong>Burp</strong></a> has a free community edition of a web proxy server that lets you view and modify requests and responses</li>
</ul>
<p>The remainder of this article will focus on how you can use Postman to intercept the traffic between your client and server.</p>
<h3 id="heading-a-postman-recipe-for-reverse-engineering-an-api">A Postman recipe for reverse engineering an API</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163565765/dfcca52b-721f-474d-aeaa-c34359672863.png" alt /></p>
<p>It’s time to get our hands dirty, sniffing and inspecting to our heart’s content. First, we’ll import a single request into the Postman app. Then we’ll use Postman as a proxy to capture a stream of HTTP/S requests from a variety of clients like a desktop web browser, a mobile device, and an Electron app.</p>
<iframe src="https://www.youtube.com/embed/2VKVPB5USgU?feature=oembed" width="700" height="393"></iframe>

<p>To follow along in Postman, click the orange <strong>+New</strong> button in the top left of the Postman app. Under the <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/launching_postman/newbutton#templates">Templates</a> tab, search for <strong>Reverse engineering an API</strong>, and import the sample collection into your instance of the Postman app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163567201/a496fa9c-cfcb-472d-aa64-a1dc267071d0.png" alt /></p>
<p>Import this collection and follow along with these examples</p>
<p>Read through the descriptions in the Postman app for details, or check out the <a target="_blank" href="https://documenter.getpostman.com/view/1559645/Rzn9uMQk">web documentation</a> for step-by-step instructions and screenshots.</p>
<p><a target="_blank" href="https://documenter.getpostman.com/view/1559645/Rzn9uMQk"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163569001/e3d9b398-00f2-4f24-a757-63f8bb21ed95.png" alt /></a></p>
<p>Examples of inspecting HTTP requests</p>
<h4 id="heading-import-a-single-request"><strong>Import a single request</strong></h4>
<p>If you want to inspect a request in Postman, here’s a super simple way to import it as <a target="_blank" href="https://curl.haxx.se/docs/manpage.html">cURL</a> from your browser. In this example, we will use <a target="_blank" href="https://developers.google.com/web/tools/chrome-devtools/">Chrome DevTools</a> to inspect and select a request. You can follow similar steps when using other web browsers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163570490/febdfc88-664b-4727-8815-07939cc3add4.png" alt /></p>
<p>Copy the cURL request from Chrome DevTools</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163572188/de837ab0-47e1-4f16-9b8a-69093fa6f531.png" alt /></p>
<p>Paste the cURL request as raw text in Postman</p>
<h4 id="heading-inspect-a-stream-of-requests"><strong>Inspect a stream of requests</strong></h4>
<p>If you want to inspect a stream of requests from your client, you can use the Postman built-in proxy to capture these requests. Postman <a target="_blank" href="http://blog.getpostman.com/2017/09/29/client-proxy-settings-in-postman/">has a bunch of different proxies</a>. In this scenario, we’ll rely on <a target="_blank" href="https://learning.getpostman.com/docs/postman/sending_api_requests/capturing_http_requests">the Postman built-in proxy</a> in the native apps for Mac, Windows, or Linux. You can capture requests sent from your client, like a desktop web browser, mobile device, or an Electron app.</p>
<p>You can pipe this stream of requests to your <a target="_blank" href="https://learning.getpostman.com/docs/postman/sending_api_requests/history">Postman History</a> and save them to a <a target="_blank" href="https://learning.getpostman.com/docs/postman/collections/intro_to_collections">Postman Collection</a>. Then you can revisit these requests for inspection at a later date, or <a target="_blank" href="https://learning.getpostman.com/docs/postman/collections/sharing_collections">share them with a teammate</a>.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/1*a61LpBuYq-6S9b0_24d1fw.gif" alt /></p>
<p>Postman as a proxy to capture HTTP/S requests from web browser</p>
<p>Currently, the Postman built-in proxy in the native apps only captures HTTP request traffic. Fortunately, most websites have HTTP Strict Transport Security (HSTS) enabled for an additional layer of security. Unfortunately, this means the Postman built-in proxy cannot capture requests sent over HTTPS if the website has HSTS enabled.</p>
<blockquote>
<p><em>Note: As of the publication of this article, the Postman built-in proxy captures HTTP traffic, but not traffic from HTTPS websites with HSTS enabled.</em> <a target="_blank" href="https://trello.com/c/Ewv9DGhh/79-interceptor-integration"><em>Interceptor integration</em></a> <em>and</em> <a target="_blank" href="https://trello.com/c/S4E7egzO/78-https-proxy"><em>HTTPS proxy</em></a> <em>is slated for development in the</em> <a target="_blank" href="https://trello.com/b/4N7PnHAz/postman-roadmap-for-developers"><em>Postman roadmap for developers</em></a><em>.</em></p>
</blockquote>
<h3 id="heading-a-final-thought-about-reverse-engineering-an-api">A final thought about reverse engineering an API</h3>
<p>This recipe is just the tip of the iceberg of how you can sniff and inspect HTTP traffic to start understanding what’s going on under the hood. For tougher nuts to crack, you may have to dig into <a target="_blank" href="https://en.wikipedia.org/wiki/Transport_Layer_Security#Certificate_pinning">SSL certificate pinning</a>, spoof particular client attributes, or learn how to sign and authenticate more complex requests.</p>
<p>Although these tools and methods are powerful and can be used for selfish reasons, they can and should be used for good.</p>
<blockquote>
<p>Be excellent to each other.</p>
<p>— <a target="_blank" href="https://www.imdb.com/title/tt0096928/">Bill S. Preston, Esq.</a></p>
</blockquote>
<p>Tools like Postman can enhance the visibility of client requests, making them easier to replicate and tweak, so you can diagnose and resolve issues faster. Ultimately, this will help you gain a deeper understanding of a public or private API, especially for APIs that aren’t well-documented.</p>
]]></content:encoded></item><item><title><![CDATA[Acing your APIs — what you need to know for test automation]]></title><description><![CDATA[We’ll break it down, with examples, so you can test early and often.
Photo by Denisse Leon on Unsplash

As Quality Engineers, we set the quality standard on our products and hold our development teams accountable.
Writing tests for our microservices ...]]></description><link>https://blog.joycejetson.com/acing-your-apis-what-you-need-to-know-for-test-automation-e3fdba3519b9</link><guid isPermaLink="true">https://blog.joycejetson.com/acing-your-apis-what-you-need-to-know-for-test-automation-e3fdba3519b9</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Mon, 26 Nov 2018 22:59:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163590428/877364dd-2dcc-4cdf-8275-69dd1d04610a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-well-break-it-down-with-examples-so-you-can-test-early-and-often">We’ll break it down, with examples, so you can test early and often.</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/photos/0uvej5ZGoJ4?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Denisse Leon</a> on <a target="_blank" href="https://unsplash.com/search/photos/push-button?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<blockquote>
<p>As Quality Engineers, we set the quality standard on our products and hold our development teams accountable.</p>
<p>Writing tests for our microservices keeps our products running smoothly. We would not be able to release with the high level of confidence we currently have without these tests in place to ensure that our services are running and integrated as expected.</p>
<p><a target="_blank" href="https://twitter.com/stevie_joe">Trent McCann</a>, Lead Quality Engineer at Cvent</p>
<p><strong><em>Part 1:</em></strong> <a class="post-section-overview" href="#4e18"><strong><em>API tests</em></strong></a></p>
<p><strong><em>Part 2:</em></strong> <a class="post-section-overview" href="#46b4"><strong><em>integration tests</em></strong></a></p>
<p><strong><em>Part 3:</em></strong> <a class="post-section-overview" href="#e14e"><strong><em>other stuff that people talk about when writing tests</em></strong></a></p>
<p><strong><em>Part 4: a recipe for</em></strong> <a class="post-section-overview" href="#f038"><strong><em>writing tests in Postman</em></strong></a></p>
</blockquote>
<p>As our applications and services grow, it becomes more and more time consuming to execute regression testing on the existing codebase every time new functionality is introduced.</p>
<p>⚠️ The testing community at times conflates common testing terminology, or refers to concepts interchangeably. Regardless of how your team decides to define particular terms, first understand the purpose for why you’re running each type of test.</p>
<h3 id="heading-part-1-api-tests">Part 1: API tests</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163577570/10edbf6a-2244-430f-8fa9-06edfac34fcc.png" alt /></p>
<p>API test for a single API request</p>
<p>When some people talk about “units tests” for an API, they are likely referring to a test of a single HTTP API request. Similar to how software unit tests are written to assess the smallest unit of functionality, you can think of an API test like a unit test.</p>
<p>With this type of testing, you may or may not have access to the underlying code. However, you can validate that an API behaves as expected from the user’s perspective.</p>
<blockquote>
<p>Testing a publicly facing API through your UI is not enough!</p>
<p><a target="_blank" href="https://twitter.com/ambertests">Amber Race</a>, Senior SDET at Big Fish Games</p>
</blockquote>
<h4 id="heading-examples-of-api-tests">Examples of API tests</h4>
<ul>
<li><strong>Status</strong>: the correct response code was returned</li>
<li><strong>Performance</strong>: the response was returned within a certain time</li>
<li><strong>Syntax</strong>: the content type of the returned content was as expected</li>
<li><strong>Syntax</strong>: the server accepts correct input</li>
<li><strong>Error handling</strong>: the server rejects incorrect input</li>
<li><strong>Error handling</strong>: excluding a required parameter results in an error</li>
<li><strong>Error handling</strong>: submitting incorrect data types results in an error</li>
<li><strong>Error detection</strong>: negative testing to identify exceptions and race conditions</li>
<li><strong>Schema</strong>: the response payload conforms to an expected structure or format</li>
<li><strong>Functional</strong>: the server returns a predictable value based on the input condition</li>
<li><strong>Functional</strong>: the request predictably modifies a resource</li>
<li><strong>Security checks</strong>: SQL injections do not result in data leakage</li>
</ul>
<blockquote>
<p>Tests are the documentation for your code. They should document the desired functionality of the software, and also address edge cases and error scenarios.</p>
<p><a target="_blank" href="https://medium.com/u/153a0cb9bc2c">Valentin Despa</a>, Software Developer at AOE</p>
</blockquote>
<h3 id="heading-part-2-integration-tests">Part 2: Integration tests</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163578301/50621b29-e411-4d1e-a6ed-d08625fe331b.png" alt /></p>
<p>Integration tests are built across multiple units to verify that components are working together as expected. This can encompass two or more individual components, or endpoints. Integration tests can include internal services, third-party services, and other external dependencies.</p>
<blockquote>
<p>We write tests because we want them to fail someday, to warn us that something is our application has changed or behaves differently. While this seems rather obvious, tests that never fail are quite common.</p>
<p>It can be that the test run report is not properly understood by the CI/CD tool and marked as passed, or that assertions themselves are not executed, are faulty, or too permissive. So when you write a test, make sure it can fail.</p>
<p><a target="_blank" href="https://medium.com/u/153a0cb9bc2c">Valentin Despa</a>, Software Developer at AOE</p>
</blockquote>
<h4 id="heading-setup-and-teardown">Setup and teardown</h4>
<p>Sometimes your test cases require some initial groundwork to prepare your test environment. Perhaps you’re generating new users, creating authentication tokens, or simply initializing variables.</p>
<p>After your tests run, you may need to clean up the test conditions, so that you’re not littering new users, records, and other side effects throughout your test environment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163579439/f815efcb-0990-4117-8970-d7aea6355ccd.png" alt /></p>
<p>Automate the setup and teardown of your test conditions</p>
<p>Automating the setup and teardown steps allows you to quickly re-create your test conditions in a consistent way so that you can repeat your tests quickly and easily. Creating repeatable tests allows you to more efficiently tweak other variables, isolate the system under test, and observe the results in a scalable manner.</p>
<h4 id="heading-scenario-tests"><strong>Scenario tests</strong></h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163580471/ad92c7cd-f857-4c4b-a639-395d28cf273c.png" alt /></p>
<p>Make sure your application is robust and stable across a spectrum of scenarios. Testing both expected and unexpected use cases is critical to a good user experience. Visualize the user’s workflow and think about how they interact with the application.</p>
<p>Write and run your API tests in a sequence that mirrors a typical user workflow, commonly identified in the user story business requirements. Testers should also identify test cases for atypical user behaviors.</p>
<blockquote>
<p>Generally, I take a black box approach — follow the happy-path to ensure it meets the defined functional specs and start going off that path. Try negative and edge case scenarios to see how the application will respond.</p>
<p>A good rule of thumb to keep in mind is: if a user can do it, they will at some point actually do it, no matter how obscure it may seem.</p>
<p><a target="_blank" href="https://twitter.com/stevie_joe">Trent McCann</a>, Lead Quality Engineer at Cvent</p>
</blockquote>
<h3 id="heading-part-3-other-stuff-that-people-talk-about-when-writing-tests"><strong>Part 3: Other stuff that people talk about when writing tests</strong></h3>
<h4 id="heading-performance-tests"><strong>Performance tests</strong></h4>
<p>You can run these test cases to <a target="_blank" href="https://medium.com/postman-engineering/dont-get-techcrunched-performance-testing-for-your-http-apis-3196e40f6b70">performance test your APIs</a>. Increasing concurrent load at controlled increments allows you to identify bottlenecks and validate service-level agreements (SLAs) for internal APIs or public services.</p>
<p><a target="_blank" href="https://medium.com/postman-engineering/dont-get-techcrunched-performance-testing-for-your-http-apis-3196e40f6b70"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163581578/e313f6b7-f89a-4cc3-bd3b-1d9a1a043a3e.png" alt /></a></p>
<p>Exploratory load testing to gain a deeper understanding of your systems</p>
<h4 id="heading-mocking-dependencies"><strong>Mocking dependencies</strong></h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163582638/23a22ac6-3477-42e4-af88-64304e23230e.png" alt /></p>
<p>If your test case involves shared or production resources, some teams will use mock services. Mocking the actual service allows you to rely on a predictable response so you can isolate the component under test when debugging issues.</p>
<p>You can also use mocks to simulate error conditions or rare instances that might be difficult or problematic to set up in a production environment.</p>
<h4 id="heading-contract-testing"><strong>Contract testing</strong></h4>
<p>As organizations continue to transition to a microservices architecture, teams become increasingly dependent on internal services. An <a target="_blank" href="https://medium.com/postman-engineering/api-first-software-development-for-modern-organizations-fdbfba9a66d3">API-first approach</a> assumes the design and development of an application programming interface (API) comes before the implementation.</p>
<p>Consumer-Driven Contract Testing (CDC Testing) ensures that your service doesn’t break when a service that you rely on is updated. This type of contract testing requires the consumer of the service to define the format of the expected responses, including any validation tests. The provider must pass these tests before releasing any updates to the service.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163584080/65e77bc1-2964-4ba0-8ec4-401808ce4f21.png" alt /></p>
<p>Consumer-Driven Contract Testing ensures that your service doesn’t break when a service that you rely on is updated</p>
<blockquote>
<p>We take an API-First Design approach to ensure that our API specifications are defined and approved before cutting any code. This provides us with a unified design to build upon, and allows our developers and QE to simultaneously develop our application and tests, thereby avoiding the waiting period before the handoff from dev to QE.</p>
<p>We leverage the Postman mock service to ensure that our tests are developed and ready for use when handoff takes place. Then it is simply a matter of swapping variables and our QEs are off to the races.</p>
<p><a target="_blank" href="https://twitter.com/stevie_joe">Trent McCann</a>, Lead Quality Engineer at Cvent</p>
</blockquote>
<h4 id="heading-regression-testing">Regression testing</h4>
<p>Run initial smoke tests to verify that your build is stable enough to proceed with more rigorous, regression testing.</p>
<p>Regression tests can be either unit tests, integration tests, or both. Run your entire test suite after a patch, upgrade, or bug fix. Even if you’re working on a part of the code that you don’t believe impacts a previous patch, you should run your regression tests to ensure that new functionality doesn’t break something that was previously working.</p>
<blockquote>
<p><em>Tests give you confidence when adding new features and changing your code. They should not be a burden to write and maintain but a tool that can empower you as a development team to build better software.</em></p>
<p><a target="_blank" href="https://medium.com/u/153a0cb9bc2c">Valentin Despa</a>, Software Developer at AOE</p>
</blockquote>
<h3 id="heading-part-4-a-recipe-for-writing-postman-tests">Part 4: a recipe for writing Postman tests</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163585048/5ce19fc4-eb25-4032-956f-05468ddf2029.png" alt /></p>
<p>Now it’s time to get tactical! Let’s check out some examples.</p>
<iframe src="https://www.youtube.com/embed/pi9MxX0HSHU?feature=oembed" width="700" height="393"></iframe>

<p>To follow along with these, and other, examples, click the orange <strong>+New</strong> button in the top left of the Postman app. Under the <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/launching_postman/newbutton#templates">Templates</a> tab, search for <strong><em>Intro to writing tests — with examples</em></strong> and import the sample collection and environment into your instance of the Postman app.</p>
<p><a target="_blank" href="https://www.getpostman.com/docs/v6/postman/launching_postman/newbutton#templates"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163586550/34902ef4-7491-45a8-8c52-3bb726a5be0e.png" alt /></a></p>
<p>Import this collection and follow along with these examples</p>
<p>Read through the descriptions in the Postman app for details, or check out the <a target="_blank" href="https://documenter.getpostman.com/view/1559645/RzZFCGFR">web documentation</a> for step-by-step instructions and screenshots.</p>
<ul>
<li>Basic test syntax</li>
<li>Considerations for using variables</li>
<li>Test automation in Postman</li>
<li>And examples aplenty!</li>
</ul>
<p><a target="_blank" href="https://documenter.getpostman.com/view/1559645/RzZFCGFR"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163588263/beb55c39-94ef-4b1a-b696-c07fcc178e35.png" alt /></a></p>
<p>Examples of writing tests in Postman</p>
<h3 id="heading-a-final-thought-about-writing-tests">A final thought about writing tests</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163589369/5782ba99-4ed7-4382-9e07-2d723ad2c86b.png" alt /></p>
<p>Once you’ve written your tests, the world is your oyster. Do more with your time, and continue your <a target="_blank" href="https://medium.com/postman-engineering/from-manual-to-automated-testing-the-roadblocks-and-the-journey-6333dfacc5ae">journey from manual to automated testing</a>.</p>
<p>Couple your tests with a CI/CD pipeline to ensure no failure conditions are released into your server environments. Continue running your tests in production at regular intervals to monitor your endpoints and make sure they’re behaving as expected. Run exploratory or regular tests <a target="_blank" href="https://medium.com/postman-engineering/dont-get-techcrunched-performance-testing-for-your-http-apis-3196e40f6b70">to assess the performance of your APIs</a> with real-world loads.</p>
<p>Automating simple API tests and more complex integration tests allows you to catch issues earlier in the development cycle when the cost of debugging is the lowest. Running these tests in an easily repeatable manner allows you scale your development with confidence as the code base grows.</p>
<blockquote>
<p><strong>If you have examples of tests that you use, you too can share them with the rest of the Postman community. Publish your examples in a</strong> <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/launching_postman/newbutton#templates"><strong>template</strong></a><strong>.</strong></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[API-first software development for modern organizations]]></title><description><![CDATA[Photo by Iker Urteaga on Unsplash
As more organizations move to the cloud, they implement processes to deal with new microservices architectures, containerization, and continuous delivery. Whether they’re adopting cloud services or transitioning to a...]]></description><link>https://blog.joycejetson.com/api-first-software-development-for-modern-organizations-fdbfba9a66d3</link><guid isPermaLink="true">https://blog.joycejetson.com/api-first-software-development-for-modern-organizations-fdbfba9a66d3</guid><dc:creator><![CDATA[Joyce Lin]]></dc:creator><pubDate>Wed, 01 Aug 2018 15:37:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163746217/64a92c27-bf3b-4e4a-9dea-38b12a3afdd1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Photo by <a target="_blank" href="https://unsplash.com/photos/TL5Vy1IM-uA?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Iker Urteaga</a> on <a target="_blank" href="https://unsplash.com/search/photos/blocks?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
<p>As more organizations move to the cloud, they implement processes to deal with new microservices architectures, containerization, and continuous delivery. Whether they’re adopting cloud services or transitioning to a cloud infrastructure, an API-first approach can help you manage the complexity of working in the cloud.</p>
<p>The traditional code-first approach to app development sometimes results in delays, rework, or a disjointed frankenstein-esque experience for the developer, especially in this cloud-driven landscape.</p>
<p>An API-first approach assumes the design and development of an application programming interface (API) comes before the implementation. Your team begins by creating an interface for their application. After the API has been developed, the team will rely on this interface to build the rest of the application.</p>
<p>By introducing new features as an independent service accessed by API, the rest of the app can be stitched together, along with any other future apps.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163712708/83ae4022-d924-4006-9fae-c9a8dd89d15d.png" alt /></p>
<p>Design and build the API first, before building out the rest of the app.</p>
<p>In a world where speed-to-market holds a premium, why would you spend extra time to focus on the API first?</p>
<h4 id="heading-when-the-code-comes-first"><strong>When the code comes first</strong></h4>
<p>With a code-first approach, you might start with your integrated development environment (IDE) to type out a few lines of code. Somewhere in the back of your mind, you know that eventually an interface will be created to deliver this service. However, your main focus is on what you call “core functionality” not the “interface”.</p>
<p>When it comes time to implement the interface (the API), the core service is mostly done so it drives the implementation of the API. In some cases, the API might need to be shoehorned into place to accommodate the behavior of the core service. For example, you can’t retrieve information the way you want to due to the way access is granted or the way a database is structured.</p>
<p>To the user who will ultimately use this API, it can feel tacked on, like an afterthought to the core service.</p>
<p>Besides a disjointed developer experience, this approach leaves your team vulnerable to bottlenecks.</p>
<p>Once a version of the API is completed, developers will commit the code to a shared repository and release it to a server environment. Only then can your dependent teams begin. At this point, there’s a host of other tools that you might use to consume the API, to develop test cases, write documentation, and provide feedback.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163713931/25d8ff6f-c952-4e84-ba7e-78fca6269c80.png" alt /></p>
<p>Testing and documentation wait for development before getting started.</p>
<p>This is a synchronous flow that’s frequently encountered in the traditional waterfall software development process. Delays at any point in time will hold up dependent teams and push back the overall delivery of the product.</p>
<p>Feedback is gathered later in the development process, so changes are more costly since valuable time and resources have already been invested into this earlier version of the product.</p>
<h4 id="heading-when-the-api-comes-first"><strong>When the API comes first</strong></h4>
<p>With an API-first approach, instead of starting with code, you could start with design, planning, mocks, and tests.</p>
<p>As you might already suspect, this process is aligned with the popular agile software development principle of iterating rapidly. This allows the team and any other stakeholders to weigh in on the proposed direction and functionality, early and often.</p>
<p>Gathering feedback at this early stage allows you to make changes more easily before a lot of time and effort is sunk into the project. Using mocks or an API development environment makes the current state of the project more accessible to both technical and non-technical team members.</p>
<p>By also separating the design of the API from its implementation, the architect is constrained only by the data model and business logic. Your API can now evolve unfettered by any existing user interface or legacy engineering frameworks.</p>
<p>Once the direction has been solidified, the design then serves as the contract that all teams can begin working towards in parallel, and only then does coding officially begin.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163715142/1b0483ba-7c91-4e31-b56c-ecaeca1026d1.png" alt /></p>
<p>Testing, documentation, and development can begin independently of other teams’ progress.</p>
<p>To drill down a little bit deeper on the API-first approach, let’s talk about API-first development and API-first design.</p>
<h4 id="heading-api-first-development"><strong>API-first development</strong></h4>
<p>This concept refers to developing the actual API first and foremost. When you’re developing new functionality, the functionality should first be exposed as an API in your organization. The developers responsible for the rest of the application will be the first consumers of this API. This ensures the quality, predictability, and stability to withstand web clients, mobile users, and other developer consumers. Other projects requiring this functionality can now independently consume the functionality via this API.</p>
<h4 id="heading-api-first-design"><strong>API-first design</strong></h4>
<p>This approach takes it a step further and requires planning the intended API’s functionality before building the API itself. What functionality will the API have? What data will it expose? What will the developer experience be like? How will it scale? How will we add new functionality in the future?</p>
<p>When people talk about API-first, sometimes they’re only referring to API-first development and sometimes they’re including API-first design as well. For the remainder of this article, API first will encompass both API-first development and API-first design.</p>
<p><strong>Word of Caution:</strong> focusing on the design first does not mean ruminating endlessly on all the what-if scenarios. A good design should have the flexibility to adapt to changing circumstances and accommodate new insights. As some teams can attest, mandating that specifications drive development can backfire.</p>
<p>Most developers still prefer documenting existing code as specifications, rather than writing the specification first. An interface is intended to be an abstraction for interacting with a system, while the implementation is the way the system does its work.</p>
<p><a target="_blank" href="http://www.hyrumslaw.com/">Hyrum Wright</a> observed that it’s problematic to fully separate an interface from its implementation, especially in large scale systems.</p>
<p>Hyrum’s Law differentiates between an explicitly documented interface that is planned for and an implicit interface that will become evident only with usage. Consumers will come to rely on behavior observed from both the explicit and implicit interface, at which point any changes to the implementation will violate their expectations.</p>
<blockquote>
<p><a target="_blank" href="http://www.hyrumslaw.com/"><strong><em>With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.</em></strong></a></p>
<p><strong><em>- Hyrum’s Law</em></strong></p>
</blockquote>
<p><a target="_blank" href="https://xkcd.com/1172/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163716150/c0ea7a59-93d6-4540-be7e-e64fa6ea9cb4.png" alt /></a></p>
<p>Relevant XKCD</p>
<h3 id="heading-why-api-first">Why API first?</h3>
<p>Clearly, pausing to flesh out the API delays valuable building time. Is it worth it? While not all organizations have the liberty to fully plan out their work, there are several benefits for choosing this approach that potentially outweigh delaying your time-to-market.</p>
<ul>
<li><strong>Earlier validation:</strong> getting early feedback on the design allows the team to pivot or adapt to any new inputs while the cost of change is still relatively low. This reduces overall cost over the lifetime of the project.</li>
<li><strong>Clear abstraction layer</strong>: showing only the necessary details to the intended user hides internal complexity. This allows others to ramp up more quickly when implementing the new service.</li>
<li><strong>Decoupling dependencies</strong>: by adhering to a contract between internal services, dependencies are decoupled so that work can progress independent of other teams’ work. Working in parallel minimizes the project’s overall development time.</li>
<li><strong>Faster growth</strong>: building out the API design at an early stage takes future functionality into account, laying the groundwork for expansion, and accommodates the ability to quickly scale to other apps, devices, and platforms.</li>
<li><strong>Freedom from constraints</strong>: focusing first on the API instead of the code and implementation frees the design from legacy constraints.</li>
</ul>
<h3 id="heading-what-does-api-first-look-like-in-modern-organizations">What does API first look like in modern organizations?</h3>
<p>Some organizations launched as API-only businesses, like <a target="_blank" href="https://www.twilio.com/">Twilio</a> or <a target="_blank" href="https://www.algolia.com/">Algolia</a>, who are both known for offering their services most importantly as an API. Twilio virtualized traditional telecommunications infrastructure allowing developers to replicate any communications experience using APIs. The business recently announced Twilio Build, a partner program designed with an API-first approach.</p>
<blockquote>
<p><a target="_blank" href="https://www.twilio.com/press/releases/release_twilio%20_launches_build"><strong><em>Twilio’s unique API-first cloud platform is tailor-made to support an ecosystem of partners that are differentiated by the innovations they deliver for their customers.</em></strong></a></p>
<p><strong>- Ron Huddleston, Twilio</strong></p>
</blockquote>
<p>As some organizations adopt agile software development practices, an API-first approach allows other companies to optimize their total development time. For example, Etsy <a target="_blank" href="https://codeascraft.com/2016/09/06/api-first-transformation-at-etsy-concurrency/">switched to an API-first approach</a> after facing the common challenge of implementing their logic twice.</p>
<blockquote>
<p><a target="_blank" href="https://codeascraft.com/2016/09/06/api-first-transformation-at-etsy-concurrency/"><strong><em>All of the code that was built for the website then had to be rebuilt in our API to be used by our iOS and Android apps.</em></strong></a></p>
<p><strong>- Stephanie Schirmer, Etsy</strong></p>
</blockquote>
<p>Besides increasing extensibility for new devices and features, Etsy’s upgrade optimized their platform’s performance by enabling concurrent API calls previously limited by their PHP code base.</p>
<p>Another example of an API-first company is Netflix. Accounting for a large percent of total internet traffic, Netflix also re-configured their API architecture to allow concurrency. In the process, they distributed their API development so that each client application team was capable of implementing and operating their own endpoints.</p>
<blockquote>
<p><a target="_blank" href="https://medium.com/netflix-techblog/optimizing-the-netflix-api-5c9ac715cf19"><strong><em>A single team should not become a bottleneck nor need to have expertise on every client application to create optimized endpoints. Rapid innovation through fast, decoupled development cycles across a wide variety of device types and distributed ownership and expertise across teams should be enabled.</em></strong></a></p>
<p><strong>- Ben Christensen, Netflix</strong></p>
</blockquote>
<p>In this context, many teams treat APIs as a separate product or platform. Today, many engineering teams have a completely separate group for building new API functionality and maintaining scalability of their APIs.</p>
<p>Dedicating resources for designing and implementing the APIs demonstrates the value these organizations have for an API-first approach. This is in stark contrast with the code-first mentality which might propose building the application and then retrofitting an API as an afterthought.</p>
<p>Ok, it’s time to try it out.</p>
<p>I love pushups 💪 — who doesn’t? Let’s build a web app that reminds us to get some exercise. I can picture it in my mind, kind of.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163717185/461c6d5a-b5ca-4b91-a95b-05fe81970bd4.gif" alt /></p>
<p>Gif by <a target="_blank" href="http://clterryart.tumblr.com/post/147392799827">CLTerry</a></p>
<p>At this point, wecould probably just pull up our integrated development environment (IDE) and plunge right in and get started coding.</p>
<p>Instead, let’s walk through an API-first approach, and learn about one way to build a new product or feature in Postman.</p>
<ol>
<li>Design the new feature</li>
<li>Get feedback about the new feature</li>
<li>Build the feature</li>
<li>Deploy the changes</li>
</ol>
<h3 id="heading-1-design-the-api">#1 Design the API</h3>
<p>Let’s open the <a target="_blank" href="https://www.getpostman.com/apps">Postman app</a>, and log in.</p>
<p>Create a <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/collections/intro_to_collections">Postman collection</a>. This will be used to group our requests, and will come in handy when we start testing our API. Let’s name this collection after our project called Pushup.</p>
<p>Create a <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/environments_and_globals/intro_to_environments_and_globals">Postman environment</a> also called Pushup to store variables so that we can update a value in a single place and propagate the changes easily. Store our base url <code>[https://api.pushup.com/v1](https://api.pushup.com/v1)</code> under a key called <code>base_url</code>. When we’re ready for development, we can swap it out to <code>[https://localhost:3000/v1](https://localhost:3000/v1)</code>, for example. In addition to storing useful values for configuration, this would be a good spot to keep any sensitive and confidential information like API keys and tokens.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163718779/f73399f6-6857-48bf-9605-1a937af577cf.png" alt /></p>
<p><em>Store config values or confidential information in a Postman environment.</em></p>
<p>Let’s add a Postman <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/collections/managing_collections#adding-folders">folder</a> to this collection. Similar to a collection, we can further group our requests in a meaningful way. You can nest these folders, and also dedicate variables and scripts to use within the folder scope. Let’s call our first folder Pushups after an endpoint we plan to make <code>/pushups</code> and follow a predictable REST architectural style.</p>
<ol>
<li>GET request to retrieve a list of all types of pushups (<code>/pushups</code>)</li>
<li>GET request to retrieve an existing pushup (<code>/pushups/:pushupId</code>)</li>
<li>POST request to create a new type of pushup (<code>/pushups</code>)</li>
<li>PUT request to update an existing pushup (<code>/pushups/:pushupId</code>)</li>
<li>DELETE request to delete an existing pushup (<code>/pushups/:pushupId</code>)</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163720550/02d188f1-68d3-4ddd-871d-ec67bfd11d43.png" alt /></p>
<p>Group requests in a collection and sub-folders.</p>
<p>Add a second Postman folder called “Get Started”. For developers new to this API, this folder can include a few requests walking through an example workflow. This is helpful for other team members to visualize what is happening, and also give you a head start on testing this API. Let’s duplicate some of our previous requests and drag them over to our new folder.</p>
<ol>
<li>POST request to create a new type of pushup (<code>/pushups</code>)</li>
<li>PUT request to update an existing pushup (<code>/pushups/:pushupId</code>)</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163722272/5b868436-42d4-4f42-a381-e73662ea3466.png" alt /></p>
<p>Create a separate folder to help others visualize an example workflow.</p>
<p>For every request, <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/collections/examples">add an example</a> illustrating what you’d like the response to look like. For example, we can add headers, HTTP status code, and a response body. These examples will come in handy later for <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/mock_servers/intro_to_mock_servers">mocking</a> and <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/api_documentation/intro_to_api_documentation">documentation</a>, before we have a working endpoint.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163724158/b393ff2c-b801-4085-ae9f-ecfeac546403.png" alt /></p>
<p>Add examples to demonstrate a response.</p>
<h3 id="heading-2-get-feedback-on-the-api-design">#2 Get feedback on the API design</h3>
<p>The design is just about perfect! We’re actually ready to start developing the API, but it can’t hurt to ask our teammates what they think. Changing the API now will be much less painful than waiting until later once we’ve coded the whole dang thing.</p>
<p><strong>Collaborate in workspaces:</strong> Go ahead and share the Pushup collection from your personal <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/workspaces/intro_to_workspaces">workspace</a> to a team workspace so they can look it over. If anybody wants to make any changes, you can give them edit permissions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163725903/1b316746-024c-4a21-9056-806d20356ae6.png" alt /></p>
<p>Allow others read and write permissions for collaboration.</p>
<p><strong>Activity feed:</strong> an <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/workspaces/activity_feed_and_restoring_collections">activity feed</a> displays updates to the collection, so that you can keep track of who is making changes, and what kind of changes.</p>
<p><strong>Revert changes:</strong> if anyone makes any changes that we don’t like, <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/workspaces/activity_feed_and_restoring_collections#restoring-collections">restore the collection</a> and roll it back to the point right after their change was made.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163728073/a2333db8-3bea-4d8e-bd2e-54a126c567c8.png" alt /></p>
<p>Review the collection’s activities and restore the collection to a previous point in time.</p>
<p><strong>Mock the API:</strong> your boss loves pushups too, but he’s not part of your Postman team. We can <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/mock_servers/intro_to_mock_servers">mock up the responses</a> using the <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/collections/examples">examples</a> that we previously saved for each request.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163729881/5fa45419-580e-43f7-a71c-733b191bb3f6.png" alt /></p>
<p>Mock the API to visualize intended behavior, all before you have a working endpoint.</p>
<p>Now your boss can visualize the intended behavior of these endpoints by hitting the mock endpoints, before the real endpoints are up and running.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163731808/2b934365-8830-45b5-8263-0af56e0766ed.png" alt /></p>
<p>Send a request to the mock endpoint along with the unique path in your saved example.</p>
<p>Turns out our teammates had some good feedback. Let’s implement some of their suggestions.</p>
<p>Update the <code>/pushups</code> endpoint to be inclusive of other exercises. Pushups are great, but what if we want to expand the functionality of the app to include burpees, arm circles, and anything else? Let’s <a target="_blank" href="http://blog.getpostman.com/2018/07/16/find-and-replace-text-code-and-variables-in-postman/">find and replace</a>* the text by replacing “pushup” with “exercise”, and similar instances of the word. In fact, let’s rename our collection as “Workout”.</p>
<p><em>*<strong>*Note</strong></em>:* Find and Replace is available in Postman’s Canary v6.2.2.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163733675/37dab415-753f-4747-85ae-c9b5e4b7becc.png" alt /></p>
<p>Find and replace text related to “pushups” to be more inclusive of other exercises.</p>
<p>Add a third Postman folder called “Account” for account-related requests. It would be nice to let other people use this app too, but we don’t want to mix up our workout schedules.</p>
<ol>
<li>POST generate an access token (<code>/oauth2/token</code>).</li>
<li>GET request to retrieve the exercise history of a user (<code>/account/:userId</code>)</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163735458/b1b16627-3f00-44b8-a78d-53e94dc87d80.png" alt /></p>
<p>Defining what our POST request to create an access token could look like.</p>
<p>Now you can initialize and save the resulting access token as an <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/environments_and_globals/intro_to_environments_and_globals">environment variable</a> so it can be used in subsequent requests.</p>
<p>In fact, add an Authorization header with our access token to all of our other Pushup API requests. Don’t forget to duplicate this “Create an account” request, and add it to the beginning of our “Get Started” workflow folder.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163737026/dfab22ed-7f01-41d8-b5a2-e2503050965e.png" alt /></p>
<p>Include the access token as an Authorization header with all other API requests.</p>
<p>Time for another round of feedback. Our collection updates are made in real time, so our teammates can once again review the latest version of the collection in our team workspace. The examples are also updated in real time, so your boss can view the latest version of the mock responses too.</p>
<p>We can continue repeating this loop until everyone feels good about what we’re building. This allows us to iterate quickly. It’s better to update the design and the mock at this stage before we invest our time and resources into development.</p>
<p>Alright, we’re ready to start building!</p>
<h3 id="heading-3-build-the-api">#3 Build the API</h3>
<p>I think the collection helped people visualize the app a little bit better. It seems like there’s a few more teammates who want to help out now. Fortunately, your boss has agreed to let them work on this for one week.</p>
<p>How can we do this in a week?!?</p>
<p>With parallel development.</p>
<p>By gaining alignment on the plan up front, we have established a public contract of sorts to avoid any major pivots and integration failures down the line. We’ve also decoupled a number of dependencies, so that no one is waiting on anyone else.</p>
<p>We have everything we need to get started.</p>
<ul>
<li><strong>Document the API:</strong> your technical writer has everything they need to begin describing each endpoint and laying the groundwork for the <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/api_documentation/intro_to_api_documentation">API documentation</a>. This API is a private one, and we’ll use it internally within our organization, but thorough documentation will be helpful for anyone working on the project and especially new team members. Furthermore, this API documentation will continue to socialize the purpose and behavior of the planned service.</li>
<li><strong>Write tests:</strong> Since we saved examples, your QA engineer doesn’t have to wait for development to get going. They can <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/scripts/test_scripts">write tests and assertions</a> for each endpoint, run each test against the mock responses, or create new <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/collections/examples">examples</a> to mock any external dependencies that are not yet available.</li>
<li><strong>Develop the backend:</strong> your back-end engineer will be helping out with the API and database development. Every request in Postman represents a server-side route that must be developed. The mock responses will also provide insight into how to set up the database and structure the database queries.</li>
<li><strong>Develop the user interface</strong>: you can handle the front-end development this time. Both back-end and front-end development will be referring to the <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/scripts/test_scripts">mocks</a> to develop their respective code. You know how and where to send client requests, what kind of server response to expect, and can make requests to the mock server until a time the real endpoints become available. As a shortcut, remember that you can use Postman to <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/sending_api_requests/generate_code_snippets">generate a code snippet</a> for every request you plan to make to the server.</li>
</ul>
<h3 id="heading-generate-code-snippets">Generate code snippets</h3>
<p>Once you’ve finalized and saved your requests in Postman, you can <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/sending_api_requests/generate_code_snippets">generate a code snippet</a> in your preferred language or framework to add to your own application. Let’s walk through how to generate code snippets in Postman.</p>
<h4 id="heading-identify-the-request"><strong>Identify the request</strong></h4>
<p>In your app, imagine there’s a button called “See all exercises”. If a user pushes that button, we’d like the client to make an authenticated GET request to the <code>/exercises</code> endpoint.</p>
<p>In our Workout collection (previously called Pushup), expand the Exercises folder, and click on the GET request to list all the exercises to load it up in the request builder.</p>
<p>Select an environment if you’re relying on any environment variables.</p>
<p>When you have the request working as you’d like it, click the <strong>Code</strong> link on the right side to open the <strong>GENERATE CODE SNIPPETS</strong> modal.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163738760/9ede12ea-1b29-4f9e-8908-27ac64c7796f.png" alt /></p>
<p>Use the Code link to generate a code snippet of the current request.</p>
<h4 id="heading-select-the-programming-language-and-framework"><strong>Select the programming language and framework</strong></h4>
<p>From the dropdown, select the language and framework that you’re using for your own app. Our team is using Node.js, specifically the Request framework, to develop our web app. You can update the snippet* in this editor.</p>
<p><strong>*Note:</strong> the code snippet may include a <code>Postman-Token</code> header. It’s a holdover from the deprecated Postman Chrome app, and can be deleted in your own app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163740686/0c20c623-9267-4f5d-bffc-53d9afa644e7.png" alt /></p>
<p>Select your preferred programming language and framework to customize your code snippet.</p>
<p>When you’re ready, copy and paste this code directly into your IDE where you’re developing your own app.</p>
<p>If you’re using a Postman environment variable to store your secrets, Postman will use string substitution while generating the code snippet. In your own app, you will likely have a way to pull in environment variables so that you’re not hardcoding any secrets or leaking any sensitive information.</p>
<h3 id="heading-4-deploy-the-api">#4 Deploy the API</h3>
<p>Finally, everyone is ready to deploy our app to a staging server where we will test the app before letting it go to production.</p>
<ul>
<li><strong>Share the API documentation:</strong> your technical writer has finished documenting all the endpoints and team members can <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/api_documentation/viewing_documentation">view the private documentation</a> in a web browser as an easy reference.</li>
<li><strong>Run the tests:</strong> your QA engineer has swapped out the mock endpoints for the real ones already deployed to the staging server by the backend engineer. They added test cases in Postman, which we will run for any new build and must pass prior to any future deployments. We’re using Postman as the single source of truth for our API tests, API documentation, and how our APIs are being consumed.</li>
</ul>
<p>For the API documentation and API tests in Postman, team members with write permissions have made their updates. Postman automatically merge d their changes into the shared collection so that everyone can work off the latest version. If we decide to undo any changes, we can <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/workspaces/activity_feed_and_restoring_collections#restoring-collections">restore the collection</a> to a previous point in time.</p>
<ul>
<li><strong>Deploy server-side code:</strong> your backend engineer has committed the code updates made in their IDE to Git and pushed them to our shared repository on GitHub. We’re using GitHub as the single source of truth for our code base, including the implementation for our APIs.</li>
<li><strong>Deploy client-side code</strong>: commit the code updates made in your IDE to Git, and pushed the client-side code to GitHub.</li>
</ul>
<p>As part of our branching workflow, the server-side and client-side code must undergo a peer review before it will be merged into our main branch. Once approved, the code is integrated and released to the staging server environment for manual and automated testing.</p>
<p>For this particular project, we’ll use the <a target="_blank" href="https://www.getpostman.com/docs/v6/postman/collection_runs/starting_a_collection_run">Postman collection runner</a> to execute the test suite written by QA. If any tests fail, we debug the issues until the code is running as intended. Only after all the tests have passed, will we release the code to production.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163742074/681589f9-6377-426a-846c-ab9ea226fc24.png" alt /></p>
<p>A closer look at API-first development where work progresses in parallel, avoiding bottlenecks.</p>
<p>In the future if we decide to set up a Continuous Integration and Continuous Delivery (CI/CD) process to automate our build, we’ll use <a target="_blank" href="http://blog.getpostman.com/2018/06/21/newman-run-and-test-your-collections-from-the-command-line/">Newman to handle test automation from our CI environment</a>.</p>
<h3 id="heading-rinse-and-repeat">Rinse and repeat</h3>
<p>Huzzah! It’s been 3 glorious weeks since we released the app to production, and we are pumped, figuratively and literally 🏋️</p>
<p>There’s been such a fitness buzz in the office, that we’re ready to expand the functionality of the app.</p>
<p>Since we followed an API-first approach, we’re set up favorably to handle new feature requests. The team can use the Workout API to build out additional application functionality or expand to other platforms. Alternatively, a new team can jump in to help out and get up to speed quickly by referencing our API documentation.</p>
<p>Let’s continue this API-first approach for our next feature. Adding another feature will follow the same process as when we first created the app.</p>
<ol>
<li>Design the new feature</li>
<li>Get feedback about the new feature</li>
<li>Build the feature</li>
<li>Deploy the changes</li>
</ol>
<p>Repeat as many times as necessary.</p>
<p><strong>Want to check it out in the Postman app?</strong> Click the orange “Run in Postman” button below to download the Postman collection and environment containing these sample requests, or <a target="_blank" href="https://documenter.getpostman.com/view/1559645/RWMJqSZe">check out the documentation</a>.</p>
<p><a target="_blank" href="https://app.getpostman.com/run-collection/c8f32ebc050535f9ef05#?env%5BWorkout%5D=W3sidHlwZSI6InRleHQiLCJlbmFibGVkIjp0cnVlLCJrZXkiOiJiYXNlX3VybCIsInZhbHVlIjoiaHR0cHM6Ly9hcGkud29ya291dC5jb20vdjEifSx7InR5cGUiOiJ0ZXh0IiwiZW5hYmxlZCI6dHJ1ZSwia2V5IjoiY2xpZW50X2lkIiwidmFsdWUiOiJ5b3VyLWNsaWVudC1pZCIsImRlc2NyaXB0aW9uIjoiIn0seyJ0eXBlIjoidGV4dCIsImVuYWJsZWQiOnRydWUsImtleSI6ImNsaWVudF9zZWNyZXQiLCJ2YWx1ZSI6InlvdXItY2xpZW50LXNlY3JldCIsImRlc2NyaXB0aW9uIjoiIn0seyJrZXkiOiJhY2Nlc3NfdG9rZW4iLCJ2YWx1ZSI6Im15LWFjY2Vzcy10b2tlbiIsImRlc2NyaXB0aW9uIjoiIiwidHlwZSI6InRleHQiLCJlbmFibGVkIjp0cnVlfV0="><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163743123/c52f364c-d9f8-4e83-93f9-81737e0f082a.png" alt /></a></p>
<p>click this button to download the collection and environment</p>
<p><a target="_blank" href="https://documenter.getpostman.com/view/1559645/RWMJqSZe"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735163744959/0df986a1-0967-4092-b939-1433a31234ba.png" alt /></a></p>
<h3 id="heading-what-is-the-single-source-of-truth-for-your-apis">What is the single source of truth for your APIs?</h3>
<p>We agreed earlier that our shared repository, in this example GitHub, is the single source of truth for our code base, including the <em>implementation</em> for our APIs. This code base is deployed on your own servers, a cloud provider, or on an API gateway if you’re managing an extensive system of services.</p>
<p>Even though the code lives in your source control system, teams will sometimes say that Postman serves as the single source of truth for their APIs.</p>
<blockquote>
<p><a target="_blank" href="https://bettercloud.tech/postman-pro-at-bettercloud-e46d2de2f76a"><strong><em>With Postman Pro, we’ve created a single source of truth for all API endpoints that’s shared across the organization.</em></strong></a></p>
<p><strong><em>- David Esposito, BetterCloud</em></strong></p>
</blockquote>
<p>Some teams use Postman to write their API tests, write their API documentation, and then run their API tests before any build is permitted to release. Postman is the single source of truth for their APIs.</p>
<p>For a lot of teams, Postman is used as a reference for the latest endpoints, use cases, and examples of how their APIs <em>should</em> be functioning.</p>
<p>Although any updates in Postman still require one more step to update the code base, via code generation or other means, the data maintained in Postman serves as the single source of truth for their APIs.</p>
<p>This source of truth is valuable for all API stakeholders, including Product Managers, Sales, Customer Support, DevOps, or anybody who will interact with or consume the API.</p>
<h3 id="heading-closing-thoughts-on-api-first-software-development">Closing thoughts on API-first software development</h3>
<p>We’ve reviewed a number of reasons why organizations choose an API-first approach for software development. Some organizations are under the gun to push something into the market, and doing it quickly outweighs any headaches they might have to deal with down the line.</p>
<p>For other teams, let’s make APIs a first class citizen. It’s conceivable that one day, if not today, components will be talking to each other and services will be relied on internally and externally. The world of code is only increasing in complexity.</p>
<p>Consider your API, one that is resilient, versatile, and future-friendly. Designing and building the API first will save time, resources, and headaches over the lifetime of your project.</p>
]]></content:encoded></item></channel></rss>