Upgrading from earlier version

Upgrading your project

In this section, we will discuss changes and upgrade advice for users upgrading from versions of Nitric reliant on a nitric.yaml file.

What you'll learn

  • Install the new Nitric CLI
  • Upgrade existing Nitric projects

What's changed?

The Node SDK now uses a 'Config-as-Code' design pattern.

  • Resources, permissions and configuration will infer automatically from your code.

The API definitions have minor changes to support the new pattern.

  • Examples on how to use the API can be found in the documentation.

Why the change?

Config as code is an expressive and self-documenting pattern. Save time by not having to read through pages of documentation or manage 1000s of lines of config.

Examples include:

  • Resource definition yaml
  • OpenAPI 3.0 specifications
  • Resource permission yaml or configuration screens

Install the new Nitric CLI

The Nitric CLI is no longer distributed via NPM. A fresh installation is necessary.

Uninstall the existing CLI with NPM or manually if you didn't start with NPM.

  npm uninstall -g @nitric/cli

Remove any config folders such as '/home/user-name/.nitric'

Follow our installation guide to set up the Nitric CLI.

Upgrade existing Nitric projects

If projects don't have a nitric.yaml file, where do the resources get defined?

All resources (topics, queues, collections, buckets, apis, api routes and methods, schedules and secrets) are defined by your code.

// A topic named updates will be created on deploy
const updates = topic('updates')

// A queue named batch will be created on deploy
const batchQueue = queue('batch')

// Create an auto-scaling secure API named 'public'
const publicApi = api('public')

// Create profile with POST method on path /examples
publicApi.post('/examples', async (ctx) => {
  ...
})

// Create profile with GET method on path /examples
publicApi.get('/examples', async (ctx) => {
  ...
})

Refactoring functions

Refactor functions into middleware handlers which can be executed as API methods, topic subscriptions and schedules.

Before

// Start your function here
faas.http(async (ctx: faas.HttpContext): Promise<faas.HttpContext> => {
  // Handler code goes here
})

After

const publicApi = api('public')

// Create profile with post method
publicApi.post('/examples', async (ctx) => {
  // Handler code goes here
})
// Create a schedule that runs every 5 minutes
schedule('process-transactions').every('5 minutes', async (ctx) => {
  // Handler code goes here
})
// Subscribe to a topic
updates.subscribe(async (ctx) => {
  // Handler code goes here
})

Complete refactoring example

The example is a POST request of an API which creates a record in a Collection.

We'll go from code, yaml, and OpenAPI to just code.

Before

// example.ts

interface Example {
  name: string
  description: string
}

import { faas, documents } from '@nitric/sdk'
import { uuid } from 'uuidv4'

interface CreateContext extends faas.HttpContext {
  req: faas.HttpRequest & {
    body?: Example
  }
}

// Start your function here
faas
  .http(
    faas.json(), //  use json body parser middleware to decode data
    async (ctx: CreateContext): Promise<faas.HttpContext> => {
      const example = ctx.req.body

      // Create a new example document
      await documents().collection('examples').doc(uuid()).set(example)
    }
  )
  .start()
# nitric.yaml

name: examples
# Nitric functions
functions:
  create:
    handler: functions/create.ts
# Nitric collections
collections:
  examples: {}
# Nitric APIs
apis:
  examples: api.yaml
# api.yaml

openapi: 3.0.0
info:
  version: 1.0.0
  title: Example API
  description: Example API
paths:
  /examples:
    post:
      operationId: examples-create
      x-nitric-target:
        name: create
        type: function
      description: Creates and persists new examples
      responses:
        '200':
          description: Successful response
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExamplesCreate'
components:
  schemas:
    ExamplesCreate:
      type: object
      properties:
        name:
          type: string
        description:
          type: string

After

// example.ts

import { api, collection } from '@nitric/sdk'
import { uuid } from 'uuidv4'

// Create an auto-scaling secure API
const publicApi = api('public')

// Access profile collection with permissions
const examples = collection('examples').for('writing', 'reading')

// Create profile with post method
publicApi.post('/examples', async (ctx) => {
  let name = ctx.req.json().name
  let description = ctx.req.json().age

  // Create the new profile
  await examples.doc(name).set({ name, description })
})
# nitric.yaml

name: examples
handlers:
  - functions/*.ts