OpenAPITools / OpenAPITools/openapi-generator

[BUG][Go] client returns pointer address instead of the error message when the response has optional title/detail field

Open
#20,553 2 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
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
  1. generate OpenAPI client
  2. run server like go run ./server/
  3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.