diff --git a/docs/usage/openapi-client.md b/docs/usage/openapi-client.md index 5bbb8bd480..0ba44d20d6 100644 --- a/docs/usage/openapi-client.md +++ b/docs/usage/openapi-client.md @@ -1,23 +1,46 @@ -# OpenAPI Client +# OpenAPI clients -You can generate a JSON:API client in various programming languages from the [OpenAPI specification](https://swagger.io/specification/) file that JsonApiDotNetCore APIs provide. +After [enabling OpenAPI](~/usage/openapi.md), you can generate a JSON:API client for your API in various programming languages. -For C# .NET clients generated using [NSwag](https://github.com/RicoSuter/NSwag), we provide an additional package -that provides workarounds for NSwag bugs and introduces support for partial PATCH/POST requests. -The concern here is that a property on a generated C# class being `null` could either mean: "set the value to `null` -in the request" or: "this is `null` because I never touched it". +The following generators are supported, though you may try others as well: +- [NSwag](https://github.com/RicoSuter/NSwag): Produces clients for C# and TypeScript +- [Kiota](https://learn.microsoft.com/en-us/openapi/kiota/overview): Produces clients for C#, Go, Java, PHP, Python, Ruby, Swift and TypeScript + +# [NSwag](#tab/nswag) + +For C# clients, we provide an additional package that provides workarounds for bugs in NSwag and enables using partial PATCH/POST requests. + +To add it to your project, run the following command: +``` +dotnet add package JsonApiDotNetCore.OpenApi.Client.NSwag +``` + +# [Kiota](#tab/kiota) + +For C# clients, we provide an additional package that provides workarounds for bugs in Kiota. + +To add it to your project, run the following command: +``` +dotnet add package JsonApiDotNetCore.OpenApi.Client.Kiota +``` + +--- ## Getting started +To generate your C# client, follow the steps below. + +# [NSwag](#tab/nswag) + ### Visual Studio The easiest way to get started is by using the built-in capabilities of Visual Studio. -The next steps describe how to generate a JSON:API client library and use our package. +The following steps describe how to generate and use a JSON:API client in C#, using our package. 1. In **Solution Explorer**, right-click your client project, select **Add** > **Service Reference** and choose **OpenAPI**. 2. On the next page, specify the OpenAPI URL to your JSON:API server, for example: `http://localhost:14140/swagger/v1/swagger.json`. - Specify `ExampleApiClient` as class name, optionally provide a namespace and click **Finish**. + Specify `ExampleApiClient` as the class name, optionally provide a namespace and click **Finish**. Visual Studio now downloads your swagger.json and updates your project file. This adds a pre-build step that generates the client code. @@ -25,7 +48,7 @@ The next steps describe how to generate a JSON:API client library and use our pa > To later re-download swagger.json and regenerate the client code, > right-click **Dependencies** > **Manage Connected Services** and click the **Refresh** icon. -3. Although not strictly required, we recommend to run package update now, which fixes some issues. +3. Although not strictly required, we recommend running package update now, which fixes some issues. > [!WARNING] > NSwag v14 is currently *incompatible* with JsonApiDotNetCore (tracked [here](https://github.com/RicoSuter/NSwag/issues/4662)). Stick with v13.x for the moment. @@ -36,7 +59,7 @@ The next steps describe how to generate a JSON:API client library and use our pa dotnet add package JsonApiDotNetCore.OpenApi.Client.NSwag ``` -5. Add the next line inside the **OpenApiReference** section in your project file: +5. Add the following line inside the **OpenApiReference** section in your project file: ```xml /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.NSwag @@ -62,10 +85,6 @@ The next steps describe how to generate a JSON:API client library and use our pa } ``` - > [!TIP] - > The project at src/Examples/OpenApiNSwagClientExample contains an enhanced version that logs the HTTP requests and responses. - > Additionally, the example shows how to write the swagger.json file to disk when building the server, which is imported from the client project. This keeps the server and client automatically in sync, which is handy when both are in the same solution. - 7. Add code that calls one of your JSON:API endpoints. ```c# @@ -121,42 +140,64 @@ The next steps describe how to generate a JSON:API client library and use our pa } ``` +> [!TIP] +> The [example project](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/openapi/src/Examples/OpenApiNSwagClientExample) contains an enhanced version that uses `IHttpClientFactory` for [scalability](https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory) and [resiliency](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests#use-polly-based-handlers) and logs the HTTP requests and responses. +> Additionally, the example shows how to write the swagger.json file to disk when building the server, which is imported from the client project. This keeps the server and client automatically in sync, which is handy when both are in the same solution. + ### Other IDEs -When using the command-line, you can try the [Microsoft.dotnet-openapi Global Tool](https://docs.microsoft.com/en-us/aspnet/core/web-api/microsoft.dotnet-openapi?view=aspnetcore-5.0). +When using the command line, you can try the [Microsoft.dotnet-openapi Global Tool](https://docs.microsoft.com/en-us/aspnet/core/web-api/microsoft.dotnet-openapi?view=aspnetcore-5.0). -Alternatively, the next section shows what to add to your client project file directly: +Alternatively, the following section shows what to add to your client project file directly: ```xml - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + - + http://localhost:14140/swagger/v1/swagger.json + NSwagCSharp + ExampleApiClient + ExampleApiClient.cs ``` From here, continue from step 3 in the list of steps for Visual Studio. +# [Kiota](#tab/kiota) + +To generate your C# client, install the Kiota tool by following the steps at https://learn.microsoft.com/en-us/openapi/kiota/install#install-as-net-tool. + +Next, generate client code by running the [command line tool](https://learn.microsoft.com/en-us/openapi/kiota/using#client-generation). For example: + +``` +dotnet kiota generate --language CSharp --class-name ExampleApiClient --output ./GeneratedCode --backing-store --exclude-backward-compatible --clean-output --clear-cache --openapi ..\JsonApiDotNetCoreExample\GeneratedSwagger\JsonApiDotNetCoreExample.json +``` + +> [!CAUTION] +> The `--backing-store` switch is needed for JSON:API partial PATCH/POST requests to work correctly. + +Kiota is pretty young and therefore still rough around the edges. At the time of writing, there are various bugs, for which we have workarounds +in place. For a full example, see the [example project](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/openapi/src/Examples/OpenApiKiotaClientExample). + +--- + ## Configuration -### NSwag +Various switches enable you to tweak the client generation to your needs. See the section below for an overview. + +# [NSwag](#tab/nswag) The `OpenApiReference` element in the project file accepts an `Options` element to pass additional settings to the client generator, which are listed [here](https://github.com/RicoSuter/NSwag/blob/master/src/NSwag.Commands/Commands/CodeGeneration/OpenApiToCSharpClientCommand.cs). +A guide with common best practices is available [here](https://stevetalkscode.co.uk/openapireference-commands). -For example, the next section puts the generated code in a namespace and generates an interface (which is handy for dependency injection): +For example, the following section puts the generated code in a namespace and generates an interface (which is handy for dependency injection): ```xml @@ -167,10 +208,37 @@ For example, the next section puts the generated code in a namespace and generat ``` +Likewise, you can enable nullable reference types by adding `/GenerateNullableReferenceTypes:true`, optionally combined with `/GenerateOptionalParameters:true`. + +# [Kiota](#tab/kiota) + +The available command-line switches for Kiota are described [here](https://learn.microsoft.com/en-us/openapi/kiota/using#client-generation). + +At the time of writing, Kiota provides [no official integration](https://github.com/microsoft/kiota/issues/3005) with MSBuild. +Our [example project](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/openapi/src/Examples/OpenApiKiotaClientExample) takes a stab at it, although it has glitches. If you're an MSBuild expert, please help out! + +```xml + + + + + + + + + +``` + +--- + ## Headers and caching -To use [ETags for caching](~/usage/caching.md), NSwag needs extra settings to make response headers accessible. -Specify the following in the `` element of your project file: +The use of HTTP headers varies per client generator. To use [ETags for caching](~/usage/caching.md), see the notes below. + +# [NSwag](#tab/nswag) + +NSwag needs extra settings to make response headers accessible. Specify the following in the `` element of your project file: ``` /GenerateExceptionClasses:false /WrapResponses:true /GenerateResponseClasses:false /ResponseClass:ApiResponse /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.NSwag @@ -197,3 +265,24 @@ The response of the first API call contains both data and an ETag header, which That ETag gets passed to the second API call. This enables the server to detect if something changed, which optimizes network usage: no data is sent back, unless is has changed. If you only want to ask whether data has changed without fetching it, use a HEAD request instead. + +# [Kiota](#tab/kiota) + +Use `HeadersInspectionHandlerOption` to gain access to response headers. For example: + +```c# +var headerInspector = new HeadersInspectionHandlerOption +{ + InspectResponseHeaders = true +}; + +var responseDocument = await apiClient.Api.People.GetAsync(configuration => configuration.Options.Add(headerInspector)); + +string eTag = headerInspector.ResponseHeaders["ETag"].Single(); +``` + +Due to a [bug in Kiota](https://github.com/microsoft/kiota/issues/4190), a try/catch block is needed additionally to make this work. + +For a full example, see the [example project](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/openapi/src/Examples/OpenApiKiotaClientExample). + +--- diff --git a/docs/usage/toc.md b/docs/usage/toc.md index 6f90725cba..925aa660a2 100644 --- a/docs/usage/toc.md +++ b/docs/usage/toc.md @@ -26,7 +26,7 @@ # [Common Pitfalls](common-pitfalls.md) # [OpenAPI](openapi.md) -## [Client](openapi-client.md) +## [Clients](openapi-client.md) # Extensibility ## [Layer Overview](extensibility/layer-overview.md)