oapi-codegen icon indicating copy to clipboard operation
oapi-codegen copied to clipboard

Array in content issue

Open ShouheiNishi opened this issue 2 years ago • 2 comments

If the schema is existed in content in operation object and describes array of object with additionalProperties, code generation is failed.

Test data is in https://github.com/ShouheiNishi/oapi-codegen/commit/81494c12c605e380ea880d231767a6fe39c4ba1a.

$ git status
HEAD detached at 81494c1
nothing to commit, working tree clean
$ cd internal/test/
$ go generate -v ./issues/content-array/...
issues/content-array/doc.go
error generating code: error formatting Go code // Package array provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
package array

import (
        "bytes"
        "compress/gzip"
        "context"
        "encoding/base64"
        "encoding/json"
        "encoding/xml"
        "errors"
        "fmt"
        "gopkg.in/yaml.v2"
        "io"
        "os"
        "net/http"
        "net/url"
        "path"
        "strings"
        "time"

        "github.com/oapi-codegen/runtime"
        strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
        strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
        strictiris "github.com/oapi-codegen/runtime/strictmiddleware/iris"
        strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
        openapi_types "github.com/oapi-codegen/runtime/types"
        "github.com/getkin/kin-openapi/openapi3"
        "github.com/go-chi/chi/v5"
        "github.com/labstack/echo/v4"
        "github.com/gin-gonic/gin"
        "github.com/gofiber/fiber/v2"
        "github.com/kataras/iris/v12"
        "github.com/kataras/iris/v12/core/router"
        "github.com/gorilla/mux"
)












// RequestEditorFn  is the function signature for the RequestEditor callback function
type RequestEditorFn func(ctx context.Context, req *http.Request) error

// Doer performs HTTP requests.
//
// The standard http.Client implements this interface.
type HttpRequestDoer interface {
        Do(req *http.Request) (*http.Response, error)
}

// Client which conforms to the OpenAPI3 specification for this service.
type Client struct {
        // The endpoint of the server conforming to this interface, with scheme,
        // https://api.deepmap.com for example. This can contain a path relative
        // to the server, such as https://api.deepmap.com/dev-test, and all the
        // paths in the swagger spec will be appended to the server.
        Server string

        // Doer for performing requests, typically a *http.Client with any
        // customized settings, such as certificate chains.
        Client HttpRequestDoer

        // A list of callbacks for modifying requests which are generated before sending over
        // the network.
        RequestEditors []RequestEditorFn
}

// ClientOption allows setting custom parameters during construction
type ClientOption func(*Client) error

// Creates a new Client, with reasonable defaults
func NewClient(server string, opts ...ClientOption) (*Client, error) {
    // create a client with sane default values
    client := Client{
        Server: server,
    }
    // mutate client and add all optional params
    for _, o := range opts {
        if err := o(&client); err != nil {
            return nil, err
        }
    }
    // ensure the server URL always has a trailing slash
    if !strings.HasSuffix(client.Server, "/") {
        client.Server += "/"
    }
    // create httpClient, if not already present
    if client.Client == nil {
        client.Client = &http.Client{}
    }
    return &client, nil
}

// WithHTTPClient allows overriding the default Doer, which is
// automatically created using http.Client. This is useful for tests.
func WithHTTPClient(doer HttpRequestDoer) ClientOption {
        return func(c *Client) error {
                c.Client = doer
                return nil
        }
}

// WithRequestEditorFn allows setting up a callback function, which will be
// called right before sending the request. This can be used to mutate the request.
func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
        return func(c *Client) error {
                c.RequestEditors = append(c.RequestEditors, fn)
                return nil
        }
}

// The interface specification for the client above.
type ClientInterface interface {
// Test request
    Test(ctx context.Context, reqEditors... RequestEditorFn) (*http.Response, error)


}



func (c *Client) Test(ctx context.Context, reqEditors... RequestEditorFn) (*http.Response, error) {
    req, err := NewTestRequest(c.Server)
    if err != nil {
        return nil, err
    }
    req = req.WithContext(ctx)
    if err := c.applyEditors(ctx, req, reqEditors); err != nil {
        return nil, err
    }
    return c.Client.Do(req)
}








// NewTestRequest generates requests for Test
func NewTestRequest(server string) (*http.Request, error) {
    var err error

    serverURL, err := url.Parse(server)
    if err != nil {
        return nil, err
    }

    operationPath := fmt.Sprintf("/test")
    if operationPath[0] == '/' {
        operationPath = "." + operationPath
    }

    queryURL, err := serverURL.Parse(operationPath)
    if err != nil {
        return nil, err
    }


    req, err := http.NewRequest("GET", queryURL.String(), nil)
    if err != nil {
        return nil, err
    }





    return req, nil
}



func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
    for _, r := range c.RequestEditors {
        if err := r(ctx, req); err != nil {
            return err
        }
    }
    for _, r := range additionalEditors {
        if err := r(ctx, req); err != nil {
            return err
        }
    }
    return nil
}
// ClientWithResponses builds on ClientInterface to offer response payloads
type ClientWithResponses struct {
    ClientInterface
}

// NewClientWithResponses creates a new ClientWithResponses, which wraps
// Client with return type handling
func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
    client, err := NewClient(server, opts...)
    if err != nil {
        return nil, err
    }
    return &ClientWithResponses{client}, nil
}

// WithBaseURL overrides the baseURL.
func WithBaseURL(baseURL string) ClientOption {
        return func(c *Client) error {
                newBaseURL, err := url.Parse(baseURL)
                if err != nil {
                        return err
                }
                c.Server = newBaseURL.String()
                return nil
        }
}

// ClientWithResponsesInterface is the interface specification for the client with responses above.
type ClientWithResponsesInterface interface {
// TestWithResponse request
    TestWithResponse(ctx context.Context, reqEditors... RequestEditorFn) (*TestResponse, error)


}


type TestResponse struct {
    Body         []byte
        HTTPResponse *http.Response
    JSON200 *[]200_Item
}

// Status returns HTTPResponse.Status
func (r TestResponse) Status() string {
    if r.HTTPResponse != nil {
        return r.HTTPResponse.Status
    }
    return http.StatusText(0)
}

// StatusCode returns HTTPResponse.StatusCode
func (r TestResponse) StatusCode() int {
    if r.HTTPResponse != nil {
        return r.HTTPResponse.StatusCode
    }
    return 0
}






// TestWithResponse request returning *TestResponse
func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors... RequestEditorFn) (*TestResponse, error){
    rsp, err := c.Test(ctx, reqEditors...)
    if err != nil {
        return nil, err
    }
    return ParseTestResponse(rsp)
}








// ParseTestResponse parses an HTTP response from a TestWithResponse call
func ParseTestResponse(rsp *http.Response) (*TestResponse, error) {
    bodyBytes, err := io.ReadAll(rsp.Body)
    defer func() { _ = rsp.Body.Close() }()
    if err != nil {
        return nil, err
    }

    response := &TestResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}

    switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
var dest []200_Item
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
 return nil, err
}
response.JSON200 = &dest

}


    return response, nil
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

// (GET /test)
Test(w http.ResponseWriter, r *http.Request)

}

// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.

type Unimplemented struct {}

 // (GET /test)
 func (_ Unimplemented) Test(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNotImplemented)
 }

// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
    Handler ServerInterface
    HandlerMiddlewares []MiddlewareFunc
    ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
}

type MiddlewareFunc func(http.Handler) http.Handler



// Test operation middleware
func (siw *ServerInterfaceWrapper) Test(w http.ResponseWriter, r *http.Request) {
  ctx := r.Context()








  handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    siw.Handler.Test(w, r)
  }))


  for _, middleware := range siw.HandlerMiddlewares {
    handler = middleware(handler)
  }


  handler.ServeHTTP(w, r.WithContext(ctx))
}


type UnescapedCookieParamError struct {
    ParamName string
        Err error
}

func (e *UnescapedCookieParamError) Error() string {
    return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
}

func (e *UnescapedCookieParamError) Unwrap() error {
    return e.Err
}

type UnmarshalingParamError struct {
    ParamName string
    Err error
}

func (e *UnmarshalingParamError) Error() string {
    return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
}

func (e *UnmarshalingParamError) Unwrap() error {
    return e.Err
}

type RequiredParamError struct {
    ParamName string
}

func (e *RequiredParamError) Error() string {
    return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
}

type RequiredHeaderError struct {
    ParamName string
    Err error
}

func (e *RequiredHeaderError) Error() string {
    return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
}

func (e *RequiredHeaderError) Unwrap() error {
    return e.Err
}

type InvalidParamFormatError struct {
    ParamName string
          Err error
}

func (e *InvalidParamFormatError) Error() string {
    return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
}

func (e *InvalidParamFormatError) Unwrap() error {
    return e.Err
}

type TooManyValuesForParamError struct {
    ParamName string
    Count int
}

func (e *TooManyValuesForParamError) Error() string {
    return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
}

// Handler creates http.Handler with routing matching OpenAPI spec.
func Handler(si ServerInterface) http.Handler {
  return HandlerWithOptions(si, ChiServerOptions{})
}

type ChiServerOptions struct {
    BaseURL string
    BaseRouter chi.Router
    Middlewares []MiddlewareFunc
    ErrorHandlerFunc   func(w http.ResponseWriter, r *http.Request, err error)
}

// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
    return HandlerWithOptions(si, ChiServerOptions {
        BaseRouter: r,
    })
}

func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
    return HandlerWithOptions(si, ChiServerOptions {
        BaseURL: baseURL,
        BaseRouter: r,
    })
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
r := options.BaseRouter

if r == nil {
r = chi.NewRouter()
}
if options.ErrorHandlerFunc == nil {
    options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
        http.Error(w, err.Error(), http.StatusBadRequest)
    }
}
wrapper := ServerInterfaceWrapper{
Handler: si,
HandlerMiddlewares: options.Middlewares,
ErrorHandlerFunc: options.ErrorHandlerFunc,
}

r.Group(func(r chi.Router) {
r.Get(options.BaseURL+"/test", wrapper.Test)
})

return r
}

    type TestRequestObject struct {
        }

    type TestResponseObject interface {
        VisitTestResponse(w http.ResponseWriter) error
    }






            type Test200JSONResponse  []Test200JSONResponse_Item


            func (response Test200JSONResponse) VisitTestResponse(w http.ResponseWriter) error {
                w.Header().Set("Content-Type", "application/json")
                w.WriteHeader(200)


                    return json.NewEncoder(w).Encode(response)
                }






// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {

// (GET /test)
Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
}

type StrictHandlerFunc = strictnethttp.StrictHttpHandlerFunc
type StrictMiddlewareFunc = strictnethttp.StrictHttpMiddlewareFunc

type StrictHTTPServerOptions struct {
    RequestErrorHandlerFunc  func(w http.ResponseWriter, r *http.Request, err error)
    ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
}

func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
    return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions {
        RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
            http.Error(w, err.Error(), http.StatusBadRequest)
        },
        ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        },
    }}
}

func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
    return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}

type strictHandler struct {
    ssi StrictServerInterface
    middlewares []StrictMiddlewareFunc
    options StrictHTTPServerOptions
}



    // Test operation middleware
    func (sh *strictHandler) Test(w http.ResponseWriter, r *http.Request) {
        var request TestRequestObject



        handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
            return sh.ssi.Test(ctx, request.(TestRequestObject))
        }
        for _, middleware := range sh.middlewares {
            handler = middleware(handler, "Test")
        }

        response, err := handler(r.Context(), w, r, request)

        if err != nil {
            sh.options.ResponseErrorHandlerFunc(w, r, err)
        } else if validResponse, ok := response.(TestResponseObject); ok {
            if err := validResponse.VisitTestResponse(w); err != nil {
                sh.options.ResponseErrorHandlerFunc(w, r, err)
            }
        } else if response != nil {
            sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
        }
    }

: array.go:237:19: '_' must separate successive digits (and 1 more errors)
exit status 1
issues/content-array/doc.go:3: running "go": exit status 1
$

ShouheiNishi avatar Sep 20 '23 04:09 ShouheiNishi

This was closed as part of #1121 :clap:

jamietanna avatar Sep 20 '24 15:09 jamietanna

Actually sorry, it doesn't look like it was quite - we're seeing a slightly different issue now:

./content-array.gen.go:410:28: undefined: Test200JSONResponse_Item

jamietanna avatar Sep 20 '24 20:09 jamietanna