Skip to content

Commit 43cec51

Browse files
committed
Merge branch 'oa/existing-integration' of https://github.com/json-api-dotnet/JsonApiDotNetCore into oa/existing-integration
2 parents b72d823 + 520c618 commit 43cec51

File tree

7 files changed

+165
-184
lines changed

7 files changed

+165
-184
lines changed

docs/usage/openapi-client.md

Lines changed: 103 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,139 @@
11
# OpenAPI Client
22

3-
You can generate a client in various programming languages from the OpenAPI specification file that JsonApiDotNetCore APIs provide. For C# .NET clients generated using NSwag, we provide an additional package that introduces support for partial PATCH/POST requests. The issue here is that a property on a generated C# class being `null` could mean "set the value to `null` in the request" or "this is `null` because I never touched it".
3+
You can generate a JSON:API client in various programming languages from the [OpenAPI specification](https://swagger.io/specification/) file that JsonApiDotNetCore APIs provide.
44

5-
## Installation
5+
For C# .NET clients generated using [NSwag](https://github.com/RicoSuter/NSwag), we provide an additional package that introduces support for partial PATCH/POST requests. The issue here is that a property on a generated C# class being `null` could mean "set the value to `null` in the request" or "this is `null` because I never touched it".
66

7-
You are required to install the following NuGet packages:
8-
9-
- `JsonApiDotNetCore.OpenApi.Client`
10-
- `NSwag.ApiDescription.Client`
11-
- `Microsoft.Extensions.ApiDescription.Cient`
12-
- `NSwag.ApiDescription.Client`
13-
14-
The following examples demonstrate how to install the `JsonApiDotNetCore.OpenApi.Client` package.
15-
16-
### CLI
17-
18-
```
19-
dotnet add package JsonApiDotNetCore.OpenApi.Client
20-
```
7+
## Getting started
218

229
### Visual Studio
2310

24-
```powershell
25-
Install-Package JsonApiDotNetCore.OpenApi.Client
26-
```
11+
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.
2712

28-
### *.csproj
13+
1. In **Solution Explorer**, right-click your client project, select **Add** > **Service Reference** and choose **OpenAPI**.
2914

30-
```xml
31-
<ItemGroup>
32-
<!-- Be sure to check NuGet for the latest version # -->
33-
<PackageReference Include="JsonApiDotNetCore.OpenApi.Client" Version="4.0.0" />
34-
</ItemGroup>
35-
```
15+
2. On the next page, specify the OpenAPI URL to your JSON:API server, for example: `http://localhost:14140/swagger/v1/swagger.json`.
16+
Optionally provide a class name and namespace and click **Finish**.
17+
Visual Studio now downloads your swagger.json and updates your project file. This results in a pre-build step that generates the client code.
3618

19+
Tip: To later re-download swagger.json and regenerate the client code, right-click **Dependencies** > **Manage Connected Services** and click the **Refresh** icon.
20+
3. Although not strictly required, we recommend to run package update now, which fixes some issues and removes the `Stream` parameter from generated calls.
3721

38-
## Adding an OpenApiReference
22+
4. Add some demo code that calls one of your JSON:API endpoints. For example:
3923

40-
Add a reference to your OpenAPI specification in your project file as demonstrated below.
24+
```c#
25+
using var httpClient = new HttpClient();
26+
var apiClient = new ExampleApiClient("http://localhost:14140", httpClient);
4127

42-
```xml
43-
<ItemGroup>
44-
<OpenApiReference Include="swagger.json">
45-
<Namespace>JsonApiDotNetCoreExampleClient.GeneratedCode</Namespace>
46-
<ClassName>ExampleApiClient</ClassName>
47-
<CodeGenerator>NSwagCSharp</CodeGenerator>
48-
<Options>/UseBaseUrl:false /GenerateClientInterfaces:true</Options>
49-
</OpenApiReference>
50-
</ItemGroup>
51-
```
28+
PersonCollectionResponseDocument getResponse =
29+
await apiClient.GetPersonCollectionAsync();
5230

31+
foreach (PersonDataInResponse person in getResponse.Data)
32+
{
33+
Console.WriteLine($"Found user {person.Id} named " +
34+
$"'{person.Attributes.FirstName} {person.Attributes.LastName}'.");
35+
}
36+
```
5337

54-
## Usage
38+
5. Add our client package to your project:
5539

56-
The NSwag tooling generates the OpenAPI client during a prebuild step. Once your application is built,
57-
you can instantiate it using the class name as indicated in the project file.
40+
```
41+
dotnet add package JsonApiDotNetCore.OpenApi.Client
42+
```
5843
59-
```c#
60-
namespace JsonApiDotNetCoreExampleClient
61-
{
62-
class Program
63-
{
64-
static void Main(string[] args)
65-
{
66-
using (HttpClient httpClient = new HttpClient())
67-
{
68-
ExampleApiClient exampleApiClient = new ExampleApiClient(httpClient);
44+
6. Add the following glue code to connect our package with your generated code. The code below assumes you specified `ExampleApiClient` as class name in step 2.
6945
70-
// IntelliSense is now available on `exampleApiClient`!
71-
}
72-
}
73-
}
74-
}
75-
```
46+
```c#
47+
using JsonApiDotNetCore.OpenApi.Client;
48+
using Newtonsoft.Json;
7649
77-
Support for partial write requests can be enabled by leveraging the extensibility points of the generated client.
78-
79-
```c#
80-
namespace JsonApiDotNetCoreExampleClient.GeneratedCode
81-
{
82-
// Note that this class should be in the same namespace as the ExampleApiClient generated by NSwag.
83-
public partial class ExampleApiClient : JsonApiClient
50+
partial class ExampleApiClient : JsonApiClient
8451
{
8552
partial void UpdateJsonSerializerSettings(JsonSerializerSettings settings)
8653
{
8754
SetSerializerSettingsForJsonApi(settings);
8855
}
8956
}
90-
}
91-
```
57+
```
9258
93-
You can now perform a write request by calling the `RegisterAttributesForRequest` method. Calling this method treats all attributes that contain their default value (<c>null</c> for reference types, <c>0</c> for integers, <c>false</c> for booleans, etc) as omitted unless explicitly listed to include them using the `alwaysIncludedAttributeSelectors` parameter.
59+
7. Extend your demo code to send a partial PATCH request with the help of our package:
9460
95-
```c#
96-
// Program.cs
97-
static void Main(string[] args)
98-
{
99-
using (HttpClient httpClient = new HttpClient())
61+
```c#
62+
var patchRequest = new PersonPatchRequestDocument
10063
{
101-
ExampleApiClient exampleApiClient = new ExampleApiClient(httpClient);
102-
103-
var requestDocument = new PersonPatchRequestDocument
64+
Data = new PersonDataInPatchRequest
10465
{
105-
Data = new PersonDataInPatchRequest
66+
Id = "1",
67+
Attributes = new PersonAttributesInPatchRequest
10668
{
107-
Id = "546",
108-
Type = PersonResourceType.People,
109-
Attributes = new PersonAttributesInPatchRequest
110-
{
111-
FirstName = "Jack"
112-
}
69+
FirstName = "Jack"
11370
}
114-
};
115-
116-
using (apiClient.RegisterAttributesForRequestDocument<PersonPatchRequestDocument, PersonDataInPatchRequest>(requestDocument, person => person.LastName)
117-
{
118-
await exampleApiClient.PatchPersonAsync(543, requestDocument));
119-
120-
// The request will look like this:
121-
//
122-
// {
123-
// "data": {
124-
// "type": "people",
125-
// "id": "543",
126-
// "attributes": {
127-
// "firstName": "Jack",
128-
// "lastName": null,
129-
// }
130-
// }
131-
// }
13271
}
72+
};
13373
74+
// This line results in sending "lastName: null" instead of omitting it.
75+
using (apiClient.RegisterAttributesForRequestDocument<PersonPatchRequestDocument,
76+
PersonAttributesInPatchRequest>(patchRequest, person => person.LastName))
77+
{
78+
PersonPrimaryResponseDocument patchResponse =
79+
await apiClient.PatchPersonAsync("1", patchRequest);
80+
81+
// The sent request looks like this:
82+
// {
83+
// "data": {
84+
// "type": "people",
85+
// "id": "1",
86+
// "attributes": {
87+
// "firstName": "Jack",
88+
// "lastName": null
89+
// }
90+
// }
91+
// }
13492
}
135-
}
93+
```
94+
95+
### Other IDEs
96+
97+
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).
98+
99+
Alternatively, the next section shows what to add to your client project file directly:
100+
101+
```xml
102+
<ItemGroup>
103+
<PackageReference Include="Microsoft.Extensions.ApiDescription.Client" Version="3.0.0">
104+
<PrivateAssets>all</PrivateAssets>
105+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
106+
</PackageReference>
107+
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
108+
<PackageReference Include="NSwag.ApiDescription.Client" Version="13.0.5">
109+
<PrivateAssets>all</PrivateAssets>
110+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
111+
</PackageReference>
112+
</ItemGroup>
113+
114+
<ItemGroup>
115+
<OpenApiReference Include="OpenAPIs\swagger.json" CodeGenerator="NSwagCSharp" ClassName="ExampleApiClient">
116+
<SourceUri>http://localhost:14140/swagger/v1/swagger.json</SourceUri>
117+
</OpenApiReference>
118+
</ItemGroup>
136119
```
137120

121+
From here, continue from step 3 in the list of steps for Visual Studio.
122+
123+
## Configuration
124+
125+
### NSwag
126+
127+
The `OpenApiReference` element in the project file accepts an `Options` element to pass additional settings to the client generator,
128+
which are listed [here](https://github.com/RicoSuter/NSwag/blob/master/src/NSwag.Commands/Commands/CodeGeneration/OpenApiToCSharpClientCommand.cs).
129+
130+
For example, the next section puts the generated code in a namespace, removes the `baseUrl` parameter and generates an interface (which is handy for dependency injection):
131+
132+
```xml
133+
<OpenApiReference Include="swagger.json">
134+
<Namespace>ExampleProject.GeneratedCode</Namespace>
135+
<ClassName>SalesApiClient</ClassName>
136+
<CodeGenerator>NSwagCSharp</CodeGenerator>
137+
<Options>/UseBaseUrl:false /GenerateClientInterfaces:true</Options>
138+
</OpenApiReference>
139+
```

docs/usage/openapi.md

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,63 +3,47 @@
33
JsonApiDotNetCore provides an extension package that enables you to produce an [OpenAPI specification](https://swagger.io/specification/) for your JSON:API endpoints. This can be used to generate a [documentation website](https://swagger.io/tools/swagger-ui/) or to generate [client libraries](https://openapi-generator.tech/docs/generators/) in various languages. The package provides an integration with [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore).
44

55

6-
## Installation
6+
## Getting started
77

8-
Install the `JsonApiDotNetCore.OpenApi` NuGet package.
8+
1. Install the `JsonApiDotNetCore.OpenApi` NuGet package:
99

10-
### CLI
10+
```
11+
dotnet add package JsonApiDotNetCore.OpenApi
12+
```
1113
12-
```
13-
dotnet add package JsonApiDotNetCore.OpenApi
14-
```
15-
16-
### Visual Studio
17-
18-
```powershell
19-
Install-Package JsonApiDotNetCore.OpenApi
20-
```
21-
22-
### *.csproj
23-
24-
```xml
25-
<ItemGroup>
26-
<!-- Be sure to check NuGet for the latest version # -->
27-
<PackageReference Include="JsonApiDotNetCore.OpenApi" Version="4.0.0" />
28-
</ItemGroup>
29-
```
30-
31-
## Usage
14+
2. Add the integration in your `Startup` class.
3215
33-
Add the integration in your `Startup` class.
34-
35-
```c#
36-
public class Startup
37-
{
38-
public void ConfigureServices(IServiceCollection services)
16+
```c#
17+
public class Startup
3918
{
40-
IMvcCoreBuilder mvcBuilder = services.AddMvcCore();
41-
services.AddJsonApi<AppDbContext>(mvcBuilder: mvcBuilder);
19+
public void ConfigureServices(IServiceCollection services)
20+
{
21+
IMvcCoreBuilder mvcBuilder = services.AddMvcCore();
4222
43-
// Adds the Swashbuckle integration.
44-
services.AddOpenApi(mvcBuilder);
45-
}
23+
services.AddJsonApi<AppDbContext>(mvcBuilder: mvcBuilder);
4624
47-
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
48-
{
49-
app.UseRouting();
50-
app.UseJsonApi();
25+
// Adds the Swashbuckle integration.
26+
services.AddOpenApi(mvcBuilder);
27+
}
28+
29+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
30+
{
31+
app.UseRouting();
32+
app.UseJsonApi();
5133
52-
// Adds the Swashbuckle middleware.
53-
app.UseSwagger();
34+
// Adds the Swashbuckle middleware.
35+
app.UseSwagger();
5436
55-
app.UseEndpoints(endpoints => endpoints.MapControllers());
37+
app.UseEndpoints(endpoints => endpoints.MapControllers());
38+
}
5639
}
57-
}
58-
```
40+
```
5941
6042
By default, the OpenAPI specification will be available at `http://localhost:<port>/swagger/v1/swagger.json`.
6143
62-
Swashbuckle also ships with [SwaggerUI](https://swagger.io/tools/swagger-ui/), tooling for a generated documentation page. This can be enabled by installing the `Swashbuckle.AspNetCore.SwaggerUI` NuGet package and adding the following to your `Startup` class.
44+
## Documentation
45+
46+
Swashbuckle also ships with [SwaggerUI](https://swagger.io/tools/swagger-ui/), tooling for a generated documentation page. This can be enabled by installing the `Swashbuckle.AspNetCore.SwaggerUI` NuGet package and adding the following to your `Startup` class:
6347
6448
```c#
6549
// Startup.cs

docs/usage/toc.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
# [Metadata](meta.md)
2323
# [Caching](caching.md)
2424

25-
# [OpenAPI](openapi.md))
26-
## [Client](openapi-client.md))
25+
# [OpenAPI](openapi.md)
26+
## [Client](openapi-client.md)
2727

2828
# Extensibility
2929
## [Layer Overview](extensibility/layer-overview.md)

src/Examples/JsonApiDotNetCoreExampleClient/GeneratedCode/ExampleApiClient.cs renamed to src/Examples/JsonApiDotNetCoreExampleClient/ExampleApiClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
using JsonApiDotNetCore.OpenApi.Client;
22
using Newtonsoft.Json;
33

4-
namespace JsonApiDotNetCoreExampleClient.GeneratedCode
4+
namespace JsonApiDotNetCoreExampleClient
55
{
6-
internal partial class ExampleApiClient : JsonApiClient
6+
public partial class ExampleApiClient : JsonApiClient
77
{
88
partial void UpdateJsonSerializerSettings(JsonSerializerSettings settings)
99
{

0 commit comments

Comments
 (0)