swaggest / openapi-go

OpenAPI structures for Go
https://pkg.go.dev/github.com/swaggest/openapi-go/openapi3
MIT License
223 stars 18 forks source link

Method designed without params/placeholders throws "missing path parameter placeholder in url"? #91

Closed metaleap closed 6 months ago

metaleap commented 7 months ago

Using v0.2.42 here, go getted just today.

My error-raising request-struct looks like this: struct { Id yodb.I64 } which actually equates structurally/mem-wise to struct { Id int64 }.

(It's an unnamed type so I guess reflect.Type.Name will be empty, but not sure. But that's not the cause — just double-checked by temporarily naming it.)

My Add-ing code: op.AddReqStructure(reflect.New(ty_args).Interface(), openapi.WithContentType("application/json"))

This errors out with:

validate path params post /_/postDelete: missing path parameter placeholder in url: Id", link:

Nothing after "link:". What's the idea? The underlying method expects a {"Id": number} payload and does not offer any url placeholdering/parametering. How and why is the assumption there?

(Don't tell me the _ in /_/postDelete is interpreted as placeholder? That's a url-prefix for all our api-method paths, so that any non-_/* path after / is free as a user-claimable vanity-name/base-path, even sth. like apis :grin: )

From what I can tell:

metaleap commented 7 months ago

Full repro:


import (
    "reflect"
    "testing"

    "github.com/swaggest/jsonschema-go"
    "github.com/swaggest/openapi-go"
    "github.com/swaggest/openapi-go/openapi31"
)

type yodb_I64 int64
type None struct{}

func Test_Repro2(t *testing.T) {
    oarefl := openapi31.NewReflector()
    oarefl.Spec.Info.WithTitle("kaffe.local")
    oarefl.JSONSchemaReflector().DefaultOptions = append(oarefl.JSONSchemaReflector().DefaultOptions, jsonschema.ProcessWithoutTags)

    {
        var dummy_in struct{ Id yodb_I64 }
        var dummy_out None
        ty_args, ty_ret := reflect.TypeOf(dummy_in), reflect.TypeOf(dummy_out)
        op, err := oarefl.NewOperationContext("POST", "/_/postDelete")
        if err != nil {
            t.Fatal(err)
        }
        op.AddReqStructure(reflect.New(ty_args).Elem().Interface(), openapi.WithContentType("application/json"))
        op.AddRespStructure(reflect.New(ty_ret).Elem().Interface(), openapi.WithHTTPStatus(200))
        if err = oarefl.AddOperation(op); err != nil {
            t.Fatal(err)
        }
    }

    src_json, err := oarefl.Spec.MarshalJSON()
    if err != nil {
        t.Fatal(err)
    }
    t.Log(string(src_json))
}
vearutop commented 6 months ago

This behavior is due to a default option jsonschema.ProcessWithoutTags that applies to all reflections, including path parameters. Please try v0.2.43 which adds initial tag-less JSON support by reverting jsonschema.ProcessWithoutTags for non-JSON cases.

metaleap commented 6 months ago

Sound good but already way past my openapi.json TODO (or the need for any dependency for that functionality) — feel free to Close the Issue at your leisure =)