OpenAPITools / OpenAPITools/openapi-generator
[BUG][Go] client returns pointer address instead of the error message when the response has optional title/detail field
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
When an error response type has optional title and detail fields, the generated Go client returns a pointer address instead of the actual message content.
Description
The generated Go client incorrectly formats error messages when the responded problem object contains optional title and detail fields.
Instead of displaying the string values of these fields, the client prints their memory addresses.
sample client code
package main
import (
"context"
"fmt"
"github.com/itotake-coconala/openapi-issue-pointeraddr/openapi"
)
func main() {
client := openapi.NewAPIClient(openapi.NewConfiguration())
_, err := client.DefaultAPI.Call(context.Background()).Execute()
if err != nil {
fmt.Println(err)
}
}
output
$ go run ./client/
400 Bad Request %!s(*string=0x40001de0d0) (%!s(*string=0x40001de0e0))
sample server code
package main
import (
"encoding/json"
"net/http"
)
func main() {
http.HandleFunc("/call", callHandler)
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
type Problem struct {
Type string `json:"type"`
Title string `json:"title"`
Detail string `json:"detail"`
Instance string `json:"instance"`
}
func callHandler(w http.ResponseWriter, r *http.Request) {
problem := Problem{
Type: "",
Title: "invalid request",
Detail: "This endpoint always returnes error",
Instance: "/call",
}
w.Header().Set("Content-Type", "application/problem+json")
w.WriteHeader(400)
if err := json.NewEncoder(w).Encode(problem); err != nil {
panic(err)
}
}
openapi-generator version
v7.11.0
OpenAPI declaration file content or url
openapi: 3.1.0
info:
title: error response with optional title & detail
version: 0.0.1
servers:
- url: http://localhost:8080
paths:
/call:
post:
operationId: call
requestBody:
content:
application/json:
schema:
properties: {}
type: object
responses:
"200":
description: OK
"400":
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
description: error response
summary: the api causing error
components:
schemas:
Problem:
properties:
type:
type: string
title:
type: string
detail:
type: string
instance:
type: string
Generation Details
docker run --rm \
-u $(shell id -u):$(shell id -g) \
-v ${PWD}:/local openapitools/openapi-generator-cli:v7.11.0 generate \
-i /local/openapi.yaml \
-g go \
-o /local/openapi \
--git-user-id itotake-coconala --git-repo-id openapi-issue-pointeraddr/openapi \
--additional-properties=withGoMod=false
Steps to reproduce
- generate OpenAPI client
- run server like
go run ./server/ - run client like
go run ./client/
Related issues/PRs
Suggest a fix
In the generated API client, formatErrorMessage function formats error message using title/detail field in the response.
If these fields are optional, their types are *string and formatErrorMessage prints the address of them instead of the value.
Current formatErrorMessage code:
// format error message using title and detail when model implements rfc7807
func formatErrorMessage(status string, v interface{}) string {
str := ""
metaValue := reflect.ValueOf(v).Elem()
if metaValue.Kind() == reflect.Struct {
field := metaValue.FieldByName("Title")
if field != (reflect.Value{}) {
str = fmt.Sprintf("%s", field.Interface())
}
field = metaValue.FieldByName("Detail")
if field != (reflect.Value{}) {
str = fmt.Sprintf("%s (%s)", str, field.Interface())
}
}
return strings.TrimSpace(fmt.Sprintf("%s %s", status, str))
}
It should be like below to print the value of pointers.
// format error message using title and detail when model implements rfc7807
func formatErrorMessage(status string, v interface{}) string {
str := ""
metaValue := reflect.ValueOf(v).Elem()
if metaValue.Kind() == reflect.Struct {
field := metaValue.FieldByName("Title")
if field.Kind() == reflect.Pointer {
field = field.Elem()
}
if field != (reflect.Value{}) {
str = fmt.Sprintf("%s", field.Interface())
}
field = metaValue.FieldByName("Detail")
if field.Kind() == reflect.Pointer {
field = field.Elem()
}
if field != (reflect.Value{}) {
str = fmt.Sprintf("%s (%s)", str, field.Interface())
}
}
return strings.TrimSpace(fmt.Sprintf("%s %s", status, str))
}
The output with modified client:
$ go run ./client
400 Bad Request invalid request (This endpoint always returnes error)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Search the generator repository for the Go formatErrorMessage entry point and inspect how optional Title and Detail fields are formatted. First reproduce the issue with the supplied OpenAPI YAML and Docker generation command, then run the generated client against the sample server. Done means the client reports the field values rather than pointer addresses.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100