M project.clj => project.clj +23 -4
@@ 3,11 3,30 @@
:url "https://git.sr.ht/~jomco/ring-openapi-validator"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
- :dependencies [[org.clojure/clojure "1.10.0" :scope "provided"]
- [cheshire "5.10.0" :exclusions [com.fasterxml.jackson.core/jackson-core]]
- [com.atlassian.oai/swagger-request-validator-core "2.28.1"]
+ :dependencies [[com.atlassian.oai/swagger-request-validator-core "2.28.1"]
[io.swagger.parser.v3/swagger-parser "2.1.1"]]
- :profiles {:dev {:resource-paths ["dev-resources"]}}
+ :profiles {:dev {:resource-paths ["dev-resources"]
+ :dependencies [[clj-kondo "2022.06.22"]]
+ :plugins [[lein-kibit "0.1.8"]
+ [lein-ancient "1.0.0-RC3"]]
+ :aliases {"lint" ["do"
+ ["run" "-m" "clj-kondo.main" "--lint" "src"]
+ "kibit"]}}
+ :provided {:dependencies [[org.clojure/clojure "1.11.1"]]}}
+
+ ;; setup `vX.Y.Z` tags, deploy to clojars
+ :release-tasks [["vcs" "assert-committed"]
+ ["test"]
+ ["lint"]
+ ["ancient"]
+ ["change" "version" "leiningen.release/bump-version" "release"]
+ ["vcs" "commit"]
+ ["vcs" "tag" "v"]
+ ["deploy" "clojars"]
+ ["change" "version" "leiningen.release/bump-version"]
+ ["vcs" "commit"]
+ ["vcs" "push"]]
+
;; link to git repo, also ensures that cljdoc.org finds additional markdown files
:scm {:name "git"
:url "https://git.sr.ht/~jomco/ring-openapi-validator"})
M src/nl/jomco/ring_openapi_validator.clj => src/nl/jomco/ring_openapi_validator.clj +37 -28
@@ 1,17 1,12 @@
(ns nl.jomco.ring-openapi-validator
- (:require [clojure.string :as string]
- [cheshire.core :as json])
+ (:require [clojure.string :as string])
(:import com.atlassian.oai.validator.OpenApiInteractionValidator
com.atlassian.oai.validator.model.Request
com.atlassian.oai.validator.model.Request$Method
com.atlassian.oai.validator.model.Response
- com.atlassian.oai.validator.model.StringBody
- com.atlassian.oai.validator.report.ValidationReport
com.atlassian.oai.validator.report.ValidationReport$Level
com.atlassian.oai.validator.report.ValidationReport$MessageContext$Location
- java.util.Optional
- java.nio.charset.Charset
- java.nio.charset.StandardCharsets))
+ java.util.Optional))
(def ^:private ring->Method
{:get Request$Method/GET
@@ 44,32 39,32 @@
[{:keys [uri request-method body query-params headers]}]
(let [headers (normalize-headers headers)]
(reify Request
- (getPath [this]
+ (getPath [_]
uri)
- (getMethod [this]
+ (getMethod [_]
(ring->Method request-method))
- (getBody [this]
+ (getBody [_]
(Optional/ofNullable body))
- (getQueryParameters [this]
+ (getQueryParameters [_]
(->> query-params
keys
(map name)))
- (getQueryParameterValues [this n]
+ (getQueryParameterValues [_ n]
(->coll (get query-params n)))
- (getHeaders [this]
+ (getHeaders [_]
headers)
- (getHeaderValues [this n]
+ (getHeaderValues [_ n]
(->coll (get headers (string/lower-case n)))))))
(defn- ring->Response
- [{:keys [status body headers] :as response}]
+ [{:keys [status body headers]}]
(let [headers (normalize-headers headers)]
(reify Response
- (getStatus [this]
+ (getStatus [_]
status)
- (getBody [this]
+ (getBody [_]
(Optional/ofNullable body))
- (getHeaderValues [this n]
+ (getHeaderValues [_ n]
(->coll (get headers (string/lower-case n)))))))
(def ^:private Level->key
@@ 78,18 73,32 @@
ValidationReport$Level/INFO :info
ValidationReport$Level/WARN :warn})
-(defn- Message->map
- [msg]
- {:key (.getKey msg)
- :message (.getMessage msg)
- :level (Level->key (.getLevel msg))
- :additional-info (.getAdditionalInfo msg)
- :nested-messages (map Message->map (.getNestedMessages msg))})
-
(def ^:private Location->key
{ValidationReport$MessageContext$Location/REQUEST :request
ValidationReport$MessageContext$Location/RESPONSE :response})
+(defn- opt->val
+ "Convert java.util.Optional to a nillable value."
+ [x]
+ (.orElse x nil))
+
+(defn- Message->map
+ [msg]
+ (let [location (some-> msg
+ .getContext
+ opt->val
+ .getLocation
+ opt->val
+ Location->key)]
+ (cond->
+ {:key (.getKey msg)
+ :message (.getMessage msg)
+ :level (Level->key (.getLevel msg))
+ :additional-info (.getAdditionalInfo msg)
+ :nested-messages (map Message->map (.getNestedMessages msg))}
+ location
+ (assoc :location location))))
+
(defn- report->coll
[report]
(let [coll (mapv Message->map (.getMessages report))]
@@ 102,14 111,14 @@
`spec` is a url or path to resource describing a Swagger or OpenApi
specification.
- `opts` is an optional map of options:
+ Second argument is an optional map of options:
- `:base-path` overrides the base path in the spec.
- `:inline? true` indicate that `spec` is the specification body
as a string, instead of a url or path
If you need to customize the validator you can create a builder using
`com.atlassian.oai.validator.OpenApiInteractionValidator/createFor`"
- ([spec {:keys [base-path inline?] :as opts}]
+ ([spec {:keys [base-path inline?]}]
(cond-> (if inline?
(OpenApiInteractionValidator/createForInlineApiSpecification spec)
(OpenApiInteractionValidator/createFor spec))
M test/nl/jomco/ring_openapi_validator_test.clj => test/nl/jomco/ring_openapi_validator_test.clj +5 -1
@@ 49,7 49,11 @@
ooapi-invalid-response)]
(is (= "validation.response.body.schema.required"
(get-in report [0 :key]))
- "Report on missing property")))
+ "Report on missing property")
+
+ (is (= :response
+ (get-in report [0 :location]))
+ "Report on location of error")))
(testing "request"
(is (nil? (validator/validate-request validator ooapi-request)))
(is (= "validation.request.operation.notAllowed"