Upgrading Nitric projects from v0.x to v1.x

Overview

Nitric v1.x introduces a number of breaking changes from v0.x. However, in most cases the changes are relatively minor and can be easily applied to existing projects. This guide will help you upgrade your existing Nitric projects to v1.x.

Upgrading the Nitric CLI

The first step in upgrading your project is to upgrade the Nitric CLI. You can do this by running the following command:

brew install nitrictech/tap/nitric

Upgrading Nitric Projects

Updating Project Configuration

The format of the nitric.yaml file has changed in v1.x. The new format is more flexible and allows for more complex project configurations. The new format is as follows:

name: my-project
services:
- match: ./services/*.ts
start: yarn dev:function $SERVICE_PATH

The notable changes are:

  • The functions key has been replaced with services to better reflect the broad range of solutions that Nitric supports.
  • Service type definitions include a match key that specifies the file pattern to match for the service type.
  • Service type definitions also includes a start key that specifies the command to run to start the service.
  • A $SERVICE_PATH environment variable is available to the start command which will specify the relative filepath of each matched service.

If you have an existing nitric.yaml file, the before and after for the upgrade would look something like this:

Before

name: my-project
handlers:
- functions/*.js

After

name: my-project
services:
- match: ./functions/*.js
start: yarn dev:function $SERVICE_PATH

Where the yarn dev:function is a command capable of starting the function in development mode, for example:

{
"scripts": {
"dev:function": "nodemon -r -q dotenv/config"
}
}

Previous versions of Nitric relied on two terminal windows to run applications locally. This is no longer the case, and the nitric start command will start all services in a single terminal window. This also means that the index file that was previously provided in the templates is no longer required.

Upgrading Stack Files

There is one minor change to the inner format of stack files in v1.x, as well as a new naming convention for stack files. While v0.x stack files were named nitric-mystack.yaml, v1.x stack files are named nitric.mystack.ts (replacing the first dash with a dot). The only change to the inner format of the files is removal of the name key, which is no longer required or supported. The name of the stack will be now always be inferred from the filename, to avoid confusion and naming conflicts.

v0.x providers are not compatible with nitric v1.x. The provider version referenced in the stack files will also need to be upgraded.

Upgrading Nitric APIs

While Nitric APIs remain largely unchanged in v1.x, there is a change to the way security definitions are created and applied to APIs and their routes. In v0.x, security definitions were created when defining an API, then separately applied either to the API, routes or both. The original code for this might have looked something like this:

const helloApi = api('main', {
security: {
// only authorize requests with the 'user.read' scope
user: ['user.read'],
},
securityDefinitions: {
user: {
kind: 'jwt',
issuer: 'https://dev-abc123.my.issuer.com',
audiences: ['https://test-security-definition/'],
},
},
})

The issue with this approach is that it was easy to create a security definition and not realize it needed to be applied to take effect.

For example, this code would create a security definition but not apply, resulting in an API that was not secure:

const helloApi = api('main', {
// Note: no security key
securityDefinitions: {
user: {
kind: 'jwt',
issuer: 'https://dev-abc123.my.issuer.com',
audiences: ['https://test-security-definition/'],
},
},
})

In v1.x security definitions, now called rules, are created as standalone objects and then applied to the API or route. This ensures security definitions that have not been applied are more obvious and less likely to be overlooked.

The new code for the above example would look like this for an OpenID Connect (OICD) Rule:

import { oidcRule, api } from '@nitric/sdk'
const userAccessRule = oidcRule({
name: 'user',
audiences: ['https://test-security-definition/'],
issuer: 'https://dev-abc123.my.issuer.com',
})
const helloApi = api('main', {
security: [userAccessRule('user.read')],
})

Upgrading Nitric Functions

Nitric Functions have been renamed to Nitric Services. While in practice this change is mostly cosmetic, it serves to disambiguate the different elements of a Nitric application. Each service is an entrypoint to a Nitric application and typically represents a single deployed container image. These images could always include multiple functions, which is where confusion could arise.

Upgrading Queues

Nitric Queues have been simplified in v1.x. They also include some changes in nomenclature. The send method has been renamed to enqueue and the receive method has been renamed to dequeue. While the messages sent to queues were typically referred to as "tasks" in v0.x, they are now referred to as "messages" in v1.x.

Lastly, messages sent to queues used to require common properties such as id and payloadType. These properties are no longer used by the Nitric SDK, however, you're free to reintroduce them as you see fit or leave them out entirely.

Upgrading Topics

As with Queues, Nitric Topics have also been simplified in v1.x. The messages sent to topics were typically referred to as "events" in v0.x, they are now referred to as "messages" in v1.x. They also no longer automatically include or generate an id property or other properties such as payloadType. As with Queues, you're free to reintroduce these properties as you see fit or leave them out entirely.

Changing from Collections to Key/Value

The most significant change in Nitric v1.x is the change from Collections to Key/Value. Collection resources are no longer supported or deployed by Nitric, instead they've been superseded by Key/Value resources. Nitric always strives to provide the most consistent experience across all supported cloud providers, and this change was made to better reflect the capabilities of the underlying cloud providers, while also greatly improving the breadth of options available to fulfill the underlying requirements.

The primary differences between Collections and Key/Value are:

  • Key/Value stores, designed for efficient key/value storage rather than complex querying, now feature a keys method to facilitate the retrieval of all available keys within the store, you can also filter them via a prefix.
  • Key/Value stores do not support sub-collections.
  • For Azure deployments Key/Value stores are backed by Azure Table Storage, instead of the MongoDB deployments used for Collections.

The switch from MongoDB to Azure Table Storage for Key/Value stores significantly improves deployment times Azure and reduces runtime costs.

To migrate from Collections to Key/Value, you will need to:

  • Use alternate mechanisms or persistence if querying is required.
  • Flatten any sub-collections into a single collection. One approach to this is to use a delimiter in the key to represent the sub-collection, for example users:123 and users:123:posts:456.

While we're not aware of projects with heavy reliance on the features of Collections that have been removed, if you have such a project, please reach out to us and we'll be happy to help you migrate to a solution that meets your needs or provide guidance on what can be achieved with Key/Value stores.

Last updated on Dec 5, 2024