Skip to content

Commit bff9920

Browse files
committed
Allow generating a list of strict operation IDs
The generated code presently passes a strict operation ID to every `StrictMiddlewareFunc` you have configured for a server. This is great for writing auth-like middleware: you can have a unified function that handles authorization on the *operational* level, and test it by itself. This is not so great if you're forgetful (like the author of this MR) and sometimes forget to write those tests... or to update your handler function. By generating a list of all operation handlers, we make it much easier to write a test that asserts that some `StrictMiddlewareFunc` has proper behavior for *all* operation IDs.
1 parent 2bf1525 commit bff9920

9 files changed

Lines changed: 124 additions & 0 deletions

File tree

configuration-schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
"server-urls": {
6565
"type": "boolean",
6666
"description": "Generate types for the `Server` definitions' URLs, instead of needing to provide your own values"
67+
},
68+
"strict-operation-list": {
69+
"type": "boolean",
70+
"description": "Generate a var StrictOperationIDs []string containing the normalized operation name passed to every StrictMiddlewareFunc call. Makes it straightforward to write generic tests that assert a behaviour holds for every strict operation."
6771
}
6872
}
6973
},
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# yaml-language-server: $schema=../../../configuration-schema.json
2+
package: operationlist
3+
generate:
4+
strict-operation-list: true
5+
output: operation_list.gen.go
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package operationlist
2+
3+
//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml

internal/test/operation-list/operation_list.gen.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package operationlist
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestStrictOperationIDs(t *testing.T) {
10+
expected := []string{"ListUsers", "CreateUser", "GetUser", "DeleteUser"}
11+
assert.ElementsMatch(t, expected, StrictOperationIDs)
12+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
openapi: "3.0.1"
2+
info:
3+
version: 1.0.0
4+
title: Operation List Test
5+
paths:
6+
/users:
7+
get:
8+
summary: List users
9+
operationId: listUsers
10+
responses:
11+
'200':
12+
description: OK
13+
post:
14+
summary: Create user
15+
operationId: createUser
16+
responses:
17+
'201':
18+
description: Created
19+
/users/{id}:
20+
get:
21+
summary: Get user
22+
operationId: getUser
23+
parameters:
24+
- name: id
25+
in: path
26+
required: true
27+
schema:
28+
type: string
29+
responses:
30+
'200':
31+
description: OK
32+
delete:
33+
summary: Delete user
34+
operationId: deleteUser
35+
parameters:
36+
- name: id
37+
in: path
38+
required: true
39+
schema:
40+
type: string
41+
responses:
42+
'204':
43+
description: No Content

pkg/codegen/codegen.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
406406
}
407407
}
408408

409+
var operationListOut string
410+
if opts.Generate.OperationList {
411+
operationListOut, err = GenerateStrictOperationList(t, ops)
412+
if err != nil {
413+
return "", fmt.Errorf("error generating operation list: %w", err)
414+
}
415+
}
416+
409417
var buf bytes.Buffer
410418
w := bufio.NewWriter(&buf)
411419

@@ -522,6 +530,13 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
522530
}
523531
}
524532

533+
if opts.Generate.OperationList {
534+
_, err = w.WriteString(operationListOut)
535+
if err != nil {
536+
return "", fmt.Errorf("error writing operation list: %w", err)
537+
}
538+
}
539+
525540
err = w.Flush()
526541
if err != nil {
527542
return "", fmt.Errorf("error flushing output buffer: %w", err)
@@ -664,6 +679,22 @@ func GenerateConstants(t *template.Template, ops []OperationDefinition) (string,
664679
return GenerateTemplates([]string{"constants.tmpl"}, t, constants)
665680
}
666681

682+
// StrictOperationList is the data model passed to the operation-list.tmpl template.
683+
type StrictOperationList struct {
684+
OperationIDs []string
685+
}
686+
687+
// GenerateStrictOperationList generates a slice of the normalized operation IDs
688+
// passed to StrictMiddlewareFunc at runtime. Each value is the Go-identifier form
689+
// of the operation (e.g. "ListUsers"), matching what the strict handler emits verbatim.
690+
func GenerateStrictOperationList(t *template.Template, ops []OperationDefinition) (string, error) {
691+
ids := make([]string, 0, len(ops))
692+
for _, op := range ops {
693+
ids = append(ids, op.OperationId)
694+
}
695+
return GenerateTemplates([]string{"operation-list.tmpl"}, t, StrictOperationList{OperationIDs: ids})
696+
}
697+
667698
// GenerateTypesForSchemas generates type definitions for any custom types defined in the
668699
// components/schemas section of the Swagger spec.
669700
func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.SchemaRef, excludeSchemas []string) ([]TypeDefinition, error) {

pkg/codegen/configuration.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ type GenerateOptions struct {
143143
EmbeddedSpec bool `yaml:"embedded-spec,omitempty"`
144144
// ServerURLs generates types for the `Server` definitions' URLs, instead of needing to provide your own values
145145
ServerURLs bool `yaml:"server-urls,omitempty"`
146+
// OperationList generates a slice of all strict operation IDs in the spec, useful for writing generic strict middleware tests
147+
OperationList bool `yaml:"strict-operation-list,omitempty"`
146148
}
147149

148150
// RouterImports returns the framework-specific and strict middleware imports
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// StrictOperationIDs lists the operation name string passed as the second
2+
// argument to every StrictMiddlewareFunc call. Each entry is the normalized
3+
// Go identifier for the operation (e.g. "ListUsers"), matching exactly what
4+
// the strict handler passes when it invokes the middleware chain.
5+
var StrictOperationIDs = []string{
6+
{{- range .OperationIDs}}
7+
"{{.}}",
8+
{{- end}}
9+
}

0 commit comments

Comments
 (0)