···1818 googleListValueType = "google.protobuf.ListValue"
1919 googleStructType = "google.protobuf.Struct"
2020 googleValueType = "google.protobuf.Value"
2121+ googleEmptyType = "google.protobuf.Empty"
21222223 googleMoneyType = "google.type.Money"
2324)
···9293 var reqMediaType *openapi3.MediaType
9394 switch rpc.RequestType {
9495 case "google.protobuf.Empty":
9595- reqMediaType = openapi3.NewMediaType()
9696+ gen.addGoogleEmptySchema()
9697 default:
9797- if strings.Contains(rpc.RequestType, ".") {
9898- reqMediaType = &openapi3.MediaType{
9999- Schema: &openapi3.SchemaRef{
100100- Ref: fmt.Sprintf("#/components/schemas/%s", rpc.RequestType),
101101- },
102102- }
103103- } else {
104104- reqMediaType = &openapi3.MediaType{
105105- Schema: &openapi3.SchemaRef{
106106- Ref: fmt.Sprintf("#/components/schemas/%s.%s", gen.packageName, rpc.RequestType),
107107- },
108108- }
9898+ }
9999+ if strings.Contains(rpc.RequestType, ".") {
100100+ reqMediaType = &openapi3.MediaType{
101101+ Schema: &openapi3.SchemaRef{
102102+ Ref: fmt.Sprintf("#/components/schemas/%s", rpc.RequestType),
103103+ },
104104+ }
105105+ } else {
106106+ reqMediaType = &openapi3.MediaType{
107107+ Schema: &openapi3.SchemaRef{
108108+ Ref: fmt.Sprintf("#/components/schemas/%s.%s", gen.packageName, rpc.RequestType),
109109+ },
109110 }
110111 }
111112112113 var resMediaType *openapi3.MediaType
113114 switch rpc.ReturnsType {
114115 case "google.protobuf.Empty":
115115- resMediaType = openapi3.NewMediaType()
116116+ gen.addGoogleEmptySchema()
116117 default:
117117- if strings.Contains(rpc.ReturnsType, ".") {
118118- resMediaType = &openapi3.MediaType{
119119- Schema: &openapi3.SchemaRef{
120120- Ref: fmt.Sprintf("#/components/schemas/%s", rpc.ReturnsType),
121121- },
122122- }
123123- } else {
124124- resMediaType = &openapi3.MediaType{
125125- Schema: &openapi3.SchemaRef{
126126- Ref: fmt.Sprintf("#/components/schemas/%s.%s", gen.packageName, rpc.ReturnsType),
127127- },
128128- }
118118+ }
119119+120120+ if strings.Contains(rpc.ReturnsType, ".") {
121121+ resMediaType = &openapi3.MediaType{
122122+ Schema: &openapi3.SchemaRef{
123123+ Ref: fmt.Sprintf("#/components/schemas/%s", rpc.ReturnsType),
124124+ },
125125+ }
126126+ } else {
127127+ resMediaType = &openapi3.MediaType{
128128+ Schema: &openapi3.SchemaRef{
129129+ Ref: fmt.Sprintf("#/components/schemas/%s.%s", gen.packageName, rpc.ReturnsType),
130130+ },
129131 }
130132 }
131133···283285 case googleMoneyType:
284286 slog.Debug("Money", "name", fieldName, "type", fieldType, "format", fieldFormat)
285287 gen.addGoogleMoneySchema()
288288+ case googleEmptyType:
289289+ slog.Debug("Empty", "name", fieldName, "type", fieldType, "format", fieldFormat)
290290+ gen.addGoogleEmptySchema()
286291 default:
287292 slog.Debug("Default", "name", fieldName, "type", fieldType, "format", fieldFormat)
288293 }
···314319 Type: "object",
315320 },
316321 },
322322+ },
323323+ }
324324+}
325325+326326+func (gen *generator) addGoogleEmptySchema() {
327327+ if _, ok := gen.openAPIV3.Components.Schemas[googleEmptyType]; ok {
328328+ return
329329+ }
330330+ gen.openAPIV3.Components.Schemas[googleEmptyType] = &openapi3.SchemaRef{
331331+ Value: &openapi3.Schema{
332332+ Description: "A generic empty message that you can re-use to avoid defining duplicated empty messages in your APIs. A typical example is to use it as the request or the response type of an API method. For instance:",
333333+ Type: "object",
317334 },
318335 }
319336}
+1-1
pb/generate.go
···77func init() {}
8899//go:generate protoc --proto_path=. --go_out=. --go_opt=paths=source_relative --twirp_out=. --twirp_opt=paths=source_relative xesite.proto
1010-//go:generate go run ../cmd/twirp-openapi-gen --in=xesite.proto --path-prefix=/api --servers=https://xeiaso.net --title=xeiaso.net --out=openapi.json
1010+//go:generate go run ../cmd/twirp-openapi-gen --verbose --in=xesite.proto --path-prefix=/api --servers=https://xeiaso.net --title=xeiaso.net --out=openapi.json
11111212//go:embed xesite.proto openapi.json external/*.proto
1313var Proto embed.FS
+14-2
pb/openapi.json
···11{
22 "components": {
33 "schemas": {
44+ "google.protobuf.Empty": {
55+ "description": "A generic empty message that you can re-use to avoid defining duplicated empty messages in your APIs. A typical example is to use it as the request or the response type of an API method. For instance:",
66+ "type": "object"
77+ },
48 "protofeed.Attachment": {
59 "description": "Attachment is an object representing a file associated with an item.",
610 "properties": {
···221225 "description": "\nGet fetches the current feed of posts.",
222226 "requestBody": {
223227 "content": {
224224- "application/json": {}
228228+ "application/json": {
229229+ "schema": {
230230+ "$ref": "#/components/schemas/google.protobuf.Empty"
231231+ }
232232+ }
225233 }
226234 },
227235 "responses": {
···244252 "description": "\nMetadata fetches the build metadata of the version of xesite that is\ncurrently running.",
245253 "requestBody": {
246254 "content": {
247247- "application/json": {}
255255+ "application/json": {
256256+ "schema": {
257257+ "$ref": "#/components/schemas/google.protobuf.Empty"
258258+ }
259259+ }
248260 }
249261 },
250262 "responses": {