luposlip / json-schema

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

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

Open ngsilverman opened 1 year ago

ngsilverman commented 1 year 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 1 year 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 1 year 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 %)
       %)))