From 44f151a55210cb06c057a48815f1135d102c62ca Mon Sep 17 00:00:00 2001 From: Joost Diepenmaat Date: Fri, 24 Jun 2022 10:54:06 +0200 Subject: [PATCH] Report on location of errors, cleanup some lint. --- project.clj | 27 ++++++-- src/nl/jomco/ring_openapi_validator.clj | 65 +++++++++++-------- test/nl/jomco/ring_openapi_validator_test.clj | 6 +- 3 files changed, 65 insertions(+), 33 deletions(-) diff --git a/project.clj b/project.clj index e25c324..52e163a 100644 --- a/project.clj +++ b/project.clj @@ -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"}) diff --git a/src/nl/jomco/ring_openapi_validator.clj b/src/nl/jomco/ring_openapi_validator.clj index e29afa5..332691e 100644 --- a/src/nl/jomco/ring_openapi_validator.clj +++ b/src/nl/jomco/ring_openapi_validator.clj @@ -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)) diff --git a/test/nl/jomco/ring_openapi_validator_test.clj b/test/nl/jomco/ring_openapi_validator_test.clj index 7965c71..3643eff 100644 --- a/test/nl/jomco/ring_openapi_validator_test.clj +++ b/test/nl/jomco/ring_openapi_validator_test.clj @@ -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" -- 2.45.2