A pure-clojure library for validating ring requests & responses against OpenAPI v3 specifications.
Long term goal: Should work on any Clojure implementation.
Status: the core validator code has no dependencies and should work with minimal changes on any Clojure implementation. Clojure JVM and Babashka are currently tested as part of development.
Target | Status | Remarks |
---|---|---|
JVM Clojure | DONE | |
Babashka | DONE | |
ClojureScript | TODO | Patches welcome |
.NET Clojure | N/A | Not planned, patches welcome |
Target: Complete implementation of Ring request/response maps against OpenAPI v3.1.0 (the current version of the OpenAPI specification). We do not intent to implement v2 or earlier OpenAPI specifications.
Status: mostly complete and usable for real world scenarios. See below table.
Validation | Status | Remarks |
---|---|---|
JSON $ref | PARTIAL | Simple fragment identifiers only |
JSON allOf | DONE | Issues of sub-schemas are concatenated |
JSON anyOf | DONE | Reports :sub-issues |
JSON const | DONE | |
JSON contains | DONE | |
JSON contains | DONE | But see unevaluatedItems |
JSON dependentRequired | DONE | |
JSON discriminator | TODO | OpenAPI Extension; never required, but should improve validation performance |
JSON enum | DONE | |
JSON format | PARTIAL | Only validates "uuid" |
JSON items | DONE | |
JSON maxItems | DONE | |
JSON maxLength | DONE | |
JSON maxProperties | DONE | |
JSON maximum | DONE | |
JSON minItems | DONE | |
JSON minLength | DONE | |
JSON minProperties | DONE | |
JSON minimum | DONE | |
JSON multipleOf | DONE | |
JSON not | DONE | |
JSON oneOf | DONE | Reports :sub-issues |
JSON pattern | DONE | Using java.util.regex.Pattern |
JSON properties | DONE | |
JSON required | DONE | |
JSON type | DONE | |
JSON unevaluatedItems | TODO | |
JSON uniqueItems | DONE | Using clojure uniqueness semantics |
JSON xml | TODO | OpenAPI Extension |
OpenAPI | PARTIAL | v3.1.0 mostly implemented |
OpenAPI $ref | PARTIAL | Simple fragment identifiers only |
OpenAPI Callback | N/A | Not relevant |
OpenAPI Components | DONE | Can be referred to using $ref |
OpenAPI Contact | N/A | Not relevant |
OpenAPI Encoding | TODO | Not implemented |
OpenAPI Header | DONE | |
OpenAPI Info | N/A | Not relevant |
OpenAPI Licence | N/A | Not relevant |
OpenAPI Link | N/A | Not relevant |
OpenAPI Media Type | DONE | Any content-type, body must be parsed before validation |
OpenAPI OAuth Flow | TODO | |
OpenAPI OAuth Flows | TODO | |
OpenAPI Operation | DONE | Including headers and parameters |
OpenAPI Parameter | PARTIAL | Except allowEmptyValue , style=form + explode=true , deepObject=true |
OpenAPI Path Item | PARTIAL | Parameters in paths item are not validated |
OpenAPI Paths | DONE | |
OpenAPI Request Body | DONE | |
OpenAPI Response | DONE | |
OpenAPI Responses | DONE | |
OpenAPI Schema | PARTIAL | See JSON entries in this table for status per JSON Schema keyword |
OpenAPI Security Requirement | TODO | |
OpenAPI Security Scheme | TODO | |
OpenAPI Server | TODO | Not sure if relevant to validation |
OpenAPI Server Variable | N/A | Not relevant |
OpenAPI Tag | N/A | Not relevant |
Validating OpenAPI requests/responses:
(require '[nl.jomco.openapi.v3.validator :as validator])
(require '[clojure.data.json :as json])
(require '[clojure.java.io :as io])
(def ooapi-spec
(json/read (io/reader (io/file "ooapiv5.json"))))
(def validate
(-> ooapi-spec
(validator/validator-context nil)
validator/interaction-validator))
(validate {:request {:method :get
:uri "/courses"
:query-params {"pageNumber" "foo"
"sort" "something,-name"}}
:response {:status 200
:headers {"content-type" "application/json; charset=utf8"}
:body {"pagesize" 0
"pageNumber" 1
"hasPreviousPage" false
"hasNextPage" "true"
"items" []}}}
[])
;; =>
[{:canonical-schema-path ["components" "parameters" "pageNumber"],
:instance "foo",
:issue "coercion-error",
:path [:request :query-params "pageNumber"],
:schema {"type" "integer"},
:schema-path ["paths" "/courses" "get" "parameters" 2 "schema"]}
{:instance "something",
:path [:request :query-params "sort" 0],
:schema-path ["paths" "/courses" "get" "parameters" 8 "schema" "items" "enum"],
:canonical-schema-path ["paths" "/courses" "get" "parameters" 8 "schema" "items" "enum"],
:schema-keyword "enum",
:schema {"enum" ["courseId" "name" "-courseId" "-name"]},
:issue "schema-validation-error"}
{:instance {"pagesize" 0,
"pageNumber" 1,
"hasPreviousPage" false,
"hasNextPage" "true",
"items" []},
:path [:response :body],
:schema-path ["paths" "/courses" "get" "responses" "200" "content"
"application/json" "schema" "allOf" 0 "required"],
:canonical-schema-path ["components" "schemas" "Pagination" "required"],
:hints {:missing ["pageSize"]},
:schema-keyword "required",
:schema {"required" ["pageSize" "pageNumber" "hasPreviousPage"
"hasNextPage" "items"]},
:issue "schema-validation-error"}
{:instance "true",
:path [:response :body "hasNextPage"],
:schema-path ["paths" "/courses" "get" "responses" "200" "content"
"application/json" "schema" "allOf" 0 "properties" "hasNextPage" "type"],
:canonical-schema-path ["components" "schemas" "Pagination" "properties" "hasNextPage" "type"],
:schema-keyword "type",
:schema {"type" "boolean"},
:issue "schema-validation-error"}]
Validating JSON Schemas:
(require '[nl.jomco.openapi.v3.schema-validator :as validator])
(def validate
(validator/schema-validator
(validator/validator-context specification)
["path" "to" "schema" "in" "spec"]))
(def issues
(validate instance ["path" "of" "instance"]))
Validations result in nil
when no issues are present, or a
collection of issues.
Issues are maps with a key :issue
with one of the following values:
"schema-validation-error"
- instance (body or parameter part) did
not validate according to the JSON Schema specification."coercion-error"
- can't coerce parameter to the correct type"method-error"
- the request method did not match the specification"uri-error"
- the uri path did not match the specification"content-type-error"
- the request/response content type did not
match the specification."status-error"
- the response status code did not match the
specification.An issue can optionally have one or more of the following keys:
:instance
- the part of the document that failed to validate.:path
- the absolute path to instance:schema-path
the path in the specification that resolved to the
failing validation.:canonical-schema-path
the absolute path to the schema of the
failing validation.:schema
the relevant parts of the schema that did not
validate. Usually a map.:hints
a map with additional information depending on the error.:sub-issues
- for combining schemas (oneOf and anyOf), the
collections of results of the sub schema validations.:schema-keyword
- for JSON Schema keyword validations, the "main"
schema keyword of the failing validation.Paths are vectors of keys (strings, keywords and integers).
Requests and resposes follow ring format:
:uri
is the path of the request:request-params
is a map with string keys:headers
is a map of with string keys:method
is a keyword :get, :put, :post etc:body
if present should be a parsed document (probably JSON) and
have string keys.Interactions are maps with :request
and :response
keys
Test Schema validator against JSON Schema Test-Suite
Copyright © 2022-2023 Joost Diepenmaat, Jomco BV
This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.
Can you improve this documentation?Edit on sourcehut
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close