In a previous post we looked at how to author an API specification locally and save to Anypoint Design Center, as well as how to manually sync changes made on the Anypoint platform to your local computer.
One of the benefits of maintaining the API specification on your local computer is to be able to save the specification in source control. The Anypoint platform provides a feature called GitHub Synchronization which will automatically sync changes to the specification from Design Center to GitHub and vice versa. This feature can remove the need to use the Anypoint CLI, however it does have the following limitations:
- The feature only works with GitHub
- The feature requires administrator access to a GitHub organization and doesn’t work with individual accounts without a GitHub organization
- The feature saves the specification files to the root of the GitHub project and at the time of writing this post, the directory is not customizable
In this post we will look at an approach for automating the API specification sync between Anypoint Design Center and GitHub using GitHub Actions. While GitHub Actions are specific to GitHub, the techniques can be applied to other build tools that work with a variety of git hosting providers.
Prerequisites
- GitHub account
- Admin access to Anypoint platform, such as an Anypoint platform trial account
- Complete Step 2 of the previous post to create the connected app in Anypoint and copy the App Id, App Secret and your Anypoint Organization Id
- Complete Step 3 of the previous post to create an API project in Anypoint design center named “pet owners-api”
Step 1: Add Secrets to GitHub
In GitHub, navigate to Settings -> Secrets -> Actions. Create the following Repository Secrets
- ANYPOINT_ORG_ID: paste your Anypoint Organization Id
- ANYPOINT_CONNECTED_APP_ID: paste your Anypoint connected app Id
- ANYPOINT_CONNECTED_APP_SECRET: paste your Anypoint connected app secret
Step 2: Sync the OpenAPI Specification from Anypoint Design Center to GitHub
In this scenario, we are using the Anypoint Design Center to edit the OpenAPI spec and we want to bring the updates into GitHub for peer review and approval.
Create a new file in the GitHub project: .github/workflows/oas-retrieve-anypoint.yml
Add the following text to the file
name: OpenAPI Spec Retrieve from Anypoint
on:
workflow_dispatch:
inputs:
git_committer_name:
description: 'Name to use for the commit'
required: true
default: 'GitHub Actions'
type: string
git_committer_email:
description: 'Email to use for the commit'
required: true
default: '[email protected]'
type: string
jobs:
retrieve-from-anypoint-platform:
runs-on: ubuntu-latest
steps:
# Install nodejs 16
- name: "Install Node.js"
uses: actions/setup-node@v3
with:
node-version: 16
# Install Anypoint CLI and relevant plugins
- name: "Install Anypoint CLI"
run: |
npm install -g anypoint-cli-v4
anypoint-cli-v4 plugins:install anypoint-cli-account-plugin
anypoint-cli-v4 plugins:install anypoint-cli-designcenter-plugin
anypoint-cli-v4 --version
anypoint-cli-v4 plugins --core
# Checkout the source code
- name: "Checkout Source Code"
uses: actions/checkout@v2
# Save temporary branch name as environment variable
- name: Set Temporary Branch Name
id: dateTime
run: echo "branch_name=oasSync/anypoint-download-$(date +'%Y-%m-%d-%H-%M-%S')" >> $GITHUB_ENV
# Create new branch starting with 'oasSync/anypoint-download'
- name: Create Temporary Branch
run: git checkout -b ${{ env.branch_name }}
# Download OpenAPI spec
- name: Download OpenAPI Spec from Anypoint Design Center
run: anypoint-cli-v4 designcenter:project:download --client_id ${{secrets.ANYPOINT_CONNECTED_APP_ID}} --client_secret ${{secrets.ANYPOINT_CONNECTED_APP_SECRET}} --organization ${{secrets.ANYPOINT_ORG_ID}} pet-owners-api ./docs/oas
# Configure Git for commits
- name: Initialize mandatory git config
run: |
git config user.name ${{inputs.git_committer_name}}
git config user.email ${{inputs.git_committer_email}}
# Commit changes and push to origin
- name: Commit Changes
id: make-commit
run: |
git add .
git commit --message "Adding changes retrieved from Anypoint platform"
echo "::set-output name=commit::$(git rev-parse HEAD)"
git push origin ${{ env.branch_name }}
# Create new pull request
- name: Create Pull Request
run: echo "pr_number=$(gh pr create -B main -H ${{ env.branch_name }} --title '${{ env.branch_name }} into main' --body 'Created by GitHub Action' | cut -d'/' -f7)" >> $GITHUB_ENV
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
# Merge pull request and delete temporary branch
- name: Merge Pull Request and Delete Temporary Branch
run: gh pr merge ${{env.pr_number}} --rebase --delete-branch
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
Workflow Highlights
- Runs when triggered by a user in the GitHub web UI and accepts input parameters for the name and email to use for make the git commits.
- Installs the Anypoint CLI and dependencies in the runner environment.
- Creates a new branch with a naming convention that starts with oasSync so that it is clear where the change is originating from.
- Downloads the OpenAPI specification, commits the changes, pushes to the GitHub project and opens a pull request
- The final step of automatically merging the pull request to the main branch is optional and may not be a good fit with your process if you want to ensure peer review.
Step 3: Sync the OpenAPI Specification from GitHub to Anypoint Design Center
In this scenario, we are developing the specification locally and using a traditional process of pushing the changes to the GitHub project and opening a pull request.
Create a new file in the GitHub project: .github/workflows/oas-deploy-main.yml
Add the following text to the file
name: OpenAPI Spec Deploy
on:
workflow_dispatch:
pull_request:
types:
- closed
branches:
- main
paths:
- 'docs/oas/**'
jobs:
deploy-to-anypoint-platform:
# check if pull request was merged & ignore branches that begin with oasSync/anypoint-download
if: ${{ github.event.pull_request.merged == true && !startsWith(github.head_ref, 'oasSync/anypoint-download') }}
runs-on: ubuntu-latest
steps:
# Checkout the source code
- name: "Checkout Source Code"
uses: actions/checkout@v2
# Install nodejs 16
- name: "Install Node.js"
uses: actions/setup-node@v3
with:
node-version: 16
# Install Anypoint CLI and relevant plugins
- name: "Install Anypoint CLI"
run: |
npm install -g anypoint-cli-v4
anypoint-cli-v4 plugins:install anypoint-cli-account-plugin
anypoint-cli-v4 plugins:install anypoint-cli-designcenter-plugin
anypoint-cli-v4 --version
anypoint-cli-v4 plugins --core
# Upload OpenAPI spec
- name: Upload OpenAPI Spec to Anypoint Design Center
run: anypoint-cli-v4 designcenter:project:upload --client_id ${{secrets.ANYPOINT_CONNECTED_APP_ID}} --client_secret ${{secrets.ANYPOINT_CONNECTED_APP_SECRET}} --organization ${{secrets.ANYPOINT_ORG_ID}} pet-owners-api ./docs/oas
Workflow Highlights
- Runs only when a pull request that is targeted to the main branch is closed and merged and when there is a change to the directory where we are storing the specification.
- Checks that the branch being merged (head) does NOT start with “oasSync/anypoint-download” so that we aren’t firing the workflow to upload changes to Anypoint when the changes originated from the platform; essentially avoiding circular actions.
- Installs the Anypoint CLI and dependencies in the runner environment.
- Uploads the changed specification to Anypoint Design Center.
Summary
By using GitHub Actions we are able to take advantage of all of the API specification development features of the Anypoint platform while ensuring that GitHub remains the source of truth for the specification file.
Resources
- Sample Project: https://github.com/aaronwinters/pet-owners-api
- GitHub Actions: setup-node Action
- GitHub Blog: Input Types for Manual Workflows
- GitHub Docs: Using Conditions to Control Job Execution
- GitHub Docs: Passing Values between Steps and Jobs in a Workflow