[BUG][Go-server] attempt to fix the controller-api mustache template for a nullable bodyParam (#20478)

* go-server: attempt  to fix the controller-api mustache template for a nullable bodyParam

* added to petstore an example to trigger the issue which this PR fixes
This commit is contained in:
Dragos Vingarzan 2025-02-19 10:09:32 +01:00 committed by GitHub
parent cd7cdb1e24
commit c2884b7b1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 769 additions and 1 deletions

View File

@ -624,7 +624,7 @@ func (c *{{classname}}Controller) {{nickname}}(w http.ResponseWriter, r *http.Re
{{/isArray}}
{{/isBodyParam}}
{{/allParams}}
result, err := c.service.{{nickname}}(r.Context(){{#allParams}}, {{paramName}}Param{{/allParams}})
result, err := c.service.{{nickname}}(r.Context(){{#allParams}}, {{#isNullable}}{{#isBodyParam}}&{{/isBodyParam}}{{/isNullable}}{{paramName}}Param{{/allParams}})
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)

View File

@ -582,6 +582,24 @@ paths:
$ref: '#/components/schemas/User'
description: Created user object
required: true
put:
tags:
- user
summary: Create user
description: This can only be done by the logged in user.
operationId: createUserNullable
responses:
default:
description: successful operation
security:
- api_key: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserNullable'
description: Created user object, with a nullable bodyParam
required: true
/user/createWithArray:
post:
tags:
@ -1052,6 +1070,66 @@ components:
name: User
required:
- deepSliceModel
UserNullable:
title: a User
description: A User who is purchasing from the pet store
type: object
nullable: true
properties:
id:
type: integer
format: int64
username:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
phone:
type: string
nullable: true
userStatus:
type: integer
format: int32
description: User Status
deepSliceModel:
nullable: true
type: array
description: An array 1-deep.
items:
type: array
description: An array 2-deep.
items:
type: array
description: An array 3-deep.
items:
$ref: '#/components/schemas/Tag'
deepSliceMap:
type: array
description: An array 1-deep.
items:
type: array
description: An array 2-deep.
items:
title: an Object
type: object
description: An array 3-deep.
properties:
tag:
$ref: '#/components/schemas/Tag'
Pet:
type: array
description: An array of pet.
items:
$ref: '#/components/schemas/Pet'
xml:
name: User
required:
- deepSliceModel
Tag:
title: Pet Tag
description: A tag for a pet

View File

@ -27,5 +27,6 @@ go/model_special_info.go
go/model_species.go
go/model_tag.go
go/model_user.go
go/model_user_nullable.go
go/routers.go
main.go

View File

@ -605,6 +605,24 @@ paths:
summary: Create user
tags:
- user
put:
description: This can only be done by the logged in user.
operationId: createUserNullable
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserNullable'
description: "Created user object, with a nullable bodyParam"
required: true
responses:
default:
description: successful operation
security:
- api_key: []
summary: Create user
tags:
- user
/user/createWithArray:
post:
description: ""
@ -1240,6 +1258,211 @@ components:
type: object
xml:
name: User
UserNullable:
description: A User who is purchasing from the pet store
example:
firstName: firstName
lastName: lastName
password: password
userStatus: 6
phone: phone
deepSliceModel:
- - - name: name
id: 1
- name: name
id: 1
- - name: name
id: 1
- name: name
id: 1
- - - name: name
id: 1
- name: name
id: 1
- - name: name
id: 1
- name: name
id: 1
id: 0
deepSliceMap:
- - tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- - tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
email: email
username: username
nullable: true
properties:
id:
format: int64
type: integer
username:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
phone:
nullable: true
type: string
userStatus:
description: User Status
format: int32
type: integer
deepSliceModel:
description: An array 1-deep.
items:
description: An array 2-deep.
items:
description: An array 3-deep.
items:
$ref: '#/components/schemas/Tag'
type: array
type: array
nullable: true
type: array
deepSliceMap:
description: An array 1-deep.
items:
description: An array 2-deep.
items:
$ref: '#/components/schemas/an_Object'
type: array
type: array
required:
- deepSliceModel
title: a User
type: object
xml:
name: User
Tag:
description: A tag for a pet
example:

View File

@ -58,6 +58,7 @@ type StoreAPIRouter interface {
// The UserAPIRouter implementation should parse necessary information from the http request,
// pass the data to a UserAPIServicer to perform the required actions, then write the service results to the http response.
type UserAPIRouter interface {
CreateUserNullable(http.ResponseWriter, *http.Request)
CreateUser(http.ResponseWriter, *http.Request)
CreateUsersWithArrayInput(http.ResponseWriter, *http.Request)
CreateUsersWithListInput(http.ResponseWriter, *http.Request)
@ -118,6 +119,7 @@ type StoreAPIServicer interface {
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type UserAPIServicer interface {
CreateUserNullable(context.Context, *UserNullable) (ImplResponse, error)
CreateUser(context.Context, User) (ImplResponse, error)
CreateUsersWithArrayInput(context.Context, []User) (ImplResponse, error)
CreateUsersWithListInput(context.Context, []User) (ImplResponse, error)

View File

@ -51,6 +51,11 @@ func NewUserAPIController(s UserAPIServicer, opts ...UserAPIOption) *UserAPICont
// Routes returns all the api routes for the UserAPIController
func (c *UserAPIController) Routes() Routes {
return Routes{
"CreateUserNullable": Route{
strings.ToUpper("Put"),
"/v2/user",
c.CreateUserNullable,
},
"CreateUser": Route{
strings.ToUpper("Post"),
"/v2/user",
@ -94,6 +99,33 @@ func (c *UserAPIController) Routes() Routes {
}
}
// CreateUserNullable - Create user
func (c *UserAPIController) CreateUserNullable(w http.ResponseWriter, r *http.Request) {
var userNullableParam UserNullable
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&userNullableParam); err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertUserNullableRequired(userNullableParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
if err := AssertUserNullableConstraints(userNullableParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.CreateUserNullable(r.Context(), &userNullableParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
_ = EncodeJSONResponse(result.Body, &result.Code, result.Headers, w)
}
// CreateUser - Create user
func (c *UserAPIController) CreateUser(w http.ResponseWriter, r *http.Request) {
var userParam User

View File

@ -27,6 +27,17 @@ func NewUserAPIService() *UserAPIService {
return &UserAPIService{}
}
// CreateUserNullable - Create user
func (s *UserAPIService) CreateUserNullable(ctx context.Context, userNullable *UserNullable) (ImplResponse, error) {
// TODO - update CreateUserNullable with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
// TODO: Uncomment the next line to return response Response(0, {}) or use other options such as http.Ok ...
// return Response(0, nil),nil
return Response(http.StatusNotImplemented, nil), errors.New("CreateUserNullable method not implemented")
}
// CreateUser - Create user
func (s *UserAPIService) CreateUser(ctx context.Context, user User) (ImplResponse, error) {
// TODO - update CreateUser with the required logic for this service method.

View File

@ -0,0 +1,76 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
/*
* OpenAPI Petstore
*
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* API version: 1.0.0
*/
package petstoreserver
// UserNullable - A User who is purchasing from the pet store
type UserNullable struct {
Id int64 `json:"id,omitempty"`
Username string `json:"username,omitempty"`
FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"`
Email string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
Phone *string `json:"phone,omitempty"`
// User Status
UserStatus int32 `json:"userStatus,omitempty"`
// An array 1-deep.
DeepSliceModel *[][][]Tag `json:"deepSliceModel"`
// An array 1-deep.
DeepSliceMap [][]AnObject `json:"deepSliceMap,omitempty"`
}
// AssertUserNullableRequired checks if the required fields are not zero-ed
func AssertUserNullableRequired(obj UserNullable) error {
elements := map[string]interface{}{
"deepSliceModel": obj.DeepSliceModel,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
if obj.DeepSliceModel != nil {
if err := AssertRecurseInterfaceRequired(*obj.DeepSliceModel, AssertTagRequired); err != nil {
return err
}
}
if err := AssertRecurseInterfaceRequired(obj.DeepSliceMap, AssertAnObjectRequired); err != nil {
return err
}
return nil
}
// AssertUserNullableConstraints checks if the values respects the defined constraints
func AssertUserNullableConstraints(obj UserNullable) error {
if obj.DeepSliceModel != nil {
if err := AssertRecurseInterfaceRequired(*obj.DeepSliceModel, AssertTagConstraints); err != nil {
return err
}
}
if err := AssertRecurseInterfaceRequired(obj.DeepSliceMap, AssertAnObjectConstraints); err != nil {
return err
}
return nil
}

View File

@ -27,5 +27,6 @@ go/model_special_info.go
go/model_species.go
go/model_tag.go
go/model_user.go
go/model_user_nullable.go
go/routers.go
main.go

View File

@ -605,6 +605,24 @@ paths:
summary: Create user
tags:
- user
put:
description: This can only be done by the logged in user.
operationId: createUserNullable
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserNullable'
description: "Created user object, with a nullable bodyParam"
required: true
responses:
default:
description: successful operation
security:
- api_key: []
summary: Create user
tags:
- user
/user/createWithArray:
post:
description: ""
@ -1240,6 +1258,211 @@ components:
type: object
xml:
name: User
UserNullable:
description: A User who is purchasing from the pet store
example:
firstName: firstName
lastName: lastName
password: password
userStatus: 6
phone: phone
deepSliceModel:
- - - name: name
id: 1
- name: name
id: 1
- - name: name
id: 1
- name: name
id: 1
- - - name: name
id: 1
- name: name
id: 1
- - name: name
id: 1
- name: name
id: 1
id: 0
deepSliceMap:
- - tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- - tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- tag:
name: name
id: 1
Pet:
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
- photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 0
category:
name: name
id: 6
tags:
- name: name
id: 1
- name: name
id: 1
status: available
email: email
username: username
nullable: true
properties:
id:
format: int64
type: integer
username:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
phone:
nullable: true
type: string
userStatus:
description: User Status
format: int32
type: integer
deepSliceModel:
description: An array 1-deep.
items:
description: An array 2-deep.
items:
description: An array 3-deep.
items:
$ref: '#/components/schemas/Tag'
type: array
type: array
nullable: true
type: array
deepSliceMap:
description: An array 1-deep.
items:
description: An array 2-deep.
items:
$ref: '#/components/schemas/an_Object'
type: array
type: array
required:
- deepSliceModel
title: a User
type: object
xml:
name: User
Tag:
description: A tag for a pet
example:

View File

@ -58,6 +58,7 @@ type StoreAPIRouter interface {
// The UserAPIRouter implementation should parse necessary information from the http request,
// pass the data to a UserAPIServicer to perform the required actions, then write the service results to the http response.
type UserAPIRouter interface {
CreateUserNullable(http.ResponseWriter, *http.Request)
CreateUser(http.ResponseWriter, *http.Request)
CreateUsersWithArrayInput(http.ResponseWriter, *http.Request)
CreateUsersWithListInput(http.ResponseWriter, *http.Request)
@ -118,6 +119,7 @@ type StoreAPIServicer interface {
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type UserAPIServicer interface {
CreateUserNullable(context.Context, *UserNullable) (ImplResponse, error)
CreateUser(context.Context, User) (ImplResponse, error)
CreateUsersWithArrayInput(context.Context, []User) (ImplResponse, error)
CreateUsersWithListInput(context.Context, []User) (ImplResponse, error)

View File

@ -51,6 +51,11 @@ func NewUserAPIController(s UserAPIServicer, opts ...UserAPIOption) *UserAPICont
// Routes returns all the api routes for the UserAPIController
func (c *UserAPIController) Routes() Routes {
return Routes{
"CreateUserNullable": Route{
strings.ToUpper("Put"),
"/v2/user",
c.CreateUserNullable,
},
"CreateUser": Route{
strings.ToUpper("Post"),
"/v2/user",
@ -94,6 +99,33 @@ func (c *UserAPIController) Routes() Routes {
}
}
// CreateUserNullable - Create user
func (c *UserAPIController) CreateUserNullable(w http.ResponseWriter, r *http.Request) {
var userNullableParam UserNullable
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&userNullableParam); err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertUserNullableRequired(userNullableParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
if err := AssertUserNullableConstraints(userNullableParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.CreateUserNullable(r.Context(), &userNullableParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
_ = EncodeJSONResponse(result.Body, &result.Code, result.Headers, w)
}
// CreateUser - Create user
func (c *UserAPIController) CreateUser(w http.ResponseWriter, r *http.Request) {
var userParam User

View File

@ -27,6 +27,17 @@ func NewUserAPIService() *UserAPIService {
return &UserAPIService{}
}
// CreateUserNullable - Create user
func (s *UserAPIService) CreateUserNullable(ctx context.Context, userNullable *UserNullable) (ImplResponse, error) {
// TODO - update CreateUserNullable with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
// TODO: Uncomment the next line to return response Response(0, {}) or use other options such as http.Ok ...
// return Response(0, nil),nil
return Response(http.StatusNotImplemented, nil), errors.New("CreateUserNullable method not implemented")
}
// CreateUser - Create user
func (s *UserAPIService) CreateUser(ctx context.Context, user User) (ImplResponse, error) {
// TODO - update CreateUser with the required logic for this service method.

View File

@ -0,0 +1,76 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
/*
* OpenAPI Petstore
*
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* API version: 1.0.0
*/
package petstoreserver
// UserNullable - A User who is purchasing from the pet store
type UserNullable struct {
Id int64 `json:"id,omitempty"`
Username string `json:"username,omitempty"`
FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"`
Email string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
Phone *string `json:"phone,omitempty"`
// User Status
UserStatus int32 `json:"userStatus,omitempty"`
// An array 1-deep.
DeepSliceModel *[][][]Tag `json:"deepSliceModel"`
// An array 1-deep.
DeepSliceMap [][]AnObject `json:"deepSliceMap,omitempty"`
}
// AssertUserNullableRequired checks if the required fields are not zero-ed
func AssertUserNullableRequired(obj UserNullable) error {
elements := map[string]interface{}{
"deepSliceModel": obj.DeepSliceModel,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
if obj.DeepSliceModel != nil {
if err := AssertRecurseInterfaceRequired(*obj.DeepSliceModel, AssertTagRequired); err != nil {
return err
}
}
if err := AssertRecurseInterfaceRequired(obj.DeepSliceMap, AssertAnObjectRequired); err != nil {
return err
}
return nil
}
// AssertUserNullableConstraints checks if the values respects the defined constraints
func AssertUserNullableConstraints(obj UserNullable) error {
if obj.DeepSliceModel != nil {
if err := AssertRecurseInterfaceRequired(*obj.DeepSliceModel, AssertTagConstraints); err != nil {
return err
}
}
if err := AssertRecurseInterfaceRequired(obj.DeepSliceMap, AssertAnObjectConstraints); err != nil {
return err
}
return nil
}