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