luposlip / json-schema

Clojure library JSON Schema validation and generation - Draft-07 compatible
Apache License 2.0
68 stars 7 forks source link

Types are always arrays, not compatible with some parsers #14

Open ngsilverman opened 11 months ago

ngsilverman commented 11 months ago

The README states that this:

(json-schema.infer/infer-strict
    {:title "ent-1"})
    {:things [{:quantity 1}]})

Will generate this:

{:$schema "http://json-schema.org/draft-07/schema#"
 :title "ent-1"
 :type :object
 :additionalProperties false
 :properties {"things" {:type :array
                        :items {:type :object
                                :additionalProperties false
                                :properties {"quantity" {:type :integer}}
                                :required ["quantity"]}}}
 :required ["things"]}

However, for me, using version 0.4.1, it generates this:

{:$schema "http://json-schema.org/draft-07/schema#",
 :title "ent-1",
 :type #{:object},
 :additionalProperties false,
 :properties {"things" {:type #{:array},
                        :items {:type #{:object},
                                :additionalProperties false,
                                :properties {"quantity" {:type #{:integer}}},
                                :required #{"quantity"}}}},
 :required #{"things"}}

Notably, the types are sets, which gets correctly converted to JSON lists, and which is technically a valid schema but can cause issues. For example the OpenAI API doesn't recognize that format, it expects a single type rather than an array of types.

If there is only one type I would suggest making it a single value rather than an array.

Thanks for this library! The infer function is awesome!

luposlip commented 11 months ago

Makes sense, I'll look into that. I'm kind of busy these weeks, but I'll definitely prioritize it as soon as I can.

Thanks for your issue! 😃

ngsilverman commented 11 months ago

Thanks for the prompt reply! I'm happy to help if you can give me some pointers.

In the meantime for anyone else running into this here's a quick fix that goes through the inferred JSON schema and updates the type values:

(defn walk-update [m k f]
  (clojure.walk/postwalk (fn [x] (if (and (map? x) (contains? x k))
                                   (update x k f)
                                   x))
                         m))

(defn infer [params & docs]
  (walk-update
    (apply (partial json-schema.infer/infer params) docs)
    :type
    #(if (and (coll? %) (= (count %) 1))
       (first %)
       %)))