Get the most out of Insomnia to effectively test your API
TL;DR Don’t just write requests in Insomnia, use some of its best capabilities to keep your stuff maintainable and be more efficient.
What is Insomnia?
Insomnia is a great software to easily send requests. It’s the perfect tool to test your REST or GraphQL APIs.
It has been acquired by Kong in late 2019 and is available on Linux, macOS and Windows.
In this article, I would like to show you how to get the best of it. This will make you gain some time, avoid repeating yourself and keep your workspace maintainable.
Disclaimer: I will show the keyboard shortcuts for macOS version. If you’re using another operating system, please find the corresponding shortcuts in the Keyboard tab of the Insomnia Preferences dialog.
Staying organized
The more you will work with Insomnia, the more you will have requests. The first thing to do to ease your work and maintainability is to keep things organized. Insomnia offers two ways to do it: request collections and folders. Both are useful and can be combined.
Request Collections (or Workspaces)
Request Collections are the top level unit of organization. You can start with a single one, but at the end you will find it easier to have a collection per domain, application or even microservice. One of the benefit is to make it quicker to export a subset of the requests.
A hint to find out how you should use request collections is to keep in mind that variables and environments will be stored at request collection-level. We will talk about variables and environments later in this article.
Folders
Folders are the second level unit to organize your requests. If you are using a single workspace for your entire organization, you can put the requests for each of your products into a dedicated folder. If you are using a workspace per product, you can create a folder to group requests of the same domain.
Requests of a folder will continue to have access to the environment variables of the collection they are part of.
Template Tags
Template tags act like placeholders and their value results from the execution of a function, should it be a predefined one or your own one.
They can be used almost everywhere in Insomnia: request body, auth, query parameters, headers…
Use ^Space
to open the template tags autocomplete palette, or start typing {%
followed by a space character or the tag name.
Here are some examples of the most useful template tags:
- UUID: generates a v1 or v4 UUID, often used as a unique resource identifier in request body ;
- Timestamp: outputs the current date and time in various formats — it even accepts Moment.js formatting options so you can select Custom format, click the tag and type something like
YYYY-MM-DD
in the edit window ; - Cookie: gets the value from the cookie jar, a feature of Insomnia to manage cookies.
If the provided tags are not enough for you, consider writing your own plugin to match your needs. It’s pretty straightforward if you are familiar with Node.js modules.
Environment
In Insomnia, environments are a place to store data as a JSON object. You can modify them with the shortcut ⌘E
.
Variables are defined as properties (or sub properties thanks to JSON format) of an environment: the base environment or a sub environment.
Variables will be read directly as a property of the current environment. Use ^Space
to open the variables autocomplete palette, or start typing {{
followed by a space character or the variable name. You can use variables anytime a template tags is allowed.
Base Environment
This is the root environment containing data available to the current request collection, regarding what is the selected sub environment. There is only one base environment per workspace.
You should put in this base environment every data that are not dependent to the execution environment (development, staging, production…).
For example, you could have the following base environment:
{
"serviceName": "foo-service",
"healthCheckPath": "/monitor"
}
If the service name and the monitoring endpoint are the same whether you reach your staging or production website, then the base environment is the perfect place to store those variables.
Sub Environment
A sub environment behaves exactly like the base environment, with the exception you can create many of them. However, you can have only one active at the same time.
You will usually create one per execution environment: one for local development, one for staging, one for production, and so on.
The base environment data will be merged with the active sub environment data, with the priority for the later. Other inactive sub environments will be ignored.
Let’s say we have the following base environment:
{
"foo": 0,
"path": "/"
}
the following staging environment:
{
"foo": 1,
"name": "staging"
}
and the following production environment:
{
"foo": 2,
"name": "production"
}
If you select the production sub environment, then these variables will available:
{
"foo": 2,
"name": "production",
"path": "/"
}
Easy, right? Now let’s go a step further!
Using variables in environment definitions
— Wait, what? Didn’t you say the goal of an environment was to create variables?
— That’s correct. But here comes the magic part of Insomnia!
Because environment variables will be evaluated dynamically when they are used (mainly when a request is executed), nothing prevents you from using a variable you know will be defined at a point of time.
Let’s create a basic sub environment:
{
"protocol": "https",
"domain": "example.com"
}
You need to close the environment definition window and make this sub environment.
Now we will edit the base environment, add a name property to the object, and thanks to the magic of template tags (⌘^Space
), you can use the variables in your environment definition:
Pretty cool, right? Look at the example on the screenshot how we made use of variables coming from both the base environment and production environment.
If you select a sub environment that do not define the required properties, Insomnia will warn you by displaying the template tags in red:
Response attributes
Suppose we have an API that let us manage a collection of books, which includes two basic endpoints:
POST /books
to create a new book ;GET /books/<id>
to get a book by its id.
If the API is responsible to generate a unique identifier at the creation of a book, you can’t know in advance how to retrieve this book as its identifier is not known yet. That’s where using response attributes to chain requests is useful.
Here is an example of a POST /books
response:
{
"_id": "9b34080b-2636-4edf-b92f-bc48d124b1dc",
"title": "Twenty Thousand Leagues Under the Seas"
}
Use a template tag Response => Body Attribute
in the URL field of the GET /books/<id>
request:
Edit the tag filter to set the path of the identifier attribute ($._id
) and adapt the trigger behavior to your needs:
That’s it! Now you don’t have to worry about the identifier that has been assigned at the object creation.
Tips
- Copy as Curl: copy to the clipboard the code to perform the request with the curl command line tool. It is accessible through the menu after a click on the arrow that appears when hovering a request.
Something similar to this will be copied to the clipboard:
curl --request POST \
--url https://api.example.com/v1/books \
--header 'Content-Type: application/json' \
--data '{
"title": "Twenty Thousand Leagues Under the Seas"
}'
- Import/Export: you can import/export one or many collections. This is especially useful to backup your workspace or share a collection with someone else. It is accessible via the Data tab of the Insomnia Preferences (
⌘,
) dialog.
Bonus: Generating Insomnia Request Collections
Disclaimer: This is an advanced part about the usage of Insomnia. It is about using programming skills to create stuff instead of the user interface.
A few months ago, I had to test a lot of microservices while they were being migrated to AWS. In the middle of the migration, using CI to test the entire behavior was not possible. For most of them, I did not know which endpoints or JSON-RPC methods they expose. Fortunately, all our microservices have a private endpoint which return a JSON-formatted documentation of methods they expose and events they send or listen to. Instead of creating requests for each microservice and method I wanted to test, I wrote up a basic script which converted those JSON-formatted documentations into a dedicated Insomnia Request collection. Then I just had to import the generated file into Insomnia, launch the requests, and that’s it!
I don’t want to deep dive into the conversion process because it was very specific to my use case. However, you may find interesting to see how we can create requests and collections on-the-fly.
Request template
Let’s create a request template that will be used to generate a single request. This is basically a JSON file in which I use some placeholders that will be replaced by the corresponding value later on. For example, we will generate a random UUID for each request that will be set in place of the #{req_uuid}
placeholder.
{
"_id": "req_#{req_uuid}",
"parentId": "wrk_#{wrk_uuid}",
"modified": #{timestamp_ms},
"created": #{timestamp_ms},
"url": "{{ service.#{safe_service_name}.url }}",
"name": "#{method_name}",
"description": "#{method_desc}",
"method": "POST",
"body": {
"mimeType": "application/json",
"text": "#{method_body}"
},
"parameters": [],
"headers": [
{
"id": "pair_#{pair_uuid}",
"name": "Content-Type",
"value": "application/json"
}
],
"authentication": {},
"metaSortKey": -1000000000,
"isPrivate": false,
"settingStoreCookies": true,
"settingSendCookies": true,
"settingDisableRenderRequestBody": false,
"settingEncodeUrl": true,
"settingRebuildPath": true,
"settingFollowRedirects": "global",
"_type": "request"
}
Request Collection template
Let’s do the same for the request collection. It consists of several resources:
- the workspace itself, that is the object describing the collection ;
- the requests ;
- a sub environment (we will create a production sub environment here) ;
- other objects left empty for the sake of simplicity : the base environment, a cookie jar, and an API spec.
{
"_type": "export",
"__export_format": 4,
"__export_date": "#{date_iso}",
"__export_source": "insomnia.desktop.app:v2020.4.1",
"resources": [
#{requests},
{
"_id": "wrk_#{wrk_uuid}",
"parentId": null,
"modified": #{timestamp_ms},
"created": #{timestamp_ms},
"name": "#{wrk_name}",
"description": "",
"scope": null,
"_type": "workspace"
},
{
"_id": "env_#{env_id}",
"parentId": "wrk_#{wrk_uuid}",
"modified": #{timestamp_ms},
"created": #{timestamp_ms},
"name": "Base Environment",
"data": {},
"dataPropertyOrder": null,
"color": null,
"isPrivate": false,
"metaSortKey": #{timestamp_ms},
"_type": "environment"
},
{
"_id": "jar_#{jar_id}",
"parentId": "wrk_#{wrk_uuid}",
"modified": #{timestamp_ms},
"created": #{timestamp_ms},
"name": "Default Jar",
"cookies": [],
"_type": "cookie_jar"
},
{
"_id": "spc_#{spec_uuid}",
"parentId": "wrk_#{wrk_uuid}",
"modified": #{timestamp_ms},
"created": #{timestamp_ms},
"fileName": "#{wrk_name}",
"contents": "",
"contentType": "yaml",
"_type": "api_spec"
},
{
"_id": "env_#{env_uuid}",
"parentId": "env_#{env_id}",
"modified": #{timestamp_ms},
"created": #{timestamp_ms},
"name": "production",
"data": {
"restaurant": {
"restaurantUuid": "#{restaurant_uuid}"
},
"service": {
"#{safe_service_name}": {
"url": "http://#{service_name}.example.com"
}
}
},
"dataPropertyOrder": {
"&": [
"restaurant",
"service"
],
"&~|restaurant": [
"restaurantUuid"
],
"&~|service": [
"#{safe_service_name}"
],
"&~|service~|#{safe_service_name}": [
"url"
]
},
"color": null,
"isPrivate": false,
"metaSortKey": #{timestamp_ms},
"_type": "environment"
}
]
}
The complex part is the generation of the environment. We keep the base environment empty and use the production sub environment to set a few variables which will look like this at the end:
{
"restaurant": {
"restaurantUuid": "c4f35aef-f4de-4d29-ba08-e1acc2070fe2"
},
"service": {
"foo_service": {
"url": "http://foo-service.example.com"
}
}
}
Putting things altogether
I chose Node.js to write the generation script mainly because of its native capability to work with JSON format.
Basically it consists of reading the template file we described above, replacing placeholders with corresponding values, and writing the result in a new file:
(patterns, inputPath, outputPath) => {
const rs = fs.createReadStream(inputPath);
const ws = fs.createWriteStream(outputPath); rs.on('readable', () => {
const chunk = rs.read(); if (chunk !== null) {
const content = replacePatterns(patterns, chunk);
ws.write(content);
} else {
ws.end();
}
});
};
To replace the placeholders, a mapping object between the placeholder name and a function to get its value is enough.
In the extract below, I generate a UUID for each request and use the serviceName
variable I got from the JSON-formatted documentation of my microservice.
const requestPatterns = {
'#{req_uuid}': () => uuid(),
'#{service_name}': () => serviceName,
'#{safe_service_name}': () => serviceName.replace(/[^\w]/g, '_'),
// ... many other patterns
};function replacePatterns(patterns, buffer) {
let content = buffer.toString(); Object.keys(patterns).forEach((pattern) => {
content = content.replace(new RegExp(pattern, 'g'), patterns[pattern]());
}); return content;
}
A great thing is that you can use the template tags we mentioned earlier. For instance, to let Insomnia generate a UUID itself we can use this syntax:
{% uuid 'v4' %}
This is the gist of how I generated Insomnia collections on-the-fly. If you’re interested, you can find the whole code source on its Github repository.
Conclusion
We have seen some of the features Insomnia provides to make us more productive. I hope this article made you discover a few! There are still plenty of options, settings or possibilities to explore. If you want to go further, you can check out Insomnia documentation.