Skip to content

A tool for generating Protobuf v3 schemas and gRPC service definitions from OpenAPI specifications

License

Notifications You must be signed in to change notification settings

nytimes/openapi2proto

Repository files navigation

openapi2proto Build Status

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 install github.com/NYTimes/openapi2proto/cmd/openapi2proto@latest

On Older versions of Go (<1.15), use:

go get -u github.com/NYTimes/openapi2proto/cmd/openapi2proto

Run

There are some 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 than Stdout. Defaults to Stdout 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.
  • -skip-deprecated-rpcs to skip generation of rpcs for endpoints marked as deprecated. This is disabled by default.
  • -namespace-enums to enable inserting the enum name as an enum prefix for each value. This is disabled by default.
  • -add-autogenerated-comment to add comment on top of the generated protos that those files are autogenerated and should not be modified. 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"

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}"
        };
    }
}