We have explored the basics of OpenAPI in ASP.NET here on this blog, in the past. You can review them here, and here, and here. Today, we’re starting a new series that builds on those previous posts. In this series, we’ll look at how we can use this technology to automatically generate clients for our .NET APIs (we’ll be generating a TypeScript client) and then use that generated client in our automated testing scenarios. We’ll be writing those tests using Playwright. We’ll need to have our API running in an environment of some sort to run playwright tests against it. Docker can server as a good candidate for doing so; we’ll get into that in a later installment. Today, let’s lay out some foundational pieces that will eventually allow us to build our API, generate a TypeScript client for that API, run our automated (Playwright) tests against them, all done automatically in our Continuous Integration (CI) environment in GitHub.
The Goal: A Seamless Dev Loop
The “Holy Grail” of API development is ensuring your client code is always in sync with your server code. By automating this, we eliminate the “I forgot to update the client” bugs. Our workflow will look like this:
- Build the .NET Web API.
- Generate an OpenAPI spec and a TypeScript client using NSwag.
- Test the live API using Playwright and the newly generated client.
Step 1: Configure NSwag for MSBuild
To run NSwag in CI, we’ll move away from NSwagStudio and use the NSwag.MSBuild package. This allows us to trigger code generation during the build process.
First, add the package to your Web API project:
dotnet add package NSwag.MSBuild
Next, create an nswag.json configuration file in your project root. You can export this from NSwagStudio or create it manually. Ensure the output path points to a location where your Playwright tests can find it (e.g., ./Tests/api-client.ts).
Step 2: Setting up the GitHub Action
Now, let’s define the automation in .github/workflows/ci.yml. We need a workflow that sets up both .NET and Node.js environments.
name: Build and Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Dependencies
run: |
dotnet restore
npm install
- name: Build and Generate Client
run: |
dotnet build
# This command triggers NSwag to generate the TypeScript client
dotnet nswag run nswag.json /runtime:Net80
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Integration Tests
run: |
# Start the API in the background
dotnet run --project MyApi.csproj &
# Run Playwright tests
npx playwright test
Step 3: Using the Generated Client in Playwright
This is where the magic happens. Because NSwag generated a typed TypeScript client, your Playwright tests can now interact with your API using full IntelliSense and type safety.
In your Playwright test file:
import { test, expect } from '@playwright/test';
import { WeatherClient } from './api-client'; // The generated file
test('should fetch weather forecast', async ({ request }) => {
// Use the generated client!
const client = new WeatherClient('http://localhost:5000', { fetch: request.fetch.bind(request) });
const forecast = await client.getWeatherForecast();
expect(forecast.length).toBeGreaterThan(0);
expect(forecast[0].summary).toBeDefined();
});
Why This Matters
By coupling NSwag with Playwright in your CI pipeline, you gain several massive advantages:
- Type-Safe Testing: If you change a property name in your C# DTO, the TypeScript client will update. If that change breaks your tests, the TypeScript compiler (or your test runner) will catch it immediately in CI.
- Contract Verification: Your integration tests aren’t just checking logic; they are verifying that the API contract (OpenAPI spec) is actually being fulfilled by the running service.
- Zero Manual Effort: Every time you push code, your documentation, your client library, and your tests are refreshed and validated.
Conclusion
Automating your API lifecycle with NSwag and GitHub Actions transforms OpenAPI from a simple documentation tool into a foundational piece of your testing infrastructure. It bridges the gap between the backend and the frontend (or the test suite), ensuring that your “source of truth” is always the code itself.
We’ll flesh out these building blocks further in upcoming posts. Happy Coding!
