Yes, this is another protoc generator for OpenAPI. I created this for a couple reasons...
- I wanted to learn protoc generation with a real-world problem.
- The official google one sticks to gRPC and envoy standards. My team and I use Twirp and other REST frameworks. Sometimes you just want to define models and an API for docs.
- Others try to do too much per the spec and fail to do the most common things well.
DISCLAIMER: This will be a limited subset of the OAPI3 specification. Not everything will make it in here. Why? Read the last bullet point above. :)
Some patterns were heavily inspired by gnostic.
go install github.com/technicallyjosh/protoc-gen-openapi@latest
| Option | Description | Default |
|---|---|---|
version | The version of the API. | 0.0.1 |
title | The title of the API. | |
description | A description of the API. | |
include | A list of proto package names to include only. ignore is ran after this | |
ignore | A list of proto package names to ignore delimited by pipes. | |
default_response | The default response to be used.1 | |
content_type | The content type to be associated with all operations.1 | application/json |
json_names | Use the JSON names that Protobuf provides. Otherwise, proto field names are used. | false |
json_out | Create a JSON file instead of the default YAML. | false |
host | The host to be used for all operations.1 | |
filename | Specify the filename to output. | openapi.yaml |
1Can be overridden on a file, service, or method.
Below are some basic examples on how to use this generator.
protoc \
--openapi_out=. \
--openapi_opt=version=1.0.0 \
--openapi_opt=title="My Awesome API" \
api/some_service.protobuf.yaml
# ... other thingsdeps:
- buf.build/technicallyjosh/protoc-gen-openapibuf.gen.yaml
plugins:
- name: goout: apiopt:
- paths=source_relative
- name: openapistrategy: all # important so all files are ran in the same generation.out: apiopt:
- title=My Awesome API
- description=Look how awesome my API is!
- ignore=module.v1|module.v2
- default_response=SomeErrorObjectsyntax="proto3";
import"oapi/v1/field.proto";
import"oapi/v1/file.proto";
import"oapi/v1/method.proto";
import"oapi/v1/service.proto";
option(oapi.v1.file)= {
servers {
url: "myawesomeapi.com"
}
security_schemes: {
name: "bearer_auth"scheme: {
type: "http"scheme: "bearer"bearer_format: "JWT"
}
}
// Since this is at the file level, it's applied to all.
security: {
name: "bearer_auth"scopes: ["read:resource"]
}
};
serviceMyService {
option(oapi.v1.service)= {
prefix: "/v1"x_display_name: "My Service"
};
rpcCreateSomething (CreateSomethingRequest) returns (CreateSomethingResponse) {
option(oapi.v1.method)= {
post: "create-something"summary: "Create Something"status: 201
};
}
}
messageCreateSomethingRequest {
// The name of something.// Example: something-awesomestringname=1 [(oapi.v1.required) = true];
}
messageCreateSomethingResponse {
// The ID of something.stringid=1;
stringname=2;
}Note
Defining features is a work in progress. I aim to explain all that's possible the best I can.
You can define servers at the file, service, or method level. Each one overrides the previous. This allows for more advanced composition.
Example:
syntax="proto3";
import"google/protobuf/empty.proto";
import"oapi/v1/file.proto";
import"oapi/v1/method.proto";
import"oapi/v1/service.proto";
option(oapi.v1.file)= {
servers {
url: "myawesomeapi.com"// file-defined for all services and methods
}
};
serviceMyService {
option(oapi.v1.service)= {
servers {
url: "myawesomeapi2.com"// overrides file-defined
}
};
rpcCreateSomething (google.protobuf.Empty) returns (google.protobuf.Empty) {
option(oapi.v1.method)= {
servers {
url: "myaweseomeapi3.com"// overrides service-defined
}
};
}
}Each service can have a path prefix set for all methods to inherit. This is useful when versioning your API or if you have a parameter that is defined for each method route.
You can override the entire path in the method by starting the path out with
a /.
Example:
syntax="proto3";
import"google/protobuf/empty.proto";
import"oapi/v1/file.proto";
import"oapi/v1/method.proto";
import"oapi/v1/service.proto";
option(oapi.v1.file)= {
servers {
url: "myawesomeapi.com"
}
};
serviceMyService {
option(oapi.v1.service)= {
prefix: "/v1"
};
rpcCreateSomething (google.protobuf.Empty) returns (google.protobuf.Empty) {
option(oapi.v1.method)= {
post: "create"// becomes /v1/create
};
}
rpcOverrideSomething (google.protobuf.Empty) returns (google.protobuf.Empty) {
option(oapi.v1.method)= {
get: "/create"// becomes /create
};
}
}- Enum requirements on fields
Coming... Right now I prefer that it's just me until I get a solid hold on generator patterns and the package is stable. I'm fully open to any suggestions though!