Create a new GitHub repository. Check it out locally and copy this project inside it as initial commit.
- .NET 9 SDK
- Node.js >= v18 (needed for npm packages)
Before we can use the OpenAPI specification file we need to create it. These steps will show you how you can create the file during runtime and as a build artifact.
There are two relevant packages.
Microsoft.AspNetCore.OpenApi builds and serves the openapi.json during runtime.
Microsoft.Extensions.ApiDescription.Server creates the openapi.json during build time so it can be used in the pipelines.
The latter one puts the file in the obj folder, and it's named {ProjectName}.json by default.
Follow these steps to create the openapi.json and serve it during runtime.
Then build and run the API and try to navigate to the specification file to make sure it is actually served.
Then follow these steps to create the specification file during the build process.
Add the following to the API's .csproj file to copy the specification file to the project build output directory.
It's easier to use it from the pipeline later if we copy it to the output folder.
Warning
Adding the following property will currently break your build because there seems to be a bug in the package.
You need to either add it later as it will be needed as soon as we use GitHub actions to build it and copy the file manually now
Or you need to build locally specifing the -o flag to dotnet build to specify the output directoy.
<PropertyGroup>
<OpenApiDocumentsDirectory>$(OutputPath)</OpenApiDocumentsDirectory>
</PropertyGroup>Even though Swashbuckle has been removed as a default dependency in ASP.NET Core it still cannot be fully replaced by the Microsoft package.
The Microsoft.AspNetCore.OpenApi package only creates the specification file but does not provide a GUI like Swagger.
You of course can still use Swagger to visualize and test the API Endpoints.
Follow these instructions to setup Swagger.
The first thing we are going to do with the new specification file is automatically generate a C# SDK that can be used to call the API. This workshops covers two options to create it but there are a few more.
Create a new .NET class library project in your solution and call it Client.
Delete all *.cs files so that only the .csproj file is left.
All the files needed for the client will be automatically generated by NSwag.
Next install NSwag as global npm package using npm install -g nswag.
You can check out the NSwag CLI documentation here.
Because we want to generate C# Client we need to use the openapi2csclient command.
We need to specify at least two parameters.
The first is /input to specify which OpenAPI Specification file we want to generate a client for.
The next one is /output to specify where the generated file should be created.
It is highly recommended to also specify the /classname and /namespace parameters, as the default naming of the class and the namespace are not very good.
The complete command should look something like this:
nswag openapi2csclient /input:<pathToYourSpecificationFile>/ProjectManagerSimulatorApi.json /output:<PathToYouClientProject>/Client.cs /namespace:ProjectManagerSimulatorClient /classname:ProjectManagerSimulatorClientAfter running the command you should have the generated code in your project.
Make sure to not check the code into git.
Either by being very careful or by just adding the file to your .gitignore.
We don't want the generated code to be checked into git as we will dynamically create it using a github action later.
Try to build the client project.
You will see that it will fail complaining about missing dependencies.
That's because the generated code has a dependency on a NuGet package that has not been added to the project file.
So add the Newtonsoft.Json package as a dependency.
Try to build the project again, and it should compile successfully now.
If you have not already done so create a GitHub Personal Access Token (PAT) to authenticate the request.
Please be aware that you need to select the classic PAT when creating it because GitHub packages is not yet compatible with the newer version of PATs.
This PAT will be used to authenticate you Visual Studio against the private NugetFeed.
To see how you can consume the newly created package create a new Console Application project in your Solution.
First you need to add the feed to your local NuGet Manager.
If you published the package from your local machine already you most likely already did it via the CLI.
If you have not done it you can do it using the VS GUI.
To add the private feed open the projects NuGet Manager in VS.
On the top right click on the Gear icon.
There you can a new feed.
After creating it VS will prompt you for your credentials.
Do NOT use your GitHub password.
You need to use the PAT you created.
As Username just use your GitHub username.
After the authentication process you should be able to see and install your nuget package.
Now you can use the SDK from the nuget package to actually call your API with only a few simple lines of code.
To try it I recommend running your API locally by using
dotnet run inside the API project directory.
This way you can just use VS as usual to start and debug your client application.
As next step we want to publish the Client SDK as nuget package using GitHub packages. This makes it easy for other applications to consume the SDK and therefore to call your API. In general the pipeline needs to go through the following steps:
- Build the API to generate the OpenAPI specification file
- Generate the Client SDK code
- Build the Client SDK
- Pack the build artifacts into a nuget package
- Publish the package to the GitHub package feed
Steps 1-3 are basically what you have done locally already.
You just need to convert it to a GitHub Action.
If you are unfamiliar with the GitHub Action syntax a solution is provided behind a spoiler text below.
If you feel confident enough you can try to do the following directly as a part of the GitHub Action file, but I recommend trying to run the other steps locally first as well.
This documentation about the GitHub Packages Nuget Feed in combination with the Microsoft Documentation on how to publish Nuget Packages should give you an idea on how to achieve steps 4 and 5.
Please be aware that you need to select the classic PAT when creating it because GitHub Packages is not yet compatible with the newer version of PATs.
If you do try this make sure the PAT has the write: package permission configured.
If you are unsure with how the Action file should look like click here for spoilers
name: Publish Client NuGet Package
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Build API
run: dotnet build ProjectManagerSimulatorApi/ProjectManagerSimulatorApi.csproj --configuration Release -o ./ApiOutput
- uses: actions/setup-node@v4
name: install node
- name: install NSwag
run: npm install -g nswag
- name: Generate Client
run: nswag openapi2csclient /input:./ApiOutput/ProjectManagerSimulatorApi.json /output:./Client/Client.cs /namespace:ProjectManagerSimulatorClient /classname:ProjectManagerSimulatorClient /generateOptionalParameters:true
- name: Pack
run: dotnet pack Client/Client.csproj --configuration Release --output ./nupkg --version-suffix "alpha"
- name: Publish to GitHub Packages
run: dotnet nuget push ./nupkg/*.nupkg --source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" --api-key ${{ secrets.GITHUB_TOKEN }}Be aware that the nuget feed will be connected to your GitHub User and not directly to the project.
You can link it to the project manually.
On your GitHub user profile you should see a Packages tab.
There you can configure the settings for the package.
There is an official package by Microsoft that can also be used to generate a Client SDK automatically. You can use it instead of NSwag. The easiest way to install it is as dotnet tool. You then can use it to generate the client with its CLI just the same you did with NSwag.
Since Kiota just generates a CLient SDK like NSwag does you can more or less use the same steps to publish the SDK as its own NuGet Package.
Now we are able to easily call the API Endpoints from any Client. The next step is to give some documentation to the consumer so they know what to do and expect from your API. Of course we will also do this automatically.
The easiest was to setup documentation is by using Scalar. Just follow this quick instructions and see how easily you can create the documentation. You will notice that there already is some nice naming and a few description if you browse through the documentation. You can find them in the Controllers in the API project. They are added via the Attributes added to the endpoints.
If you want to combine your API Documentation with some more documentation about your project I recommend using Docusaurus.
The first step is to create a new folder in the solution root directoy.
Let's call it docs.
Inside the docs folder, run npx create-docusaurus@latest sim-docs classic to easily set up Docusaurus with some generic documentation predefined.
You should select typescript as it will be easier for us to use later.
To see how it looks just navigate inside the newly created sim-docs folder and run npm run start.
The next step is to automatically create the API documentation for docusaurus. For this we will use the OpenAPI Plugin for Docusaurus. Install it by running
npm install docusaurus-plugin-openapi-docs
npm install docusaurus-theme-openapi-docsThen add the configuration for the docusaurus plugin as seen in its documentation to the docusaurus.config.ts file
import type * as OpenApiPlugin from "docusaurus-plugin-openapi-docs";
const config: Config = {
// more code here
plugins: [
[
'docusaurus-plugin-openapi-docs',
{
id: "api", // plugin id
docsPluginId: "classic", // configured for preset-classic
config: {
projectManagerSimulator: {
specPath: "./ProjectManagerSimulatorApi.json",
outputDir: "docs/ProjectManagerSimulator",
sidebarOptions: {
groupPathsBy: "tag",
},
} satisfies OpenApiPlugin.Options,
}
},
]
],
themes: ["docusaurus-theme-openapi-docs"],
// more code here
}This essentially tells the plugin to look for the ProjectManagerSimulatorApi.json file in the Docusaurus root folder and save the build artifacts in docs/ProjectManagerSimulator.
Now add "generate-api-docs": "docusaurus gen-api-docs all", as script to you package.json and run it using npm run generate-api-docs.
This will create the files docusaurus needs to create the documentation.
Make again sure to not add the generated files to your git.
You can run npm run start again to see the new API documentation.
It should be available under the Tutorial tab in the top navbar and then in the ProjectManagerSimulator entry on the sidebar on the left.
To make your documentation available we can use GitHub Pages to host it.
Since we will use a GitHub Action to build the documentation files you first need to configure GitHub Pages to accept them.
To do this navigate to your GitHub Project Settings > Pages and select GitHub Actions from the Source dropdown.
Now we need to create a new Action that executes the following steps
- Build the API project to create the specification file
- Copy the specification file to the docusaurus root directory
- Use the Plugin to generate the documentation files
- Use docusaurus to build a webpage out of the documentation files
- Publish the webpage to GitHub Pages
Steps 1-4 are what you did locally before. If you want to search to figure out yourself how to do step 5 I recommend trying to find a template on GitHub that shows the steps.
Otherwise you can find my solution under this spoiler
name: Deploy API Docs
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Build API
run: dotnet build ProjectManagerSimulatorApi/ProjectManagerSimulatorApi.csproj --configuration Release -o ./ApiOutput
- uses: actions/setup-node@v4
name: install node
- name: copy openapi.json
run: cp ./ApiOutput/ProjectManagerSimulatorApi.json ./docs/sim-docs/ProjectManagerSimulatorApi.json
- name: generate openapi docs
working-directory: ./docs/sim-docs
run: |
npm ci
npm run generate-api-docs
npm run build
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository
path: './docs/sim-docs/build'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4Now you can push your code and the pipeline should complete sucessfully.
You should find your new website under
https://<githubUserName>.github.io/<RepositoryName>/.
You can also link it to your repository if you click the gear icon on the right side panel of your repository and tick the Use your GitHub Pages website checkbox.
If you navigate to your website you will probably see an error message.
This is because we need to configure docusaurus with your URL.
You need to change some entries in your docusuarus.config.ts to
url: 'https://<githubusername>.github.io',
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/<repositoryName>',
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: '<githubusername>', // Usually your GitHub org/user name.
projectName: '<repositoryName>', // Usually your repo name.Push your code again and after the Action has completed you should see your documentation running just fine!