A .NET tool for generating C# API clients from OpenAPI specifications. This tool creates HttpClient-based clients with async/await patterns, JSON serialization, and proper error handling.
- OpenAPI 3.0 Support: Parse JSON OpenAPI specifications from files or URLs
- Modern C# Code: Generates clients using HttpClient with async/await patterns
- Customizable Output: Configure class names, namespaces, and output paths
- Watch Mode: Automatically regenerate clients when OpenAPI specs change
- CLI Tool: Easy to use command-line interface with rich options
- NuGet Package: Distribute and install as a .NET global tool
Install as a global .NET tool:
dotnet tool install --global DotnetClientGeneratorOr install locally in a project:
dotnet tool install DotnetClientGeneratorGenerate a C# client from an OpenAPI specification:
dotnet-client-generator --input openapi.json --output ApiClient.csCustomize the generated client:
dotnet-client-generator \
--input https://petstore.swagger.io/v2/swagger.json \
--output PetStoreClient.cs \
--class-name PetStoreClient \
--namespace PetStore.ApiAutomatically regenerate when the OpenAPI spec changes:
dotnet-client-generator --input openapi.json --output ApiClient.cs --watch| Option | Alias | Description | Required |
|---|---|---|---|
--input |
-i |
Path to OpenAPI specification file or URL | Yes |
--output |
-o |
Output file path for generated C# client | Yes |
--class-name |
-c |
Name of the generated client class | No (default: "ApiClient") |
--namespace |
-n |
Namespace for the generated client | No (default: "GeneratedClient") |
--generate-interface |
-g |
Generate an interface for the client class | No |
--generate-model-interfaces |
-m |
Generate interfaces for model classes | No |
--watch |
-w |
Watch input file for changes and regenerate | No |
The generated C# client includes:
- HttpClient Integration: Uses dependency injection-friendly HttpClient
- Async/await Pattern: All methods return Task or Task
- JSON Serialization: Uses System.Text.Json for request/response handling
- Error Handling: Throws exceptions for HTTP error responses
- Type Safety: Strongly typed method parameters where possible
- Query Parameters: Automatic query string building
- Path Parameters: Automatic URL path interpolation
- Request Bodies: JSON serialization for POST/PUT operations
- Interface Generation: Optional generation of interfaces for dependency injection
- Model Interfaces: Optional generation of interfaces for model classes
using System.Text.Json;
using System.Text;
namespace PetStore;
public class PetStoreClient
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
public PetStoreClient(HttpClient httpClient, string baseUrl = "")
{
_httpClient = httpClient;
_baseUrl = baseUrl;
}
public async Task<object?> ListPets(int? limit = null)
{
var queryParams = new List<string>();
if (limit != null)
queryParams.Add($"limit={limit}");
var path = "/pets" + (queryParams.Any() ? "?" + string.Join("&", queryParams) : "");
return await SendRequestAsync<object>(path, HttpMethod.Get);
}
public async Task<object?> CreatePet(object body)
{
var path = $"/pets";
return await SendRequestAsync<object>(path, HttpMethod.Post, body);
}
// ... other generated methods
}// Register with DI container
services.AddHttpClient<PetStoreClient>();
// Or create manually
var httpClient = new HttpClient();
var client = new PetStoreClient(httpClient, "https://petstore.swagger.io/v2");
// Use the client
var pets = await client.ListPets(limit: 10);
await client.CreatePet(new { name = "Fluffy", tag = "cat" });Generate an interface for the client class using --generate-interface:
dotnet-client-generator -i openapi.json -o ApiClient.cs --generate-interfaceThis generates:
public interface IApiClient
{
Task<GetUserResponse> GetUser(int userId);
// ... other methods
}
public class ApiClient : IApiClient
{
// ... implementation
}Generate interfaces for model classes using --generate-model-interfaces:
dotnet-client-generator -i openapi.json -o ApiClient.cs --generate-model-interfacesThis generates:
public interface IPet
{
long Id { get; }
string Name { get; }
string? Tag { get; }
}
public class Pet : IPet
{
public long Id { get; set; }
public string Name { get; set; }
public string? Tag { get; set; }
}Model interfaces are useful for:
- Dependency injection and mocking in tests
- Creating abstraction layers
- Enforcing read-only contracts
- Supporting polymorphism in domain models
dotnet builddotnet run --project DotnetClientGenerator -- --input sample-openapi.json --output TestClient.csdotnet packThis project uses GitVersion for semantic versioning. By default, commits to the main branch increment the patch version, and commits to the develop branch increment the minor version.
GitVersion is configured to interpret Conventional Commits style messages:
| Commit prefix | Effect | Example |
|---|---|---|
feat: or feat(scope): |
Increments minor version (e.g., 1.0.0 → 1.1.0) | feat: add new endpoint support |
fix: or fix(scope): |
Increments patch version (e.g., 1.0.0 → 1.0.1) | fix: correct JSON serialization |
type!: or BREAKING CHANGE |
Increments major version (e.g., 1.0.0 → 2.0.0) | feat!: remove legacy option |
For most commits, you don't need any special syntax. Just write your commit message normally:
# Normal commit on main branch → increments patch version (1.0.0 → 1.0.1)
git commit -m "Fix JSON serialization issue"
# Normal commit on develop branch → increments minor version (1.0.0 → 1.1.0)
git commit -m "Add new endpoint support"If you need to override the default increment, you can add one of these optional keywords anywhere in your commit message:
| Keyword | Effect | Example |
|---|---|---|
+semver: major or +semver: breaking |
Increments major version (e.g., 1.0.0 → 2.0.0) | Add breaking API change +semver: major |
+semver: minor or +semver: feature |
Increments minor version (e.g., 1.0.0 → 1.1.0) | Add new feature +semver: minor |
+semver: patch or +semver: fix |
Increments patch version (e.g., 1.0.0 → 1.0.1) | Fix bug +semver: patch |
# On main branch, force a minor version bump instead of patch
git commit -m "Add support for OpenAPI 3.1 +semver: minor"
# On any branch, force a major version bump for breaking changes
git commit -m "Rename output parameter +semver: breaking"- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is licensed under the MIT License.