This article is a continuation of Create OpenAPI spec for Django REST Framework APIs and Automatically create an API client from an OpenAPI spec, where creating OpenAPI specs for Django REST Framework APIs and generating Angular API clients from them were discussed.
I recently automated this entire process using GitHub Actions. Here's how it works: whenever a new release is published on the Django backend, the workflow automatically:
- Generates the OpenAPI specification
- Uploads it to the GitHub release
- Generates the Angular API client
- Publishes it to NPM
Implementation Details
The workflow requires some secrets:
NPM_TOKEN
: Must be configured as a repository secret in GitHub. This token is used for publishing the Angular API client to NPM and can be generated from your NPM account settings.GITHUB_TOKEN
: Automatically provided by GitHub Actions, used for uploading the OpenAPI spec to the release.
They need to be added to the repository secrets in the GitHub repository settings.
The workflow leverages the ubuntu-latest
runner, which comes with Docker pre-installed. This allows us to reuse the Docker image from the previous article for generating the Angular API client.
You can see the complete implementation in these pull requests:
- Add OpenAPI spec generation to release
- Add steps to generate Angular API client and publish it to NPM
Automated updates
As an added benefit, with dependabot enabled in the repository, it automatically creates pull requests to update the Angular API client in the frontend repository whenever a new version is published.
Full Workflow Code
Since this is probably going to change in future, here is the code of the current workflow:
name: Generate OpenAPI
on:
release:
types: [published]
jobs:
openapi:
runs-on: ubuntu-latest
env:
DEBUG: True
RUN_MODE: production
SECRET_KEY: changeme!
ALLOWED_HOSTS: localhost,127.0.0.1
DATABASE_URL: sqlite:////tmp/db.sqlite3
CORS_ORIGIN_WHITELIST: "http://localhost,http://127.0.0.1"
CSRF_TRUSTED_ORIGINS: "http://localhost"
REGISTER_VERIFICATION_URL: "http://localhost:4200/verify-user/"
RESET_PASSWORD_VERIFICATION_URL: "http://localhost:4200/reset-password/"
REGISTER_EMAIL_VERIFICATION_URL: "http://localhost:4200/verify-email/"
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements/base.txt
- name: Generate OpenAPI
run: python manage.py spectacular --file schema.yml
working-directory: snypy
- name: Upload to release
uses: JasonEtco/upload-to-release@master
with:
args: ./snypy/schema.yml text/yaml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Verify Docker installation
run: |
docker --version
docker pull openapitools/openapi-generator-cli
- name: Generate TypeScript Client
run: |
docker run -u $(id -u):$(id -g) --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i https://github.com/snypy/snypy-backend/releases/download/${{ steps.get_version.outputs.VERSION }}/schema.yml \
-g typescript-angular \
-o /local/client \
--additional-properties=npmName=@snypy/rest-client,npmVersion=${{ steps.get_version.outputs.VERSION }},useSingleRequestParameter=true
- name: Build TypeScript Client
run: |
cd client
npm install --force
npm run build
- name: Publish to NPM
run: |
cd client/dist
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}