metosin / malli

High-performance data-driven data specification library for Clojure/Script.
Eclipse Public License 2.0
1.5k stars 211 forks source link

Missing "Defs" in swagger (malli.json-schema) with recursive schemes #464

Closed evilsneer closed 1 year ago

evilsneer commented 3 years ago

Hi! I try to use malli as coercion&schemas with swagger ui. If i try serialise recursive schemas with registries, i get some "Could not resolve reference" of keys of recursive values. it is according to plan and swagger bad, or its just undone feature?) looks like there is some missing defs in swagger.json image

I use swagger-ui bundled with

[metosin/reitit-swagger-ui "0.5.13"] [metosin/ring-swagger-ui "3.36.0"]

guess it 3.XX.

I'v got example of that malli:

[:schema
 {:registry {:namespace1/logic-pred [:or
                                        [:= #:json-schema{:val "and"} "and"]
                                        [:= #:json-schema{:val "or"} "or"]],
             :namespace1/not-pred [:= #:json-schema{:val "not"} "not"],
             :namespace1/fields-or-expression [:or
                                                [:ref "Expression"]
                                                [:or
                                                 [:tuple
                                                  [:= #:json-schema{:val "="} "="]
                                                  [:= #:json-schema{:example "phone"} "phone"]
                                                  string?]
                                                 [:tuple
                                                  [:= #:json-schema{:val "contains"} "contains"]
                                                  [:= #:json-schema{:example "phone"} "phone"]
                                                  string?]
                                                 [:tuple
                                                  [:= #:json-schema{:val "startswith"} "startswith"]
                                                  [:= #:json-schema{:example "phone"} "phone"]
                                                  string?]
                                                 [:tuple
                                                  [:= #:json-schema{:val "like"} "like"]
                                                  [:= #:json-schema{:example "phone"} "phone"]
                                                  string?]]

                                                ;; ... (more :or's)

                                                                  ],
             "Expression" [:cat
                           :namespace1/logic-pred
                           [:+
                            [:or
                             [:ref :namespace1/fields-or-expression]
                             [:tuple
                              :namespace1/not-pred
                              [:ref :namespace1/fields-or-expression]]]]]}}
 [:map
  [:where {:optional true, :json-schema/val "[and [= a 2]]"} "Expression"]
  [:limit [int? {:default 100}]]
  [:offset [int? {:default 0}]]]]

If i malli.json-schema/transform this (it is used in swagger gen, right?) i get something like:

{:type "object",
 :properties {:where {:$ref "#/definitions/Expression", :val "[and [= a 2]]"},
              :limit {:default 100, :type "integer"},
              :offset {:default 0, :type "integer"}},
 :required [:limit :offset],
 :definitions {:namespace1/logic-pred {:anyOf [{:const "and", :val "and"} {:const "or", :val "or"}]},
               :namespace1/not-pred {:const "not", :val "not"},
               "Expression" {}}}

and it has no valuable #/definitions/Expression as you can see

evilsneer commented 3 years ago

also, the swagger json has no def of the Expression at all, in the same time

{
    "swagger": "2.0",
    "x-id": [
        "mango.routes.services/api"
    ],
    "info": {
        "title": "mango api",
        "description": "https://cljdoc.org/d/metosin/reitit"
    },
    "paths": {
        "/api/point1/phones": {
            "get": {
                "responses": {
                    "default": {
                        "description": ""
                    }
                },
                "produces": [
                    "application/json",
                    "application/transit+msgpack",
                    "application/transit+json",
                    "application/edn"
                ],
                "consumes": [
                    "application/json",
                    "application/transit+msgpack",
                    "application/transit+json",
                    "application/edn"
                ],
                "parameters": [],
                "summary": " ",
                "operationId": "test.phones-malli",
                "tags": [
                    "dataset"
                ]
            },
            "post": {
                "responses": {
                    "default": {
                        "description": ""
                    }
                },
                "produces": [
                    "application/json",
                    "application/transit+msgpack",
                    "application/transit+json",
                    "application/edn"
                ],
                "consumes": [
                    "application/json",
                    "application/transit+msgpack",
                    "application/transit+json",
                    "application/edn"
                ],
                "parameters": [
                    {
                        "in": "body",
                        "name": "body",
                        "description": "",
                        "required": true,
                        "schema": {
                            "type": "object",
                            "properties": {
                                "where": {
                                    "$ref": "#/definitions/Expression",
                                    "val": "[and [= a 2]]"
                                },
                                "limit": {
                                    "default": 100,
                                    "type": "integer",
                                    "format": "int64"
                                },
                                "offset": {
                                    "default": 0,
                                    "type": "integer",
                                    "format": "int64"
                                }
                            },
                            "required": [
                                "limit",
                                "offset"
                            ],
                            "definitions": {
                                "namespace1/logic-pred": {
                                    "const": "and",
                                    "val": "and",
                                    "x-anyOf": [
                                        {
                                            "const": "and",
                                            "val": "and"
                                        },
                                        {
                                            "const": "or",
                                            "val": "or"
                                        }
                                    ]
                                },
                                "namespace1/not-pred": {
                                    "const": "not",
                                    "val": "not"
                                },
                                "Expression": {
                                    "$ref": "#/definitions/Expression"
                                }
                            }
                        }
                    }
                ],
                "summary": "select from table `crm_test.phones` ",
                "operationId": "advanced-crm_test.phones",
                "tags": [
                    "dataset"
                ]
            }
        }
    }
}

I use [metosin/reitit "0.5.13"], but managed to [metosin/malli "0.5.1"] (it not helps:( )

cap10morgan commented 1 year ago

I did some testing around this as a part of #863 and was able to determine that this bug occurs when a schema is only ever :ref'd, not used directly.

In this case it does appear that the "Expression" schema is used directly in the [:map [:where ...]] schema, but that might be hitting #868 (which #863 also fixes).

Anyway, I'm about to push a commented-out failing test to #863 that demonstrates this bug.

cap10morgan commented 1 year ago

That test is now pushed in d774bd882a9beab47e673cf8613b92ec3c5dc034.