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 upgrade 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 withservices
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 thestart
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 do not support querying, and are instead designed to be used as a efficient key/value store.
- 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
andusers: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.