Skip to content

Commit 6dc0f17

Browse files
authored
Generate OpenAPI v2 and v3 specs (#146)
Expose the OpenAPI docs generated in our main API repo
1 parent d8404d8 commit 6dc0f17

File tree

5 files changed

+175
-2
lines changed

5 files changed

+175
-2
lines changed

Makefile

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ all: install test
55
install: grpc-install mockgen-install goimports-install update-proto
66

77
# Compile proto files.
8-
proto: grpc goimports proxy grpc-mock copyright
8+
proto: http-api-docs grpc goimports proxy grpc-mock copyright
99

1010
# Update submodule and compile proto files.
1111
update-proto: update-proto-submodule proto update-dependencies gomodtidy
@@ -32,6 +32,9 @@ PROTO_IMPORTS = \
3232
-I=$(PROTO_ROOT)
3333
PROTO_PATHS = paths=source_relative:$(PROTO_OUT)
3434

35+
OAPI_ROOT := $(PROTO_ROOT)/openapi
36+
OAPI_OUT := temporalproto/openapi
37+
3538
$(PROTO_OUT):
3639
mkdir $(PROTO_OUT)
3740

@@ -41,7 +44,7 @@ update-proto-submodule:
4144
git -c protocol.file.allow=always submodule update --init --force --remote $(PROTO_ROOT)
4245

4346
##### Compile proto files for go #####
44-
grpc: go-grpc copy-helpers
47+
grpc: http-api-docs go-grpc copy-helpers
4548

4649
# Only install helper when its source has changed
4750
HELPER_FILES = $(shell find ./cmd/protoc-gen-go-helpers)
@@ -65,6 +68,13 @@ go-grpc: clean .go-helpers-installed $(PROTO_OUT)
6568

6669
mv -f $(PROTO_OUT)/temporal/api/* $(PROTO_OUT) && rm -rf $(PROTO_OUT)/temporal
6770

71+
http-api-docs: go-grpc
72+
go run cmd/encode-openapi-spec/main.go \
73+
-v2=$(OAPI_ROOT)/openapiv2.json \
74+
-v2-out=$(OAPI_OUT)/openapiv2.go \
75+
-v3=$(OAPI_ROOT)/openapiv3.yaml \
76+
-v3-out=$(OAPI_OUT)/openapiv3.go
77+
6878
# Copy the payload helpers
6979
copy-helpers:
7080
chmod +w $(PROTO_OUT)/common/v1/payload_json.go 2>/dev/null || true

cmd/encode-openapi-spec/main.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// The MIT License
2+
//
3+
// Copyright (c) 2022 Temporal Technologies Inc. All rights reserved.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
// THE SOFTWARE.
22+
23+
package main
24+
25+
import (
26+
"bytes"
27+
"compress/gzip"
28+
"flag"
29+
"fmt"
30+
"go/format"
31+
"html/template"
32+
"io"
33+
"os"
34+
"path/filepath"
35+
"strings"
36+
)
37+
38+
type templateInput struct {
39+
Version int
40+
Format string
41+
Spec string
42+
}
43+
44+
const tmpl = `package openapi
45+
46+
// OpenAPIV{{.Version}}{{.Format}}Spec contains a gzip-compressed {{.Format}} file specifying the Temporal HTTP API
47+
var OpenAPIV{{.Version}}{{.Format}}Spec = {{.Spec}}`
48+
49+
func die(msg string, args ...any) {
50+
fmt.Fprintf(os.Stderr, msg+"\n", args...)
51+
os.Exit(1)
52+
}
53+
54+
func prepareSpec(version int, input, output string) {
55+
extension := strings.TrimPrefix(filepath.Ext(input), ".")
56+
f, err := os.Open(input)
57+
if err != nil {
58+
die("Failed to open spec file %q: %v", input, err)
59+
}
60+
defer f.Close()
61+
62+
var b bytes.Buffer
63+
w := gzip.NewWriter(&b)
64+
if _, err := io.Copy(w, f); err != nil {
65+
die("Failed to compress v%d spec: %s", version, err)
66+
}
67+
if err := w.Close(); err != nil {
68+
die("Failed to compress v%d spec: %s", version, err)
69+
}
70+
71+
var src bytes.Buffer
72+
t := template.Must(template.New("spec").Parse(tmpl))
73+
t.Execute(&src, templateInput{
74+
Version: version,
75+
Format: strings.ToTitle(extension),
76+
Spec: fmt.Sprintf("%#v", b.Bytes()),
77+
})
78+
79+
fmtd, err := format.Source(src.Bytes())
80+
if err != nil {
81+
die("Failed to format generated v%d code: %s", version, err)
82+
}
83+
84+
out, err := os.Create(output)
85+
if err != nil {
86+
die("Failed to open %q: %s", output, err)
87+
}
88+
defer out.Close()
89+
if _, err := out.Write(fmtd); err != nil {
90+
die("Failed to write v%d code: %s", version, err)
91+
}
92+
93+
}
94+
95+
func main() {
96+
var v2Path, v3Path, v2Out, v3Out string
97+
flag.StringVar(&v2Path, "v2", "", "The path to the OpenAPI v2 spec file. Required.")
98+
flag.StringVar(&v3Path, "v3", "", "The path to the OpenAPI v3 spec file. Required.")
99+
flag.StringVar(&v2Out, "v2-out", "", "The path to the v2 output file. Required.")
100+
flag.StringVar(&v3Out, "v3-out", "", "The path to the v3 output file. Required.")
101+
flag.Parse()
102+
if v2Path == "" || v3Path == "" || v2Out == "" || v3Out == "" {
103+
flag.Usage()
104+
os.Exit(127)
105+
}
106+
107+
prepareSpec(2, v2Path, v2Out)
108+
prepareSpec(3, v3Path, v3Out)
109+
}

temporalproto/openapi/openapiv2.go

Lines changed: 26 additions & 0 deletions
Large diffs are not rendered by default.

temporalproto/openapi/openapiv3.go

Lines changed: 26 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Arbitrary payload data in an unconstrained format.
2+
This may be activity input parameters, a workflow result, a memo, etc.

0 commit comments

Comments
 (0)