Getting Started with the Golioth Management API

Integrating with an external API doesn’t have to mean hand-writing HTTP requests, guessing payload shapes, or chasing runtime errors. In this post, we’ll walk through how to get started with the Golioth Management API from a TypeScript-based Node.js backend using auto generated types from our OpenAPI definition.

By the end, you’ll have:

  • A Node.js project written in TypeScript
  • Fully typed API bindings generated from Golioth’s OpenAPI spec
  • API authentication handled cleanly with a .env file
  • A small example that talks to the Golioth Management API

Why OpenAPI + TypeScript?

Golioth Management API is published as an OpenAPI definition. This means we can automatically generate:

  • Strongly typed request and response objects
  • Autocomplete in your editor
  • Compile-time errors instead of runtime surprises

For backend developers, this removes a lot of guesswork and makes refactoring much safer.

1. Create a new Node.js + TypeScript project

Before we start, you’ll need:

  • Node.js 18+ installed
  • Basic familiarity with TypeScript
  • A Golioth account and an API key

Start by creating a new project directory and initializing it:

mkdir golioth-demo
cd golioth-demo
npm init -y

Install the basic dependencies:

npm install dotenv
npm install --save-dev typescript tsx @types/node

Initialize TypeScript:

npx tsc --init

We now have a minimal TypeScript-enabled Node.js project, let’s start integrating!

2. Store your API key context using a .env file

The Golioth API requires an API key to be passed in a header. You should never hardcode a secret key into your code, as it can easily fall into the wrong hands. Instead, you can set up your application to pull the secret from the execution environment, which allows you to keep your API keys stored in your deployment environment, and use different credentials in different environments.

API keys can only be used to access APIs for the project they’re attached to. To keep things portable, we’ll put the project and organization IDs in the environment as well, allowing our application to work with any project without having to change the code.

A common solution for managing growing execution environments is to add a .env file in the project root:

GOLIOTH_API_KEY=your-api-key
GOLIOTH_ORG=your-org-id
GOLIOTH_PROJECT=your-project-id

Then load it in your application’s src/index.ts using dotenv:

import 'dotenv/config';

Now your API key is available at runtime as:

process.env.GOLIOTH_API_KEY

⚠️ Warning:

The .env file should never be committed to source control in your repository, and it’s best to add it to your .gitignore right away.

3. Generate TypeScript bindings from the OpenAPI spec

To generate the TypeScript bindings for the Golioth API, we’ll use the Swagger TypeScript API package. This provides a flexible set of configuration parameters that allows us to fine tune the generated TypeScript code to make the Golioth API integration as simple as possible.

First, we’ll need to install the generator:

npm install --save-dev swagger-typescript-api

Although swagger-typescript-api can be run as a command line tool with npx, it’s easier to set up its configuration by wrapping it up in a little script that runs the code generation. It’ll also allow us to tweak the generated code a bit.

Create a scripts directory at the root of your repository, and add the following to a TypeScript file named golioth.ts:

 

import path from "node:path";
import { generateApi } from "swagger-typescript-api";

const fromEnv = {
    projectId: "GOLIOTH_PROJECT",
    organizationId: "GOLIOTH_ORG",
};
type PName = keyof typeof fromEnv;

generateApi({
    url: "<https://api.golioth.io/openapi.json>",
    apiClassName: "Golioth",
    output: path.resolve("src/api"),
    fileName: "golioth.ts",

    // split API into modules:
    moduleNameFirstTag: true,
    // Unwrap the json data in the response:
    unwrapResponseData: true,

    // Skip predefined parameters:
    hooks: {
        onCreateRoute(routeData) {
            routeData.request.parameters =
                routeData.request.parameters?.filter(
                    (p) => !fromEnv[(p as { name: PName }).name]
                ) ?? [];
            return routeData;
        },
        onInsertPathParam(paramName) {
            if (paramName in fromEnv) {
                return `process.env.${fromEnv[paramName as PName]}`;
            }
        },
    },
});

 

The configuration is fairly straight forward, but the hooks are an important addition here: The keys in the fromEnv object will be replaced with their mapped environment variables. We’ll get to why that’s important in a little bit!

Finally, add this as a script in your package.json:

    // ...
    "scripts": {
        // ...
        "generate:golioth": "tsx scripts/golioth.ts"
    }
}

 

And run the script to generate the TypeScript bindings:

npm run generate:golioth

After this completes, a new golioth.ts file gets added to src/api, containing several thousand lines of type definitions, including a Golioth class, which we’ll use to instantiate our API.

💡 Note:

It’s good practice to commit the generated file to source control, as the Golioth API is actively being developed, with new methods and parameters being added continuously.

Although generating the file locally (as a postinstall script, for example) would let your type definition stay up to date with the latest additions to the Golioth API, it adds a risk of having different type definitions in different development environments.

By committing the generated output and making a habit of regenerating the API at regular intervals, you’ll ensure a reproducible environment for your development and testing.

4. Create and configure the Golioth API client

With the generated bindings and API key in place, creating a client is straightforward.

We find it’s cleanest to instantiate the Golioth client in a separate file, and export it as a const. Create a new file called src/golioth.ts:

import { Golioth } from "./api/golioth";

export const golioth = new Golioth({
    baseApiParams: {
        headers: {
            // Pulling the API key from the execution environment:
            "X-Api-Key": process.env.GOLIOTH_API_KEY,
        },
    },
});

At this point, you already have:

  • Authentication wired up
  • A fully typed API client
  • Editor autocomplete for all endpoints

5. Make your first API call

Let’s make a simple request to verify everything works.

For example, fetch a list of devices in your project:

import 'dotenv/config';
import { golioth } from "./golioth"

async function listDevices() {
    const devices = await golioth.devices.devicesList();

    devices.list?.forEach(device => {
        console.log(`- ${device.id}: ${device.name}`);
    })
}

listDevices().catch(console.error);

Notice a few things:

  • The method names come directly from the OpenAPI spec
  • Response objects are fully typed
  • TypeScript helps you discover fields without checking the docs

This is also where the hooks in the configuration come in to make life a little easier for us! All Golioth APIs are prefixed with a project ID (and occasionally, an organization ID), and the hooks we added let us skip these parameters in the function call.

Summary

In just a few steps, we:

  • Created a TypeScript Node.js project
  • Generated strongly typed API bindings from Golioth’s OpenAPI definition
  • Secured our API key using environment variables
  • Made our first request to the Golioth Management API

If you’re building a backend service and want a type-safe, low-friction way to integrate with Golioth, we think this is the fastest way to get started.

Happy building!

Trond Snekvik
Trond Snekvik
Trond is the lead frontend developer at Golioth. Despite his love for Typescript, he has extensive experience with embedded systems, and wrote a master thesis about building mesh networks on top of Bluetooth. During his 10 years at Nordic Semiconductor, Trond worked on the Bluetooth Mesh SDK and served as a Zephyr code owner, before turning to the dark side to build VS Code extensions for Zephyr. Trond enjoys pancakes, dogs, and cross country skiing.

Post Comments

No comments yet! Start the discussion at forum.golioth.io

More from this author

Related posts

spot_img

Latest posts

Find Breaking Changes in Zephyr Using Git Bisect

Finding breaking changes in upstream code is a difficult process. Git bisect and good commit discipline (like the Zephyr team maintains) helps to quickly pinpoint issues so you can pull in changes as needed.

A Physical Meme Terminal for Distributed Teams

Have you ever wanted to bypass slack and send a meme directly to your co-worker's desk? This hack day project builds on top of work from 2022 and pulls in some new features of Golioth's IoT platform, as well as some vibe coded front end / back end work to make the experience smoother. Dive into each part of the project in this blog and associated video.

Golioth Firmware SDK v0.22.0

The latest release of the Golioth Firmware SDK includes support for rotating certificates via Golioth’s integration with external PKI providers, routes logs through Pipelines, and reorganizes our firmware update reference implementation.

Want to stay up to date with the latest news?

Subscribe to our newsletter and get updates every 2 weeks. Follow the latest blogs and industry trends.