Building Blocks

Building Blocks - APIs

Nitric APIs make it dead simple to define and map functions to HTTP APIs.

Concepts

Request Context

Nitric's way of handling requests and responses was inspired by a common pattern from frameworks like Koa and Next.js edge functions. We provide a single context object that gives you everything you need to read requests and write responses.

Creating a new API

APIs are easy to declare with the Nitric SDK

JavaScript
Python
import { api } from '@nitric/sdk';

const galaxyApi = api('far-away-galaxy-api');

Routing

You define your HTTP routes and the functions that handle incoming requests using methods on your API objects, for example, post(). When calling the methods you provide the path/pattern to match on and a handler callback function.

The commonly used HTTP methods used for APIs are GET, POST, PUT, PATCH and DELETE.

JavaScript
Python
// List planets
galaxyApi.get('/planets', async (ctx) => {
  // get a list of planets
  const planets = getPlanetsList();
  ctx.res.json(planets);
  return ctx;
});

// Create planets
galaxyApi.post('/planets', async (ctx) => {
  const data = ctx.req.json();
  // create a new planet
  createPlanet(data);
  ctx.res.status = 201;
  return ctx;
});

Handling parameters

The string used to match HTTP routes can include named parameters. The values collected from those parameters are included in the context object under ctx.req.params with the name provided in the route definition.

JavaScript
Python
galaxyApi.get('/planets/:name', async (ctx) => {
  const { name } = ctx.req.params;
  // get a specific planet
  const planet = getPlanet(name);
  // set the response as json
  ctx.res.json(planet);
  return ctx;
});

galaxyApi.patch('/planets/:name', async (ctx) => {
  const { name } = ctx.req.params;
  const update = ctx.req.json();
  // update a specific planet
  updatePlanet(name, update);
  return ctx;
});

galaxyApi.delete('/planets/:name', async (ctx) => {
  const { name } = ctx.req.params;
  // delete a specific planet
  deletePlanet(name);
  return ctx;
});

Setting HTTP status and headers

The response object provides status and headers properties you can set to return an HTTP status code such as 201 or 404 and appropriate headers.

JavaScript
Python
galaxyApi.get('/planets/alderaan', async (ctx) => {
  ctx.res.status = 301;
  ctx.res.headers['Location'] = ['https://example.org/debris/alderann'];
  return ctx;
});

Securing the API

APIs can include security definitions for OIDC-compatible providers such as Auth0, FusionAuth and AWS Cognito.

A securityDefinitions object can be provided to start defining the auth requirements of your API. security rules can also be specified on the API to apply a security definition to the entire API. The security definition defines the kind of auth and the configuration required. For a JWT this configuration is the JWT issuer and audiences. The security object defines the required scope to access that resource.

For a more in depth tutorial look at the Auth0 integration guide

JavaScript
Python
const helloApi = api('main', {
  security: {
    user: ['user.read'],
  },
  securityDefinitions: {
    user: {
      kind: 'jwt',
      issuer: 'https://dev-abc123.us.auth0.com',
      audiences: ['https://test-security-definition/'],
    },
  },
});

Overriding API-level security

Individual routes can also have their own security rules applied for any securityDefinition supplied at the API level.

JavaScript
Python
galaxyApi.get('planets/unsecured-planet', async (ctx) => {}, {
  // override top level security, and apply no security to this route
  security: {},
});

galaxyApi.post('planets/unsecured-planet', async (ctx) => {}, {
  // override top level security to require user.write scope to access
  security: {
    user: ['user.write'],
  },
});

Defining Middleware

APIs support middleware at the API level and the route level. Middleware functions are supplied an HttpContext object and a next() function which calls the next middleware in the chain.

JavaScript
Python
const validate = (ctx, next) => {
  // Perform request validation, etc.
  next();
};

API level middleware

Middleware defined at the API level will be called on every request on to every route.

JavaScript
Python
import { api } from '@nitric/sdk';
import { validate, logRequest } from '../middleware';

const customersApi = api('customers', {
  middleware: [logRequest, validate],
});

Route level middleware

Middleware defined at a route level will only be called for that route.

JavaScript
Python
import { api } from '@nitric/sdk';
import { validate } from '../middleware';

const customersApi = api('customers');

const getAllCustomers = (ctx) => {};

// Inline using .get()
customersApi.get('/customers', [validate, getAllCustomers]);

// Using .route()
customersApi.route('/customers').get([validate, getAllCustomers]);