diff --git a/README.md b/README.md index 3fcc257..93dc2a5 100644 --- a/README.md +++ b/README.md @@ -27,3 +27,5 @@ The following links proved more than useful when working on this assignment: * * +* +* diff --git a/project.clj b/project.clj index e713531..0f4e0c6 100644 --- a/project.clj +++ b/project.clj @@ -7,6 +7,7 @@ [ring/ring-core "1.15.3"] [ring/ring-jetty-adapter "1.15.3"] [metosin/reitit "0.10.0"] + [metosin/reitit-malli "0.10.0"] [metosin/muuntaja "0.6.11"]] :main ^:skip-aot yohoho.core :target-path "target/%s" diff --git a/src/yohoho/core.clj b/src/yohoho/core.clj index c8741e6..c225d98 100644 --- a/src/yohoho/core.clj +++ b/src/yohoho/core.clj @@ -2,10 +2,26 @@ (:require [reitit.ring :as ring] [ring.adapter.jetty :as http-server] [reitit.ring.middleware.muuntaja :as muuntaja] - [muuntaja.core :as m]) + [muuntaja.core :as m] + [reitit.coercion.malli :as malli] + [reitit.ring.coercion :as coercion]) (:gen-class)) +;; Data schema ---------------------------------------------------- +;; Malli schemas for validation + +;; Validating an email address is hard. +;; Regexp shamelessly taken from https://emailregex.com/ +(def email-regexp #"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])") + +(def Email [:re email-regexp]) + +(def Item + [:map + [:name :string] + [:email Email]]) + ;; Handlers ------------------------------------------------------- (defn ahoy-handler @@ -52,11 +68,19 @@ (ring/router [["/ahoy" {:get ahoy-handler}] ["/items" {:get get-items-handler - :post post-items-handler}]] - ;; Use muuntaja middleware to automatically decode JSON - {:data {:muuntaja m/instance + :post {:handler post-items-handler + :parameters {:body Item}}}]] + ;; Middlewares: + ;; - wrap-content-type-json: ensure POST routes are sent JSON payload + ;; - muuntaja middleware to automatically decode JSON + ;; - malli + coercion: handle data validation + {:data {:coercion malli/coercion + :muuntaja m/instance :middleware [wrap-content-type-json - muuntaja/format-middleware]}}) + muuntaja/format-middleware + coercion/coerce-exceptions-middleware + coercion/coerce-request-middleware + coercion/coerce-response-middleware]}}) ;; Default route: anything not explicitely handled should give a 404 (ring/create-default-handler {:not-found (constantly {:status 404