Skip to content

Commit

Permalink
Fix: Generate models for all JSON media types
Browse files Browse the repository at this point in the history
As highlighted in #1168, we have some cases where JSON-compatible media
types aren't having their respective models generated, as we previously
only looked for `application/json`.

To resolve this, we can make sure that any media types that are
compatible with JSON (via our utility method) can have their types
generated.

This is a fix for #1168, which could also be deemed a feature. However,
as this has broken in the upgrade from v1.12.x to v1.13.x, this is being
treated as a feature.

Closes #1168.
  • Loading branch information
jamietanna committed Aug 7, 2023
1 parent f20166f commit e90f06d
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 13 deletions.
162 changes: 162 additions & 0 deletions internal/test/issues/issue-1168/api.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions internal/test/issues/issue-1168/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package issue1168

//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.config.yaml spec.yaml
5 changes: 5 additions & 0 deletions internal/test/issues/issue-1168/server.config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package: issue1168
output:
api.gen.go
generate:
models: true
95 changes: 95 additions & 0 deletions internal/test/issues/issue-1168/spec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
# Copyright 2023 Coros, Corp. All Rights Reserved.
#
# Apache 2.0 Licensed; the portion included from
# https://github.com/zalando/problem/ is MIT licensed
#
openapi: 3.0.3
info:
version: 1.0.0
title: Test
description: Provides access to things
license:
name: Apache License 2.0
url: http://www.example.com/XXX

servers:
- url: https://www.example.com/api
description: Production environment

paths:
/v1/test:
get:
summary: Get it
responses:
'200':
description: Successful response
content:
text/plain:
type: string
'400':
$ref: '#/components/responses/Misc400Error'
'404':
$ref: '#/components/responses/Misc404Error'

components:
responses:
Misc400Error:
description: Bad request
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
Misc404Error:
description: Not found
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'

schemas:
# Fetched from https://opensource.zalando.com/problem/schema.yaml
# and slightly modified.
# Part of https://github.com/zalando/problem/; MIT License
ProblemDetails:
type: object
additionalProperties: true
properties:
type:
type: string
format: uri
description: >-
An absolute URI that identifies the problem type. When dereferenced,
it SHOULD provide human-readable documentation for the problem type
(e.g., using HTML).
default: 'about:blank'
example: 'https://zalando.github.io/problem/constraint-violation'
title:
type: string
description: >-
A short, summary of the problem type. Written in english and readable
for engineers (usually not suited for non technical stakeholders and
not localized); example: Service Unavailable
status:
type: integer
format: int32
description: >-
The HTTP status code generated by the origin server for this occurrence
of the problem.
minimum: 100
maximum: 600
exclusiveMaximum: true
example: 503
detail:
type: string
description: >-
A human readable explanation specific to this occurrence of the
problem.
example: Connection to database timed out
instance:
type: string
format: uri
description: >-
An absolute URI that identifies the specific occurrence of the problem.
It may or may not yield further information if dereferenced.
# </MIT License>
40 changes: 27 additions & 13 deletions pkg/codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"strings"
"text/template"

"github.com/deepmap/oapi-codegen/pkg/util"
"github.com/getkin/kin-openapi/openapi3"
"golang.org/x/tools/imports"
)
Expand Down Expand Up @@ -540,12 +541,15 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
responseOrRef := responses[responseName]

// We have to generate the response object. We're only going to
// handle application/json media types here. Other responses should
// handle media types that conform to JSON. Other responses should
// simply be specified as strings or byte arrays.
response := responseOrRef.Value
jsonResponse, found := response.Content["application/json"]
if found {
goType, err := GenerateGoSchema(jsonResponse.Schema, []string{responseName})
for mediaType, response := range response.Content {
if !util.IsMediaTypeJson(mediaType) {
continue
}

goType, err := GenerateGoSchema(response.Schema, []string{responseName})
if err != nil {
return nil, fmt.Errorf("error generating Go type for schema in response %s: %w", responseName, err)
}
Expand All @@ -569,6 +573,7 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
}
typeDef.TypeName = SchemaNameToTypeName(refType)
}

types = append(types, typeDef)
}
}
Expand All @@ -586,9 +591,12 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open
// As for responses, we will only generate Go code for JSON bodies,
// the other body formats are up to the user.
response := requestBodyRef.Value
jsonBody, found := response.Content["application/json"]
if found {
goType, err := GenerateGoSchema(jsonBody.Schema, []string{requestBodyName})
for mediaType, body := range response.Content {
if !util.IsMediaTypeJson(mediaType) {
continue
}

goType, err := GenerateGoSchema(body.Schema, []string{requestBodyName})
if err != nil {
return nil, fmt.Errorf("error generating Go type for schema in body %s: %w", requestBodyName, err)
}
Expand Down Expand Up @@ -1048,9 +1056,12 @@ func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[st
res := map[string]goImport{}
for _, r := range bodies {
response := r.Value
jsonBody, found := response.Content["application/json"]
if found {
imprts, err := GoSchemaImports(jsonBody.Schema)
for mediaType, body := range response.Content {
if !util.IsMediaTypeJson(mediaType) {
continue
}

imprts, err := GoSchemaImports(body.Schema)
if err != nil {
return nil, err
}
Expand All @@ -1064,9 +1075,12 @@ func GetResponsesImports(responses map[string]*openapi3.ResponseRef) (map[string
res := map[string]goImport{}
for _, r := range responses {
response := r.Value
jsonResponse, found := response.Content["application/json"]
if found {
imprts, err := GoSchemaImports(jsonResponse.Schema)
for mediaType, body := range response.Content {
if !util.IsMediaTypeJson(mediaType) {
continue
}

imprts, err := GoSchemaImports(body.Schema)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit e90f06d

Please sign in to comment.