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

Set response and request schemas without declared structure? #96

Closed aosderzhikov closed 3 months ago

aosderzhikov commented 4 months ago

Hi, very nice lib!

My app knows about response format only during runtime(it takes it from config file). So I cant declare response format with struct. Here is any way how I can set response schema with json, yaml, map or something else?

getOp, _ := reflector.NewOperationContext(http.MethodGet, "/user/{id}")
getOp.AddReqStructure(new(struct {
    ID string `path:"id"`
}))

getOp.AddRespStructure()  // <- put json, yaml, map or something else here
vearutop commented 4 months ago

Please check if virtual structure works for your case.

aosderzhikov commented 3 months ago

Thanks, I found this useful! There is a way to add response structure with raw yaml or json?

Like:

getOp.AddRespStructure(`
response:
  type: object
  properties:
    field1:
      type: string
    field2:
      type: integer
.....`) 
vearutop commented 3 months ago

Hi, you can use jsonschema.RawExposer to provide raw schema, please check an example.

type rawExposer func() ([]byte, error)

func (r rawExposer) JSONSchemaBytes() ([]byte, error) {
    return r()
}

func TestReflector_AddOperation_rawSchema(t *testing.T) {
    r := openapi31.NewReflector()
    oc, err := r.NewOperationContext(http.MethodPost, "/foo")
    require.NoError(t, err)

    oc.AddRespStructure(rawExposer(func() ([]byte, error) {
        return []byte(`{"type":"object","properties":{"foo":{"type":"integer"}}}`), nil
    }), openapi.WithHTTPStatus(http.StatusAccepted))

    require.NoError(t, r.AddOperation(oc))

    assertjson.EqMarshal(t, `{
      "openapi":"3.1.0","info":{"title":"","version":""},
      "paths":{
        "/foo":{
          "post":{
            "responses":{
              "202":{
                "description":"Accepted",
                "content":{
                  "application/json":{
                    "schema":{"$ref":"#/components/schemas/Openapi31TestRawExposer"}
                  }
                }
              }
            }
          }
        }
      },
      "components":{
        "schemas":{
          "Openapi31TestRawExposer":{"properties":{"foo":{"type":"integer"}},"type":"object"}
        }
      }
    }`, r.SpecSchema())
}

(Beware of definition name collisions when using same Go type to expose different schemas, perhaps this can be improved on jsonschema-go side).

aosderzhikov commented 3 months ago

But it only works for JSON? Any way to do the same with YAML?

vearutop commented 3 months ago

hmhm, I considered YAML as an unnecessary "convenience" format that does not need first-class support, being just another form of JSON, so nothing like YAMLSchemaBytes() exists

but I think it is easy to make a helper function that would take YAML, convert it to JSON and expose as JSONSchemaBytes()

aosderzhikov commented 3 months ago

Okey, thank you very much for answers, you helped me a lot!

Maybe it's a good point to add new examples in the documentation :)