openapi2proto
This tool will accept an OpenAPI/Swagger definition (yaml or JSON) and generate a Protobuf v3 schema and gRPC service definition from it.
Install
To install, have Go installed with $GOPATH/bin
on your $PATH
and then:
go get -u github.com/NYTimes/openapi2proto/cmd/openapi2proto
Run
There are 4 CLI flags for using the tool:
-spec
to point to the appropriate OpenAPI spec file-annotate
to include (google.api.http options) for grpc-gateway users. This is disabled by default.-out
to have the output written to a file rather thanStdout
. Defaults toStdout
if this is not specified.-indent
to override the default indentation for Protobuf specs of 4 spaces.-skip-rpcs
to skip generation of rpcs. These are generated by default.-namespace-enums
to enable inserting the enum name as an enum prefix for each value. This is disabled by default.
Protobuf Tags
- To allow for more control over how your protobuf schema evolves, all parameters and property definitions will accept an optional extension parameter,
x-proto-tag
, that will overide the generated tag with the value supplied.
External Files
- Any externally referenced Open API spec will be fetched and inlined.
- Any externally referenced Protobuf files will be added as imports.
- Example usage:
$ref: "google/protobuf/timestamp.proto#/google.protobuf.Timestamp"
- Example usage:
Global Options
Protocol Buffer options such as package names are supported via x-global-options
key.
x-global-options:
go_package: myawesomepackage
Will generate:
option go_package = "myawesomepackage"
Extensions
Global extensions may be generated by specifying x-extensions
key.
x-extensions:
- base: google.protobuf.MethodOptions
fields:
- name: role
type: string
number: 50001
- name: visibility
type: string
number: 50002
- name: timeout
type: int32
number: 50003
Will generate:
extend google.protobuf.MethodOptions {
string role = 50001;
string visibility = 50002;
int32 timeout = 50003;
}
Nested extensions are currently not supported.
Method Options
Method options may be generated by specifying the x-options
key within each method.
paths:
/foo
post:
x-options:
bar: baz
Will generate:
rpc foo(...) returns (...) {
option (bar) = "baz";
}
Caveats
- Fields with scalar types that can also be "null" will get wrapped with one of the
google.protobuf.*Value
types. - Fields with that have more than 1 type and the second type is not "null" will be replaced with the
google.protobuf.Any
type. - Endpoints that respond with an array will be wrapped with a message type that has a single field, 'items', that contains the array.
- Only "200" and "201" responses are inspected for determining the expected return value for RPC endpoints.
- To prevent enum collisions and to match the protobuf style guide, enum values will be
CAPITALS_WITH_UNDERSCORES
and nested enum values will have their parent types prepended to their names.
Example
╰─➤ openapi2proto -spec swagger.yaml -annotate
syntax = "proto3";
package swaggerpetstore;
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
message AddPetRequest {
message PetMessage {
int64 id = 1;
string name = 2;
string tag = 3;
}
// Pet to add to the store
PetMessage pet = 1;
}
message AddPetResponse {
int64 id = 1;
string name = 2;
string tag = 3;
}
message DeletePetRequest {
// ID of pet to delete
int64 id = 1;
}
message FindPetByIdRequest {
// ID of pet to fetch
int64 id = 1;
}
message FindPetByIdResponse {
int64 id = 1;
string name = 2;
string tag = 3;
}
message FindPetsByIdsRequest {
repeated string ids = 1;
// maximum number of results to return
int32 limit = 2;
}
message FindPetsByIdsResponse {
message PetsMessage {
int64 id = 1;
string name = 2;
string tag = 3;
}
repeated PetsMessage pets = 1;
}
message FindPetsRequest {
// maximum number of results to return
int32 limit = 1;
// tags to filter by
repeated string tags = 2;
}
message FindPetsResponse {
message PetsMessage {
int64 id = 1;
string name = 2;
string tag = 3;
}
repeated PetsMessage pets = 1;
}
service SwaggerPetstoreService {
// Creates a new pet in the store. Duplicates are allowed
rpc AddPet(AddPetRequest) returns (AddPetResponse) {
option (google.api.http) = {
post: "/api/pets"
body: "pet"
};
}
// deletes a single pet based on the ID supplied
rpc DeletePet(DeletePetRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/api/pets/{id}"
};
}
// Returns a user based on a single ID, if the user does not have access to the pet
rpc FindPetById(FindPetByIdRequest) returns (FindPetByIdResponse) {
option (google.api.http) = {
get: "/api/pets/{id}"
};
}
// Returns all pets from the system that the user has access to
rpc FindPets(FindPetsRequest) returns (FindPetsResponse) {
option (google.api.http) = {
get: "/api/pets"
};
}
// Returns all pets from the system that the user has access to
rpc FindPetsByIds(FindPetsByIdsRequest) returns (FindPetsByIdsResponse) {
option (google.api.http) = {
get: "/api/pets/{ids}"
};
}
}