Skip to content

Commit d72671b

Browse files
committed
Add support for OpenAPI configuration file and schema customization.
Motivation: Enable enhanced flexibility in OpenAPI schema generation by allowing users to provide a custom YAML/JSON configuration file for overriding and merging API specification details like metadata, servers, security, and tags. Changes: - Added a `schema-config` option in `GenerationOptions` to specify the OpenAPI configuration file path. - Updated `SchemaModelBuilder` to merge generated schemas with user-provided configuration values. - Introduced `SchemaConfigLoader` for loading and parsing configuration files. - Enhanced `SchemaGenerator` to handle schema customization during the generation process. - Updated documentation with examples for using the `schema-config` option. - Added integration tests to verify the functionality of schema customization using configuration files. - Refactored relevant classes and methods to support the new feature. Signed-off-by: Daniel Fiala <danfiala23@gmail.com>
1 parent 70d09cb commit d72671b

File tree

20 files changed

+2082
-12
lines changed

20 files changed

+2082
-12
lines changed

vertx-grpc-docs/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
<artifactId>vertx-grpc-protoc-plugin2</artifactId>
9393
<version>${project.version}</version>
9494
<mainClass>io.vertx.grpc.plugin.VertxGrpcGenerator</mainClass>
95-
<options>grpc-client=true,grpc-service=true,grpc-io=true</options>
95+
<options>grpc-client=true,grpc-service=true,grpc-io=true,openapi-json=true,openapi-yaml=true</options>
9696
</jvmMavenPlugin>
9797
</jvmMavenPlugins>
9898
<!--jvmMavenPlugins>

vertx-grpc-docs/src/main/asciidoc/plugin.adoc

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,160 @@ By default, the plugin generates both client and service files. If you need only
165165
- _[--]grpc-transcoding[=true/false]_: whether to generate transcoding options for methods with HTTP annotations
166166
- _[--]vertx-codegen[=true/false]_: whether to add Vert.x annotations to the generated classes (`@VertxGen`) By default, this is disabled
167167
- _[--]service-prefix[=Your Name]_: generate service classes with a prefix. For example, if you set it to `MyService`, the generated service class will be `MyServiceGreeterService` instead of `GreeterService`.
168+
- _[--]schema-output-format[=openapi-json+openapi-yaml]_: generate OpenAPI specification files. Use `openapi-json` for JSON format, `openapi-yaml` for YAML format, or combine both with `+` (e.g., `openapi-json+openapi-yaml`). Not generated by default.
169+
- _[--]schema-allow-merge[=true/false]_: when generating OpenAPI specs, merge all services into a single file (`openapi.json`/`openapi.yaml`). When set to `false`, generates separate files per service (`ServiceName-openapi.json`/`ServiceName-openapi.yaml`). Default is `true`.
170+
- _[--]schema-config[=/path/to/config.yaml]_: path to an OpenAPI configuration file (YAML or JSON) that customizes the generated specification. The config file can override info, servers, security, tags, externalDocs, and add securitySchemes. See <<openapi-configuration-file>> for details.
168171

169172
* [--] This means the argument can be prefixed with `--` when used as JVM arguments, but should be used without `--` when specified in the options tag. If possible, users should use plugin options as a more universal protoc plugin approach.
170173
* [=value] This means the argument can optionally specify a value. For boolean arguments (true/false), if no value is specified, the default is `true` when the argument is present. For string arguments like `service-prefix`, a value must be provided.
171174

172175
If no specific generation options are provided, both client and service files will be generated by default. By default, all extensions (currently only 'http') are supported.
173176

177+
=== OpenAPI Specification Generation
178+
179+
The plugin can generate OpenAPI 3.0 specification files from your gRPC service definitions. This is useful when using <<grpc-transcoding,gRPC transcoding>> to expose your services as REST APIs.
180+
181+
OpenAPI specs are generated for services that have HTTP annotations (`google.api.http`). Services and methods without HTTP annotations are skipped.
182+
183+
= OpenAPI specification generation
184+
185+
The plugin generates OpenAPI 3.0 specification files from your gRPC service definitions. This is useful when you use <<grpc-transcoding,gRPC transcoding>> to expose services as REST APIs.
186+
187+
The plugin only generates specs for services with HTTP annotations (`google.api.http`).
188+
189+
== Enabling OpenAPI generation
190+
191+
To start generating specs, add the `schema-output-format` option to your plugin configuration:
192+
193+
[source,xml]
194+
----
195+
<jvmMavenPlugin>
196+
<groupId>io.vertx</groupId>
197+
<artifactId>vertx-grpc-protoc-plugin2</artifactId>
198+
<version>${vertx.version}</version>
199+
<mainClass>io.vertx.grpc.plugin.VertxGrpcGenerator</mainClass>
200+
<options>grpc-client=true,grpc-service=true,schema-output-format=openapi-json+openapi-yaml</options>
201+
</jvmMavenPlugin>
202+
----
203+
204+
== Output formats
205+
206+
The plugin supports two formats:
207+
208+
* `openapi-json`: Generates a `.json` file.
209+
* `openapi-yaml`: Generates a `.yaml` file.
210+
211+
To generate both at once, combine them with a `+` symbol:
212+
`schema-output-format=openapi-json+openapi-yaml`
213+
214+
== Merge vs split mode
215+
216+
By default, the plugin combines all services into a single OpenAPI file (`openapi.json` or `openapi.yaml`). If you prefer a separate file for each service, set `schema-allow-merge` to `false`.
217+
218+
=== Merge mode (default)
219+
All services are bundled into one file.
220+
221+
[source]
222+
----
223+
schema-allow-merge=true
224+
----
225+
226+
=== Split mode
227+
Each service gets its own file, such as `GreeterService-openapi.json` or `AnotherService-openapi.yaml`.
228+
229+
[source]
230+
----
231+
schema-allow-merge=false
232+
----
233+
234+
[[openapi-configuration-file]]
235+
== Configuration file
236+
237+
You can customize the output by providing a YAML or JSON configuration file. This allows you to set or override these fields:
238+
239+
* `info`: API metadata like title, version, and contact info.
240+
* `servers`: Target server URLs.
241+
* `security`: Global security requirements.
242+
* `tags`: Tag definitions.
243+
* `externalDocs`: Links to outside documentation.
244+
* `components.securitySchemes`: Security scheme definitions.
245+
246+
.Example configuration (openapi-config.yaml)
247+
[source,yaml]
248+
----
249+
openapi: 3.0.0
250+
info:
251+
title: My Greeting API
252+
version: 2.0.0
253+
description: A greeting service
254+
contact:
255+
name: API Support
256+
email: support@example.com
257+
servers:
258+
- url: https://api.example.com
259+
description: Production
260+
security:
261+
- bearerAuth: []
262+
components:
263+
securitySchemes:
264+
bearerAuth:
265+
type: http
266+
scheme: bearer
267+
bearerFormat: JWT
268+
----
269+
270+
=== Using the configuration file
271+
272+
[source,xml]
273+
----
274+
<jvmMavenPlugin>
275+
<groupId>io.vertx</groupId>
276+
<artifactId>vertx-grpc-protoc-plugin2</artifactId>
277+
<version>${vertx.version}</version>
278+
<mainClass>io.vertx.grpc.plugin.VertxGrpcGenerator</mainClass>
279+
<options>schema-output-format=openapi-json,schema-config=${project.basedir}/openapi-config.yaml</options>
280+
</jvmMavenPlugin>
281+
----
282+
283+
The plugin merges your configuration with the generated spec using these rules:
284+
285+
1. Values in `info`, `servers`, `security`, `tags`, and `externalDocs` *replace* whatever the plugin generates.
286+
2. Values in `components.securitySchemes` are *added* to the generated schemas.
287+
3. The plugin always preserves the generated `paths` and `components.schemas`. Your config file cannot override these.
288+
289+
== Example
290+
291+
If you have a proto file with HTTP annotations like this:
292+
293+
[source,proto]
294+
----
295+
syntax = "proto3";
296+
import "google/api/http.proto";
297+
option java_package = "examples";
298+
299+
service Greeter {
300+
rpc SayHello (HelloRequest) returns (HelloReply) {
301+
option (google.api.http) = {
302+
post: "/v1/hello"
303+
body: "*"
304+
additional_bindings {
305+
get: "/v1/hello/{name}"
306+
}
307+
};
308+
}
309+
}
310+
311+
message HelloRequest {
312+
string name = 1;
313+
}
314+
315+
message HelloReply {
316+
string message = 1;
317+
}
318+
----
319+
320+
The plugin produces an OpenAPI spec for the `/v1/hello` endpoints, including the request and response schemas. You can find the output in the protobuf output root folder.
321+
174322
If you're using Gradle you need to add the plugin:
175323

176324
[source,groovy]
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{
2+
"openapi": "3.0.0",
3+
"info": {
4+
"title": "examples.grpc gRPC API",
5+
"version": "1.0.0",
6+
"description": "OpenAPI specification generated from gRPC service definitions with HTTP transcoding"
7+
},
8+
"servers": [
9+
{
10+
"url": "http://localhost:8080",
11+
"description": "gRPC server"
12+
}
13+
],
14+
"paths": {
15+
"/v1/hello/{name}": {
16+
"GET": {
17+
"summary": "SayHello",
18+
"description": "",
19+
"operationId": "sayHello",
20+
"tags": [""],
21+
"responses": {
22+
"200": {
23+
"description": "Successful response",
24+
"content": {
25+
"application/json": {
26+
"schema": {
27+
"$ref": "#/components/schemas/HelloReply"
28+
}
29+
}
30+
}
31+
},
32+
"default": {
33+
"description": "Error response",
34+
"content": {
35+
"application/json": {
36+
"schema": {
37+
"$ref": "#/components/schemas/GrpcError"
38+
}
39+
}
40+
}
41+
}
42+
}
43+
}
44+
},
45+
},
46+
"components": {
47+
"schemas": {
48+
"HelloRequest": {
49+
"type": "object",
50+
"description": "Protobuf message type: .examples.grpc.HelloRequest",
51+
"properties": {
52+
"name": {
53+
"type": "string"
54+
},
55+
}
56+
},
57+
"HelloReply": {
58+
"type": "object",
59+
"description": "Protobuf message type: .examples.grpc.HelloReply",
60+
"properties": {
61+
"message": {
62+
"type": "string"
63+
},
64+
}
65+
},
66+
"GrpcError": {
67+
"type": "object",
68+
"properties": {
69+
"code": {
70+
"type": "integer",
71+
"description": "gRPC status code"
72+
},
73+
"message": {
74+
"type": "string",
75+
"description": "Error message"
76+
},
77+
"details": {
78+
"type": "array",
79+
"items": {
80+
"type": "object"
81+
},
82+
"description": "Additional error details"
83+
}
84+
}
85+
}
86+
}
87+
}
88+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
openapi: 3.0.0
2+
info:
3+
title: examples.grpc gRPC API
4+
version: 1.0.0
5+
description: OpenAPI specification generated from gRPC service definitions with HTTP transcoding
6+
servers:
7+
- url: http://localhost:8080
8+
description: gRPC server
9+
paths:
10+
/v1/hello/{name}:
11+
GET:
12+
summary: SayHello
13+
description:
14+
operationId: sayHello
15+
tags:
16+
-
17+
responses:
18+
'200':
19+
description: Successful response
20+
content:
21+
application/json:
22+
schema:
23+
$ref: '#/components/schemas/HelloReply'
24+
default:
25+
description: Error response
26+
content:
27+
application/json:
28+
schema:
29+
$ref: '#/components/schemas/GrpcError'
30+
components:
31+
schemas:
32+
HelloRequest:
33+
type: object
34+
description: Protobuf message type .examples.grpc.HelloRequest
35+
properties:
36+
name:
37+
type: string
38+
HelloReply:
39+
type: object
40+
description: Protobuf message type .examples.grpc.HelloReply
41+
properties:
42+
message:
43+
type: string
44+
GrpcError:
45+
type: object
46+
properties:
47+
code:
48+
type: integer
49+
description: gRPC status code
50+
message:
51+
type: string
52+
description: Error message
53+
details:
54+
type: array
55+
items:
56+
type: object
57+
description: Additional error details

vertx-grpc-it/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@
8989
<artifactId>testcontainers</artifactId>
9090
<scope>test</scope>
9191
</dependency>
92+
<dependency>
93+
<groupId>io.vertx</groupId>
94+
<artifactId>vertx-openapi</artifactId>
95+
<scope>test</scope>
96+
</dependency>
9297
</dependencies>
9398

9499
<build>
@@ -136,7 +141,7 @@
136141
<artifactId>vertx-grpc-protoc-plugin2</artifactId>
137142
<version>${project.version}</version>
138143
<mainClass>io.vertx.grpc.plugin.VertxGrpcGenerator</mainClass>
139-
<options>grpc-client=true,grpc-service=true,grpc-io=true</options>
144+
<options>grpc-client=true,grpc-service=true,grpc-io=true,schema-output-format=openapi-json+openapi-yaml,schema-config=${project.basedir}/src/test/resources/openapi-config.yaml</options>
140145
</jvmMavenPlugin>
141146
</jvmMavenPlugins>
142147
</configuration>

0 commit comments

Comments
 (0)