Insomnia-2022-Roadmap Cover Copy@2x
Garen Torikian

By on December 8, 2021

Building With Insomnia as a REST API Client

As more companies invest in a cloud native infrastructure, they’re choosing to prioritize their applications as microservices—architecting them into distinct servers. Each component is responsible for one (and only one) feature. 

For example, you might have Server A responsible for handling billing logic, Server B for handling user interaction and Server C for handling third-party user interactions. These servers individually are microservices that make up the entirety of your application.

When designing a microservices architecture, you’ll need to determine how these servers ought to communicate early on. For example, Server C might need to check billing information before performing some action, which means Server C would need to ask Server A if a user has the appropriate permissions. 

We’ll need an API to handle the requests and responses consistently in these cases. The most popular API protocols boil down to three choices: gRPC, graphQL and good ol’ REST. REST is the lingua franca of the web; it has all the HTTP verbs you’re aware of, like GET and POST, and matches very closely with how browsers send and receive data.

In this post, we will explore how to build a REST API and test it using Insomnia, an open source client for interacting with APIs. We’ll build a simple server in Node.js and send requests to fetch and manipulate data. We’ll also add different authentication strategies and show off some of the highlights of using Insomnia.

Getting Started

Before following this guide, be sure to install the latest version of Insomnia. You will also need to install the latest version of Node (at least version 14.0) and npm (which comes with Node).

Building Our Server

In a brand new directory, run the following command to install all the necessary dependencies:

npm install express

Next, create a file called server.js, and paste the following lines into it:

const express = require("express");
const app = express();
const port = 3000;
app.use(express.json())

app.get("/", (req, res) => {
 res.send("Hello World!");
});

app.listen(port, () => {
 console.log(`Example app listening at http://localhost:${port}`);
});

On the command line, run node server.js, then visit http://localhost:3000 in your browser. You should see a cheerful greeting. This demonstrates that we have the necessary dependencies to continue building our server.

Normally, you would expect your server to have some form of stable long-term storage, like a database. For simplicity, we’ll create a fake list of records in JSON, which will act as the content that we can serve out during requests. 

In your server.js file, add the following lines of code:

let books = [
 {
   id: 1,
   title: "Absalom, Absalom",
   isbn: 97803801407743,
   author: { id: 1, firstname: "William", lastname: "Faulkner" },
 },
 {
   id: 2,
   title: "The Fire Next Time",
   isbn: 97801401284643,
   author: { id: 2, firstname: "James", lastname: "Baldwin" },
 },
 {
   id: 3,
   title: "Orlando",
   isbn: 9780241827502,
   author: { id: 3, firstname: "Virginia", lastname: "Woolf" },
 },
];

Our microservice will serve as the front for a bookstore inventory. Next, we’ll work out some API paths to fetch this list.

Getting Data With Insomnia

Now, let’s build an endpoint that returns this data to a user. Add the following lines to your server.js file:

app.get("/api/books", (req, res) => {
 res.send(books);
});

Restart your server if it’s already running. Let’s first visit this URL in the browser: http://localhost:3000/api/books. You’ll see your list of books as a text dump. That’s great, but we can do better.

Open up Insomnia and follow these two steps:

  1. Select GET as the operation type.
  2. Set the endpoint to the same URL you visited in the browser.

json-hello-world

app.get("/api/book/:id", (req, res) => {
 let book = books.find((book) => book.id === req.params.id);
 res.send(book);
});

That :id is essentially a placeholder. Whatever we put at the end of the path string will become available as a variable that we can use in Express. Restart your server, and then head back to Insomnia. This time, you can issue a query with a specific ID to get more details about it. In my case, I just want http://localhost:3000/api/book/2 .

json-query

Since all of the responses are JSON, looking at the data in this way—rather than through the browser or command line—makes it much easier to see what you’re getting.

Adding Data With Insomnia

Okay, we can get our inventory, but what about manipulating the inventory? Suppose we want to add a book. How would we do that?

We probably want to POST some JSON data that represents a book. In the browser, it would be near impossible to do so. In addition, trying to format JSON through the command line can be challenging. Let’s see how Insomnia handles it.

First, add the following POST route to Express:

app.post("/api/book", (req, res) => {
  const body = req.body;
  const book = {
    id: body.id,
    title: body.title,
    isbn: body.isbn,
    author: {
      id: body.author.id,
      firstname: body.author.firstname,
      lastname: body.author.lastname,
    },
  };
  books.push(book);

  res.send(books);
});

req.body is the HTTP request body and represents the JSON data payload accompanying the request. If we want to add a new book, we need to provide some JSON that’s “shaped” like the other books in our array—something like this:

{
  "id": 4,
  "title": "Ulysses",
  "isbn": 92803801040749,
  "author": {
    "id": 1,
    "firstname": "James",
    "lastname": "Joyce"
  }
}

Restart your server, and head back to Insomnia. Change the HTTP operation type to POST.  Then, set the body type to JSON, and paste this text into it (or another book, if your heart desires).

json-ulysse-james-joyce

Voila! The server will respond with the book inventory, including your recently added one. Success!

By the way, note that every time you restart your server, your list of books will begin with the original list of three books initialized at the top of your server.js file. Since we’re not maintaining persistent storage with a database, any data changes you make will disappear each time you restart the server. 

Deleting Data With Insomnia

Just to close the loop, let’s also consider how to delete a book using Insomnia. By adding the following lines to our server, we provide a “delete book” endpoint as shown below:

app.delete("/api/book/:id", (req, res) => {
 books = books.filter((book) => book.id !== req.params.id);
 res.send(books);
});

Back in Insomnia, set the HTTP operation to DELETE. This request doesn’t need a request body, so select “No Body” from the dropdown:

deleting-data-with-insomnia

The server will respond with the inventory, minus the book you put on the chopping block.

Providing Headers

We’ll explore Insomnia further by extending our demo application with more functionality. In a real-world scenario, you would never expose dangerous actions—like the ability to add or delete books from an inventory—without some form of authentication. Authentication acts as a security measure that only allows users with permissions to make modifications.

In server.js, right after where you defined your book inventory, paste the following lines:

const auth = {
 username: "admin",
 password: "mysecretpassword",
};

function authenticated(headers) {
 const [user, pass] = headers.authorization.split(":");

 if (user && pass && user === auth.login && pass === auth.password) {
   return true;
 }

 return false;
}

Here, we’ve defined a function that checks the HTTP header to see whether or not there is correct authentication info. If not, we’ll reject the request. It’s worth noting that defining passwords in plaintext and your files is a huge security risk and a very bad idea! We’re only doing it here for demo purposes. You should always store your secure config values in an environment variable

To enforce authentication, add the following lines to your POST route:

app.post("/api/book", (req, res) => {
if (!authenticated(req.headers)) {
  return res.status(401).send("Authentication required.");
}

To demonstrate how this works, restart your server and return to Insomnia. Issue another POST request to add a book. You will get a 401 error message because you haven’t provided any authentication info! Adding authentication like this is an excellent way to protect unauthorized users from accessing endpoints that we should protect.

To provide the authentication, we need to modify Insomnia’s headers. Click on the Headers tab, and create a new key-value pair of Authorization and admin:mysecretpassword.

avoiding-headers

When you issue the request again, you’ll see your new book added, just as before. 

Setting Environment Variables

One of the other neat things about Insomnia is that it supports environment variables directly in the editor. Environment variables are a great way to reuse information across multiple requests, like URLs or usernames. Insomnia environment variables can also come from files and URLs, which provide consistency across all platforms when you’re testing your API.

To see how this feature works, we’ll perform a few actions. First, we’ll create an environment that defines the variables Insomnia should know about. However, instead of using just a plaintext password, we’ll Base64-encode it to demonstrate what some sort of obfuscation might look like.

To create an environment, click on the Environment dropdown menu on the left-hand side of Insomnia, and select Manage Environments.

no-enviroment

From there, create a new sub-environment called REST API, and paste in the following JSON:

{
  "ROOT_URL": "http://localhost:3000",
  "AUTH_INFO": "{% base64 'encode', 'normal', 'admin:mysecretpassword' %}"
}

managed-enviroment

ROOT_URL, as you might notice, is the URL of our running Node server; AUTH_INFO is base-64 encoded version of our username and password. Base64-encoded version of the string admin:mysecretpassword. You’ll notice that as soon as you finish typing the {% base64 ‘encode’ template function, it converts into a label. Clicking on it brings a pop-up with more information on the encoded and plaintext values of this variable:

edit-tag

We will use this new auth string to demonstrate working with environment variables and encodings in both our API and Insomnia. Once you’ve saved this environment, select it from the same dropdown menu as before:

activate-environment

In server.js, change how the authentication headers are retrieved in the authenticated function to this:

  const authorization = Buffer.from(headers.authorization, "base64")
   .toString("utf-8")
   .split(":");

Restart your server, then head back to Insomnia’s Headers tab. Click on the previously entered admin:mysecretpassword value, then press Ctrl+space (or Cmd+space). You should have the option to enter _.AUTH_INFO, which is your environment variable from before. You can insert environment variables almost anywhere Insomnia provides a text box. To that end, let’s also replace our server name with the ROOT_URL value that we also created:

root-url-api-book

Go ahead and try to add yet another book to your growing catalog. You should be able to do so with this newer, more secure version of passing around authentication info.

 

Activating Plugins for More Features

Wouldn’t it be nice if you could send dynamic JSON payloads to your API? Well, you’re in luck! Insomnia provides support for various plugins, and one of them, the faker plugin, lets you use template tags to generate fake random strings with each request.

activating-plugins-for-more-features

After installing the plugin, you can press Ctrl+space (or Cmd+space) to insert dynamically generated data. Just like the base64 template tag we showed earlier, clicking on the Faker label lets you modify the types of data you want included.

edit-tag

Running Tests Using Insomnia

Of course, deploying your untested API directly to production isn’t a great idea, regardless of how confident you are that it works. It’s a good practice to create a test suite that validates your API is working properly. Insomnia can run unit tests to assert that your API’s status codes and response bodies are as expected. Let’s explore how that works!

First, click on the purple Dashboard link in the upper left corner of the app. Then click Create, followed by Design Document. Give this file a name like book-api.yml, and click Create. Here, you can design your API using the popular OpenAPI spec. The following spec represents the book store API we have just created; go ahead and paste the following lines directly into the editor:

openapi: 3.0.0
info:
  version: 1.0.0
  title: Sample API
  description: A sample API to illustrate OpenAPI concepts
servers:
  - url: http://localhost:3000
paths:
  /api/books:
    get:
      description: Returns a list of books
      responses:
        "200":
          description: Successfully retrieved books
  /api/book/{id}:
    get:
      description: Returns a single book
      parameters:
        - name: id
          in: path
          description: Book ID
          required: true
          schema:
            type: integer
            format: int
      responses:
        "200":
          description: Successfully retrieved one book
    delete:
      description: Removes a single book
      parameters:
        - name: id
          in: path
          description: Book ID
          required: true
          schema:
            type: integer
            format: int
      responses:
        "200":
          description: Successfully removed one book
  /api/book:
    post:
      description: Adds a new books
      responses:
        "200":
          description: Successfully added a book

Here, we’ve described our API using the OpenAPI YAML format. Click on the Debug tab, then select OpenAPI as your environment. Your left-hand pane will populate with your API endpoints; go ahead and click on GET /api/books, and click Send to execute the query:

book-api-yml

You should see a response with your list of books. There’s nothing different about how this Debug tab works; the real power of creating an OpenAPI spec is the ability to create tests. Go ahead and click on Test next, then click on New Test Suite. Call it Inventory tests, then click Create suite. Insomnia will present you with a blank pane. Let’s populate it!

Click on New test, and enter the phrase Returns a list of books as its name. Pick your [GET] /api/books endpoint in the Select Request dropdown menu. You might have noticed that these options map directly to your API and come from your provided OpenAPI spec. 

Next, click on Run tests. In the right-hand pane, you should see a Passed message. That’s great, but what happened? Go ahead and expand the test suite, and you should see some lines of code. Insomnia uses the Chai testing library behind the scenes, which enables you to set up expectations and assertions for your API responses. Let’s go ahead and modify this test to assert that an array is returned by ensuring that the inventory has more than one item. Replace the lines of code with the following:

const response1 = await insomnia.send();
expect(response1.status).to.equal(200);
// it's an array
expect(response1.data).to.have.lengthOf.above(1);

Click on Run Tests again, and your test should still pass!

test-passed

Of course, you also want to make sure that the elements in the response are in the format you expect—with an id, a title, an author and so on. But as a sample, this is pretty great!

Go ahead and add one more test: [GET] /api/book/{id}. Now, try to run it—you’ll receive an error. What happened? Well, Insomnia knows about your endpoint, but it doesn’t know what to insert for {id}. You can provide a value by going back to the Design tab, then editing the environment to add a mapping between the path parameter and its value, like this:

managed-enviroments

If you go back to Test and run all of your tests, you should see the endpoint with the variable pass!

Learning More About Insomnia

Insomnia isn’t just for REST APIs. Many of the UX features we covered are also available for APIs written in gRPC and graphQL. Insomnia is an active open source project, and you can contribute to its development or develop plugins that suit your needs!

To learn more about Insomnia, check out our documentation. You can also find out how to deploy your APIs to a microservice or discover plugins to help enhance your Insomnia experience.

Share Post

Tags: