Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e380c56

Browse files
OpenAPI: Show custom endpoints, fix content negotiation (#1747)
* Add some .http files * Include custom controllers and minimal API endpoints in OpenAPI; log warning for non-standard JSON:API action methods; fix broken content negotiation.
1 parent 8c59d1b commit e380c56

File tree

122 files changed

+6119
-768
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+6119
-768
lines changed

‎.config/dotnet-tools.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
"rollForward": false
3232
},
3333
"microsoft.openapi.kiota": {
34-
"version": "1.27.0",
34+
"version": "1.28.0",
3535
"commands": [
3636
"kiota"
3737
],
3838
"rollForward": false
3939
}
4040
}
41-
}
41+
}

‎package-versions.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<KiotaVersion>1.*</KiotaVersion>
2121
<MicrosoftApiClientVersion>9.0.*</MicrosoftApiClientVersion>
2222
<MicrosoftApiServerVersion>9.0.*</MicrosoftApiServerVersion>
23+
<MiniValidationVersion>0.9.*</MiniValidationVersion>
2324
<NSwagApiClientVersion>14.4.*</NSwagApiClientVersion>
2425
<NewtonsoftJsonVersion>13.0.*</NewtonsoftJsonVersion>
2526
<ReadableExpressionsVersion>4.1.*</ReadableExpressionsVersion>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
@hostAddress = http://localhost:14141
2+
3+
### Get all books with their authors.
4+
5+
GET {{hostAddress}}/api/books?include=author
6+
7+
### Get the first two books.
8+
9+
GET {{hostAddress}}/api/books?page[size]=2
10+
11+
### Filter books whose title contains whitespace, sort descending by publication year.
12+
13+
GET {{hostAddress}}/api/books?filter=contains(title,'%20')&sort=-publishYear
14+
15+
### Get only the titles of all books.
16+
17+
GET {{hostAddress}}/api/books?fields[books]=title
18+
19+
### Get the names of all people.
20+
21+
GET {{hostAddress}}/api/people?fields[people]=name
22+
23+
### Create a new person.
24+
25+
POST {{hostAddress}}/api/people
26+
Content-Type: application/vnd.api+json
27+
28+
{
29+
"data": {
30+
"type": "people",
31+
"attributes": {
32+
"name": "Alice"
33+
}
34+
}
35+
}
36+
37+
### Create a new book, authored by the created person.
38+
39+
POST {{hostAddress}}/api/books
40+
Content-Type: application/vnd.api+json
41+
42+
{
43+
"data": {
44+
"type": "books",
45+
"attributes": {
46+
"title": "Getting started with JSON:API",
47+
"publishYear": 2000
48+
},
49+
"relationships": {
50+
"author": {
51+
"data": {
52+
"type": "people",
53+
"id": "4"
54+
}
55+
}
56+
}
57+
}
58+
}
59+
60+
### Change the publication year and author of the book with ID 1.
61+
62+
PATCH {{hostAddress}}/api/books/1
63+
Content-Type: application/vnd.api+json
64+
65+
{
66+
"data": {
67+
"type": "books",
68+
"id": "1",
69+
"attributes": {
70+
"publishYear": 1820
71+
},
72+
"relationships": {
73+
"author": {
74+
"data": {
75+
"type": "people",
76+
"id": "4"
77+
}
78+
}
79+
}
80+
}
81+
}
82+
83+
### Delete the book with ID 1.
84+
85+
DELETE {{hostAddress}}/api/books/1

‎src/Examples/JsonApiDotNetCoreExample/Controllers/NonJsonApiController.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
namespace JsonApiDotNetCoreExample.Controllers;
44

55
[Route("[controller]")]
6+
[Tags("nonJsonApi")]
67
public sealed class NonJsonApiController : ControllerBase
78
{
8-
[HttpGet]
9+
[HttpGet(Name = "welcomeGet")]
10+
[HttpHead(Name = "welcomeHead")]
11+
[EndpointDescription("Returns a single-element JSON array.")]
12+
[ProducesResponseType<List<string>>(StatusCodes.Status200OK, "application/json")]
913
public IActionResult Get()
1014
{
1115
string[] result = ["Welcome!"];
@@ -14,12 +18,15 @@ public IActionResult Get()
1418
}
1519

1620
[HttpPost]
17-
public async Task<IActionResult> PostAsync()
21+
[EndpointDescription("Returns a greeting text, based on your name.")]
22+
[Consumes("application/json")]
23+
[ProducesResponseType<string>(StatusCodes.Status200OK, "text/plain")]
24+
[ProducesResponseType<string>(StatusCodes.Status400BadRequest, "text/plain")]
25+
public async Task<IActionResult> PostAsync([FromBody] string? name)
1826
{
19-
using var reader = new StreamReader(Request.Body, leaveOpen: true);
20-
string name = await reader.ReadToEndAsync();
27+
await Task.Yield();
2128

22-
if (string.IsNullOrEmpty(name))
29+
if (string.IsNullOrWhiteSpace(name))
2330
{
2431
return BadRequest("Please send your name.");
2532
}
@@ -29,14 +36,18 @@ public async Task<IActionResult> PostAsync()
2936
}
3037

3138
[HttpPut]
32-
public IActionResult Put([FromBody] string name)
39+
[EndpointDescription("Returns another greeting text.")]
40+
[ProducesResponseType<string>(StatusCodes.Status200OK, "text/plain")]
41+
public IActionResult Put([FromQuery] string? name)
3342
{
3443
string result = $"Hi, {name}";
3544
return Ok(result);
3645
}
3746

3847
[HttpPatch]
39-
public IActionResult Patch(string name)
48+
[EndpointDescription("Wishes you a good day.")]
49+
[ProducesResponseType<string>(StatusCodes.Status200OK, "text/plain")]
50+
public IActionResult Patch([FromHeader] string? name)
4051
{
4152
string result = $"Good day, {name}";
4253
return Ok(result);

‎src/Examples/JsonApiDotNetCoreExample/GeneratedSwagger/JsonApiDotNetCoreExample.json

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,143 @@
1010
}
1111
],
1212
"paths": {
13+
"/NonJsonApi": {
14+
"get": {
15+
"tags": [
16+
"nonJsonApi"
17+
],
18+
"description": "Returns a single-element JSON array.",
19+
"operationId": "welcomeGet",
20+
"responses": {
21+
"200": {
22+
"description": "OK",
23+
"content": {
24+
"application/json": {
25+
"schema": {
26+
"type": "array",
27+
"items": {
28+
"type": "string"
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}
35+
},
36+
"head": {
37+
"tags": [
38+
"nonJsonApi"
39+
],
40+
"description": "Returns a single-element JSON array.",
41+
"operationId": "welcomeHead",
42+
"responses": {
43+
"200": {
44+
"description": "OK"
45+
}
46+
}
47+
},
48+
"post": {
49+
"tags": [
50+
"nonJsonApi"
51+
],
52+
"description": "Returns a greeting text, based on your name.",
53+
"requestBody": {
54+
"content": {
55+
"application/json": {
56+
"schema": {
57+
"type": "string"
58+
}
59+
}
60+
}
61+
},
62+
"responses": {
63+
"200": {
64+
"description": "OK",
65+
"content": {
66+
"text/plain": {
67+
"schema": {
68+
"type": "string"
69+
}
70+
}
71+
}
72+
},
73+
"400": {
74+
"description": "Bad Request",
75+
"content": {
76+
"text/plain": {
77+
"schema": {
78+
"type": "string"
79+
}
80+
}
81+
}
82+
}
83+
}
84+
},
85+
"put": {
86+
"tags": [
87+
"nonJsonApi"
88+
],
89+
"description": "Returns another greeting text.",
90+
"parameters": [
91+
{
92+
"name": "name",
93+
"in": "query",
94+
"schema": {
95+
"type": "string"
96+
}
97+
}
98+
],
99+
"responses": {
100+
"200": {
101+
"description": "OK",
102+
"content": {
103+
"text/plain": {
104+
"schema": {
105+
"type": "string"
106+
}
107+
}
108+
}
109+
}
110+
}
111+
},
112+
"patch": {
113+
"tags": [
114+
"nonJsonApi"
115+
],
116+
"description": "Wishes you a good day.",
117+
"parameters": [
118+
{
119+
"name": "name",
120+
"in": "header",
121+
"schema": {
122+
"type": "string"
123+
}
124+
}
125+
],
126+
"responses": {
127+
"200": {
128+
"description": "OK",
129+
"content": {
130+
"text/plain": {
131+
"schema": {
132+
"type": "string"
133+
}
134+
}
135+
}
136+
}
137+
}
138+
},
139+
"delete": {
140+
"tags": [
141+
"nonJsonApi"
142+
],
143+
"responses": {
144+
"200": {
145+
"description": "OK"
146+
}
147+
}
148+
}
149+
},
13150
"/api/operations": {
14151
"post": {
15152
"tags": [
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
@hostAddress = https://localhost:44340
2+
3+
### Gets all high-priority todo-items, including their owner, assignee and tags.
4+
5+
GET {{hostAddress}}/api/todoItems?include=owner,assignee,tags&filter=equals(priority,'High')
6+
7+
### Creates a todo-item, linking it to an existing owner, assignee and tags.
8+
9+
POST {{hostAddress}}/api/todoItems
10+
Content-Type: application/vnd.api+json
11+
12+
{
13+
"data": {
14+
"type": "todoItems",
15+
"attributes": {
16+
"description": "Create release",
17+
"priority": "High",
18+
"durationInHours": 1
19+
},
20+
"relationships": {
21+
"owner": {
22+
"data": {
23+
"type": "people",
24+
"id": "1"
25+
}
26+
},
27+
"assignee": {
28+
"data": {
29+
"type": "people",
30+
"id": "1"
31+
}
32+
},
33+
"tags": {
34+
"data": [
35+
{
36+
"type": "tags",
37+
"id": "1"
38+
},
39+
{
40+
"type": "tags",
41+
"id": "2"
42+
}
43+
]
44+
}
45+
}
46+
}
47+
}

‎src/Examples/OpenApiKiotaClientExample/GeneratedCode/ExampleApiClient.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.Kiota.Serialization.Multipart;
1111
using Microsoft.Kiota.Serialization.Text;
1212
using OpenApiKiotaClientExample.GeneratedCode.Api;
13+
using OpenApiKiotaClientExample.GeneratedCode.NonJsonApi;
1314
using System.Collections.Generic;
1415
using System.IO;
1516
using System.Threading.Tasks;
@@ -28,6 +29,12 @@ public partial class ExampleApiClient : BaseRequestBuilder
2829
get => new global::OpenApiKiotaClientExample.GeneratedCode.Api.ApiRequestBuilder(PathParameters, RequestAdapter);
2930
}
3031

32+
/// <summary>The NonJsonApi property</summary>
33+
public global::OpenApiKiotaClientExample.GeneratedCode.NonJsonApi.NonJsonApiRequestBuilder NonJsonApi
34+
{
35+
get => new global::OpenApiKiotaClientExample.GeneratedCode.NonJsonApi.NonJsonApiRequestBuilder(PathParameters, RequestAdapter);
36+
}
37+
3138
/// <summary>
3239
/// Instantiates a new <see cref="global::OpenApiKiotaClientExample.GeneratedCode.ExampleApiClient"/> and sets the default values.
3340
/// </summary>

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /