Open, source-available — the new KeygenStar us on GitHub arrow_right_alt

Upgrading your Keygen API Integration from v1.0 to v1.1

Wednesday, June 1st 2022

With the release of API version v1.1, a number of backwards-compatible breaking changes were made to Keygen's API. That may seem like a stark contradiction, but it's not. We've built our API in a way where breaking changes can be made without disrupting API consumers on older versions. We are able to accomplish this using an API versioning system, inspired by how Stripe does API versioning.

We'll dive deeper into the technical details of how our versioning system works in a later blog post. But today, we'll be going over what changes have been made, and how API consumers currently on v1.0 can migrate to v1.1.

(Update: check out our deep dive into API versioning.)

What's changed in v1.1?

If you haven't already, please take a peek at our changelog, which covers the breaking changes made to our API in v1.1. As you may see, quite a bit has changed.

The bulk of these changes concern our distribution API. The gist is that our original object modeling for releases and artifacts left a lot to be desired, and had some problems. Namely, the one-to-one relationship between a release and an artifact. We've changed that relationship, so now, releases have many artifacts. That, in addition to moving quite a few attributes from the release object to the artifact object, make up the bulk of v1.1's changeset. As such, key flows for our distribution API have changed.

Sometimes we don't get things right on the first try, so we've spent some time refactoring the object model to be clearer, which will open up official support for npm, rubygems, pip, composer, and other packages soon.

More on that later. Today, let's stick to upgrading.

Upgrading your publishing flow

Moving forward, you will want to adjust your publishing procedure to use v1.1 of Keygen's API. For most integrations, this will consist of only creating a single versioned release and then filling that release with artifacts, as opposed to multiple versioned releases, each with their own artifact. Finally, you'll publish and tag the release.

This new publishing flow will consist of the following steps:

1. Create a release

The first step is creating a release. This will create a new versioned "bucket" for you to add artifacts to. This can be done using the create release endpoint, or using the CLI's keygen new command. The new release will be in a draft state.

What's changed? In v1.0, you would create a release for every artifact. With v1.1, you create a single release and add many artifacts to it.

Using the CLI, a good recipe for this is to run the following:

keygen new \
--channel 'stable' \
--version '2.0.0'

2. Upload artifacts

The next step is uploading your artifacts. Remember, releases can have many artifacts now. This can be done using the upload artifact endpoint, or using the CLI's keygen upload command.

What's changed? In v1.0, you would upload an artifact for each release. With v1.1, you upload many artifacts for a single release.

Using the CLI, a good recipe for this is to run the following for each artifact:

keygen upload ./build/keygen_linux_amd64 \
--release '2.0.0' \
--platform 'linux' \
--arch 'amd64'
keygen upload ./build/keygen_darwin_amd64 \
--release '2.0.0' \
--platform 'darwin' \
--arch 'amd64'
# …

3. Publish the release

The final step is publishing a release. Unlike v1.0, releases are no longer automatically marked as published. They must be explicitly published. Releases in a draft state will be unlisted, unavailable for download and inelligible for upgrades. This can be done using the publish release action, or using the CLI's keygen publish command.

What's changed? In v1.0, releases were automatically published after its artifact was uploaded. With v1.1, releases must be explicitly published.

Using the CLI, a good recipe for this is to run the following:

keygen publish --release '2.0.0'

Publishing a release will immediately make it available for download, also making it elligible for automatic upgrades.

4. Tag the release

As part of your publishing process, you can now add an optional tag to your release. For example, with our CLI, we utilize a latest tag, which points to our latest release, allowing us to link to the latest installer like this:

curl -sSL | sh

This step can be done using the update release endpoint, or by using the CLI's keygen tag and keygen untag commands.

What's changed? Nothing — in v1.0, releases did not have tags.

Tags must be unique, so if you're using a latest tag, the previous tag must be untagged before a newer release can utilize the latest tag. Using the CLI, a good recipe for this is to run the following:

keygen untag --release 'latest'
keygen tag 'latest' --release '2.0.0'

This will untag the current latest release and then tag 2.0.0 as latest.

This is an optional step. Tags are not required.

Upgrading your app's integration

With API version pinning, your account is pinned to the then-current API version after its first request. This means that unless your account was created after v1.1 was released, your account is likely pinned to v1.0. This is why nothing broke within your integration when we released v1.1, even though we made quite a few breaking changes.

Rather than change your account's pinned version, breaking your current integration, we'll be using the Keygen-Version header to request the newer version, overriding your account's pinned version on a per-request basis.

We can change your account's pinned version at the end.

1. Pin your app's API version

The first thing we'll want to do is create a new patch release that pins all current API requests made by the application to v1.0. This should be a mandatory patch upgrade for all clients, eventually allowing you to change your pinned version to v1.1.

You can pin the application's API version by using the Keygen-Version header in all API requests made by the application.

Keygen-Version: 1.0

The above header will pin requests to v1.0, regardless of whether or not your account's pinned version ever changes.

Publish this change as a mandatory patch upgrade. You'll want to ensure that this version cannot be skipped during upgrades.

2. Upgrade your app's API version

Next, we'll want to upgrade your app's API version. Similarly to the previous step, we'll use the Keygen-Version header to pin your app to v1.1. The header below will pin all requests to v1.1, regardless of whether or not your account's pinned version ever changes again in the future (for example, when we release v1.2).

Keygen-Version: 1.1

Another part of this upgrade will be changing how your app performs automatic upgrades, given it was using the now-deprecated release upgrade action. This will need to be replaced by the new upgrade release endpoint.

As an example, let's assume our app wants to upgrade from v1.0.0 to v2.0.0. Let's also assume previous versions were utilizing the upgrade action as follows:

GET /releases/actions/upgrade?version=1.0.0&filetype=zip&platform=darwin&channel=stable&product=XXX

Instead, we will want to perform 2 requests. First, we'll want to get the latest version of a product by using the current release's upgrade endpoint:

GET /releases/1.0.0/upgrade

Next, let's assume this responded with a v2.0.0 release object. We'd use that version to download the artifact our platform requires, e.g. a zip file on macOS:

GET /releases/2.0.0/artifacts/

From there, we would install and apply the upgrade as we did previously. Same result, but much less magic and with a cleaner API.

If you're planning on using the new arch resource and attribute, this release's artifacts should not utilize the arch attribute yet. If you utilize the new arch attribute, previous versions of your app will not find the new release during an upgrade, since the deprecated upgrade action does not support arch.

As an example, when we upgraded our CLI's API integration from v1.0 to v1.1, our artifacts changed from a combined {platform}/{arch} naming scheme to a separate platform and arch, e.g. from platform=darwin/amd64 to platform=darwin and arch=amd64.

This meant that previous versions would no longer find matching upgrades, since the platform format had changed, i.e. upgrades for platform darwin/amd64 would not match darwin. So this change must be done incrementally.

We'll introduce support for arch in step 3.

You will also want to note any other changes, detailed in our changelog, such as the attribute changes for the release and artifact objects. Please note any and all changes to ensure that nothing breaks within your integration.

Publish this change as part of your normal release cycle, after step 1. Again, you'll want to ensure that this version cannot be skipped during upgrades.

3. Changing platform format

Once the majority of your users have upgraded and your app is primarily making API requests to API version v1.1, we can now safely introduce support for the arch attribute.

For example, if your app previously used the following platform:

"platform": "darwin/amd64",
"arch": null

It would now be safe to introduce a new format:

"platform": "darwin",
"arch": "amd64"

This is because the newer upgrade endpoint no longer requires a platform parameter, rather it is simply based on version. An upgrade will now return the newer release object, and that object can be used to request the appropriate artifact for the current env.

Any lingering upgrades from previous versions still on API version v1.0 will upgrade to the last version using the darwin/amd64 platform, then upgrading a second time to the newest version using the new platform and arch format.

To prevent this double upgrade, make the release that went from API version v1.0 to v1.1 another mandatory upgrade.

Publish this change as part of your normal release cycle, after step 1 and 2. Ensure that this version cannot be skipped during upgrades.

4. Upgrade your account's API version

Once you have confirmed that all API requests are now using v1.1, you can upgrade your account's pinned version via your account settings. In addition to changing your account's pinned version, you can also use this time to upgrade the API version for your webhook endpoints to v1.1, noting the structural changes for the release and artifact objects.

This final step is optional. Feel free to stay on v1.0 indefinitely.

In conclusion

Today, we learned how to migrate from v1.0 to v1.1 of Keygen's API. At the end of this upgrade, all of your users should now be using the newer v1.1 API. If you have any questions about this process, please reach out.

Until next time.