diff --git a/README.md b/README.md index f6ed27c5..3aabe2a4 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ A fast data-driven router for Clojure(Script). * First-class [route data](https://metosin.github.io/reitit/basics/route_data.html) * Bi-directional routing * [Pluggable coercion](https://metosin.github.io/reitit/coercion/coercion.html) ([schema](https://github.com/plumatic/schema) & [clojure.spec](https://clojure.org/about/spec)) +* Helpers for [ring](https://metosin.github.io/reitit/ring/ring.html) & [the browser](https://metosin.github.io/reitit/frontend/basics.html) * Extendable * Modular * [Fast](https://metosin.github.io/reitit/performance.html) @@ -15,22 +16,26 @@ Posts: * [Reitit, Data-Driven Routing with Clojure(Script)](https://www.metosin.fi/blog/reitit/) * [Data-Driven Ring with Reitit](https://www.metosin.fi/blog/reitit-ring/) -See the [full documentation](https://metosin.github.io/reitit/) for details. +See the [full documentation](https://metosin.github.io/reitit/) for details. + +There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians Slack](http://clojurians.net/) for discussion & help. ## Modules +* `reitit` - all bundled * `reitit-core` - the routing core * `reitit-ring` - a [ring router](https://metosin.github.io/reitit/ring/ring.html) -* `reitit-middleware` - [common data-driven middleware](https://metosin.github.io/reitit/ring/default_middleware.html) for `reitit-ring` +* `reitit-middleware` - [common middleware](https://metosin.github.io/reitit/ring/default_middleware.html) for `reitit-ring` * `reitit-spec` [clojure.spec](https://clojure.org/about/spec) coercion * `reitit-schema` [Schema](https://github.com/plumatic/schema) coercion * `reitit-swagger` [Swagger2](https://swagger.io/) apidocs * `reitit-swagger-ui` Integrated [Swagger UI](https://github.com/swagger-api/swagger-ui) +* [`reitit-frontend`](frontend/basics.md) Tools for frontend routing. Bubblin' under: -* `reitit-http` with enchanced Pedestal-style Interceptors (WIP) -* `reitit-frontend` with Keechma-style Controllers (WIP) +* `reitit-http` http-routing with Pedestal-style Interceptors (WIP) +* `reitit-sieppari` support for [Sieppari](https://github.com/metosin/sieppari) Interceptors (WIP) ## Latest version @@ -44,11 +49,25 @@ Optionally, the parts can be required separately: ```clj [metosin/reitit-core "0.2.0-SNAPSHOT"] -[metosin/reitit-ring "0.2.0-SNAPSHOT"] + +;; coercion [metosin/reitit-spec "0.2.0-SNAPSHOT"] [metosin/reitit-schema "0.2.0-SNAPSHOT"] + +;; ring helpers +[metosin/reitit-ring "0.2.0-SNAPSHOT"] +[metosin/reitit-middleware "0.2.0-SNAPSHOT"] + +;; swagger-support for ring & http [metosin/reitit-swagger "0.2.0-SNAPSHOT"] [metosin/reitit-swagger-ui "0.2.0-SNAPSHOT"] + +;; frontend helpers (alpha) +[metosin/reitit-frontend "0.2.0-SNAPSHOT"] + +;; http with interceptors (alpha) +[metosin/reitit-http "0.2.0-SNAPSHOT"] +[metosin/reitit-sieppari "0.2.0-SNAPSHOT"] ``` ## Quick start diff --git a/dev-resources/json/json100b.json b/dev-resources/json/json100b.json new file mode 100644 index 00000000..24b9767e --- /dev/null +++ b/dev-resources/json/json100b.json @@ -0,0 +1 @@ +{"number":100,"boolean":true,"list":[{"kikka":"kukka"}],"nested":{"map":"this is value","secret":1}} \ No newline at end of file diff --git a/dev-resources/json/json100k.json b/dev-resources/json/json100k.json new file mode 100644 index 00000000..bb68bfe5 --- /dev/null +++ b/dev-resources/json/json100k.json @@ -0,0 +1 @@ +{"results":[{"gender":"female","name":{"title":"mrs","first":"andrea","last":"jensen"},"location":{"street":"1968 assensvej","city":"samsø","state":"nordjylland","postcode":61653},"email":"andrea.jensen@example.com","login":{"username":"heavyleopard105","password":"buffy","salt":"UKfGRyKe","md5":"ff252d31f9d6a7e19f2b28521aa1f367","sha1":"9521848f990d38a6cb707295b8b6de2d6e42a2a9","sha256":"9fc1583d6c09117db30c14811f2f287b331a889c84f197e34b7dd0afb2e7fff1"},"dob":"1968-07-08 20:01:11","registered":"2007-05-16 19:14:08","phone":"27249355","cell":"29065533","id":{"name":"CPR","value":"264203-4324"},"picture":{"large":"https://randomuser.me/api/portraits/women/0.jpg","medium":"https://randomuser.me/api/portraits/med/women/0.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/0.jpg"},"nat":"DK"},{"gender":"male","name":{"title":"mr","first":"guy","last":"gardner"},"location":{"street":"5973 patrick street","city":"shannon","state":"meath","postcode":19959},"email":"guy.gardner@example.com","login":{"username":"ticklishduck240","password":"time","salt":"rBKuQuts","md5":"d174e018f937886bde2962c7b8bd684f","sha1":"0bc1ad9a58dcb77885730b96a4e1e48f043b3160","sha256":"792a4aadb17fb948ea7dfa79d27070289829cca5c37eff3f0b9cab812ae8ef31"},"dob":"1978-11-16 11:20:56","registered":"2012-07-05 08:42:20","phone":"071-072-4663","cell":"081-592-5502","id":{"name":"PPS","value":"2493116T"},"picture":{"large":"https://randomuser.me/api/portraits/men/2.jpg","medium":"https://randomuser.me/api/portraits/med/men/2.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/2.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"mrs","first":"latife","last":"yeşilkaya"},"location":{"street":"4022 mevlana cd","city":"bartın","state":"edirne","postcode":36144},"email":"latife.yeşilkaya@example.com","login":{"username":"tinygorilla450","password":"films","salt":"SorJwZky","md5":"e9fdd8c5b3409b24fee5720a5f39d03d","sha1":"0b03ff01499cb33adefc77cb8da0ba29e3f9d31e","sha256":"db29a83f3a02e4666f8130a3e086126b8c2c0c8ddc83cc3430dd5a8213d78931"},"dob":"1949-07-27 07:30:55","registered":"2016-06-08 23:07:14","phone":"(568)-215-7054","cell":"(557)-462-9511","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/14.jpg","medium":"https://randomuser.me/api/portraits/med/women/14.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/14.jpg"},"nat":"TR"},{"gender":"female","name":{"title":"ms","first":"nicole","last":"patterson"},"location":{"street":"6497 the grove","city":"derby","state":"powys","postcode":"QL11 7YD"},"email":"nicole.patterson@example.com","login":{"username":"greengorilla216","password":"1998","salt":"Vs4V3pHw","md5":"ca46c438a794798358edf0d2ca4904db","sha1":"0eebfa6c26f0f322be1e0745edb45b6f7aa4a2b1","sha256":"c309ffc74616b19907e9a70a7838cb8d2795d14aecf65bcee22f0697f0d88acb"},"dob":"1956-08-04 06:26:17","registered":"2014-05-09 04:36:27","phone":"019467 97455","cell":"0764-342-302","id":{"name":"NINO","value":"OG 57 76 75 W"},"picture":{"large":"https://randomuser.me/api/portraits/women/16.jpg","medium":"https://randomuser.me/api/portraits/med/women/16.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/16.jpg"},"nat":"GB"},{"gender":"female","name":{"title":"miss","first":"barbie","last":"souza"},"location":{"street":"3517 avenida da legalidade","city":"parintins","state":"paraíba","postcode":71087},"email":"barbie.souza@example.com","login":{"username":"bigladybug706","password":"lilly","salt":"Jk7Q4D8r","md5":"7308bc40c6daa2014816172799e07b91","sha1":"9c16fefd1306bfa5b518a54a492ba6bc14a9ab3f","sha256":"52ab4718821aa5d29c09cc085e4ebd97c71ab9ff38280e496fab04b899db65be"},"dob":"1981-01-29 15:13:22","registered":"2005-08-29 23:26:29","phone":"(28) 8206-8049","cell":"(83) 1979-6412","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/37.jpg","medium":"https://randomuser.me/api/portraits/med/women/37.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/37.jpg"},"nat":"BR"},{"gender":"male","name":{"title":"mr","first":"noah","last":"mitchell"},"location":{"street":"1841 20th ave","city":"inwood","state":"alberta","postcode":47882},"email":"noah.mitchell@example.com","login":{"username":"lazysnake222","password":"baldwin","salt":"RLnkxm11","md5":"ae53d3a700feeca3d9f75928a5847ebf","sha1":"d8400ba2c72df5b06c00e204f9e6ca7bd1121ec2","sha256":"897dfc61b31adaaa48b5b9d3a00fcfc9fcfb452c580fe55cb0fb7442b809f0c3"},"dob":"1978-11-07 08:19:19","registered":"2006-04-09 20:54:01","phone":"277-445-7259","cell":"991-890-6275","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/93.jpg","medium":"https://randomuser.me/api/portraits/med/men/93.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/93.jpg"},"nat":"CA"},{"gender":"female","name":{"title":"ms","first":"درسا","last":"محمدخان"},"location":{"street":"3050 شهید مطهری","city":"بوشهر","state":"البرز","postcode":41352},"email":"درسا.محمدخان@example.com","login":{"username":"blackbutterfly880","password":"151515","salt":"fgC6oooc","md5":"29661f93862820415e44dd8ed22eb60f","sha1":"57f3cec8af9be549251251d066ff172903179d34","sha256":"2941de414dbde5eb2816f827f7e5d4e4fbbb7cbed7ddf50edb8da392ec23f78b"},"dob":"1960-05-12 18:02:17","registered":"2011-07-02 00:22:34","phone":"061-45571604","cell":"0928-594-9755","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/17.jpg","medium":"https://randomuser.me/api/portraits/med/women/17.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/17.jpg"},"nat":"IR"},{"gender":"female","name":{"title":"mrs","first":"emma","last":"jean-baptiste"},"location":{"street":"6935 elgin st","city":"delisle","state":"québec","postcode":26914},"email":"emma.jean-baptiste@example.com","login":{"username":"blackgoose967","password":"buddie","salt":"jzy1RPhc","md5":"e38be60f361508b3e802fb6a05e69382","sha1":"95d7e3acc7453f2d2715cd810f636c04c07fd4e6","sha256":"d6f6463a2a3d9a55233f8096b655741b9a14fdf6127c25d765d9fce3e4c35c7c"},"dob":"1991-09-20 21:17:31","registered":"2013-11-13 05:32:30","phone":"447-084-6563","cell":"838-708-6229","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/71.jpg","medium":"https://randomuser.me/api/portraits/med/women/71.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/71.jpg"},"nat":"CA"},{"gender":"female","name":{"title":"miss","first":"olivia","last":"evans"},"location":{"street":"5346 roscommon road","city":"tauranga","state":"tasman","postcode":56642},"email":"olivia.evans@example.com","login":{"username":"heavymeercat203","password":"nudist","salt":"dPoMEebX","md5":"243bb24c4fdc487d41be126685b99e4a","sha1":"049de437ed09b2cb91ed57ed53b5c510f3a67c6a","sha256":"3a298ec9b806bc84d78a1c11c14ee59498c41d6f3b4538e8d93680b8c2175800"},"dob":"1948-10-21 12:18:58","registered":"2012-03-11 22:37:52","phone":"(115)-284-8466","cell":"(212)-792-2299","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/78.jpg","medium":"https://randomuser.me/api/portraits/med/women/78.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/78.jpg"},"nat":"NZ"},{"gender":"male","name":{"title":"mr","first":"milo","last":"ramos"},"location":{"street":"6186 rua amazonas ","city":"colombo","state":"maranhão","postcode":31703},"email":"milo.ramos@example.com","login":{"username":"organicpeacock324","password":"huskies","salt":"S1T0Fw1a","md5":"a41fa8eb7ee0ff8cd38901938f95aca6","sha1":"b03d8e0a3da8575cdf3040e9fd9b0e6a05681221","sha256":"ba5c8969e92ed8ddeb4013e9ca322106d696106056f2a7d9eb5bcf5bb4c3fae9"},"dob":"1949-01-22 14:28:13","registered":"2002-04-29 13:35:06","phone":"(02) 9894-8016","cell":"(78) 2297-6087","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/4.jpg","medium":"https://randomuser.me/api/portraits/med/men/4.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/4.jpg"},"nat":"BR"},{"gender":"male","name":{"title":"mr","first":"manuel","last":"elliott"},"location":{"street":"7798 main road","city":"norwich","state":"hampshire","postcode":"V0A 3XR"},"email":"manuel.elliott@example.com","login":{"username":"organicleopard160","password":"goodgirl","salt":"XxDIaRpP","md5":"1b2fff2cc0219719f77eba4716def238","sha1":"a0e3a73477020c1f880012dc8f89e2c30aa0101e","sha256":"b75529f11a86a819d63b15a1c6b234783797b8405613445d6b79397331c4933a"},"dob":"1985-03-11 08:50:50","registered":"2003-04-25 15:19:37","phone":"019467 17086","cell":"0788-887-995","id":{"name":"NINO","value":"HJ 64 67 29 R"},"picture":{"large":"https://randomuser.me/api/portraits/men/32.jpg","medium":"https://randomuser.me/api/portraits/med/men/32.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/32.jpg"},"nat":"GB"},{"gender":"female","name":{"title":"miss","first":"alexandra","last":"pierce"},"location":{"street":"6349 springfield road","city":"swords","state":"louth","postcode":39524},"email":"alexandra.pierce@example.com","login":{"username":"heavybutterfly691","password":"pippo","salt":"FqCdrhpt","md5":"b0cdf2a0f3e2f917045eb6663672c8bc","sha1":"b31182f7b94f804be383dbdfd1566371b8dd8e49","sha256":"da37b4d8afa2f973e4407c671210b72cb5e1edd761e827bbde9e527d2c9c63ea"},"dob":"1971-07-21 10:10:31","registered":"2009-04-05 13:13:11","phone":"061-652-2664","cell":"081-839-4182","id":{"name":"PPS","value":"1777031T"},"picture":{"large":"https://randomuser.me/api/portraits/women/15.jpg","medium":"https://randomuser.me/api/portraits/med/women/15.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/15.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"miss","first":"geanne","last":"hulleman"},"location":{"street":"2635 kruisstraat","city":"lopik","state":"flevoland","postcode":99242},"email":"geanne.hulleman@example.com","login":{"username":"crazyfish299","password":"gambit","salt":"1g6YD564","md5":"379636906a92d10dad260ec75484b273","sha1":"dd4d9668a84a05169252d2dd272b63ddfb104d4d","sha256":"86bb0d89485d873f9b0b104002ffc77f89cd0374a22c7d6bf1981bff4123ef86"},"dob":"1955-02-19 00:11:50","registered":"2016-05-09 00:27:27","phone":"(436)-211-3896","cell":"(942)-026-9787","id":{"name":"BSN","value":"06488471"},"picture":{"large":"https://randomuser.me/api/portraits/women/34.jpg","medium":"https://randomuser.me/api/portraits/med/women/34.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/34.jpg"},"nat":"NL"},{"gender":"female","name":{"title":"miss","first":"پریا","last":"کریمی"},"location":{"street":"3111 کوی نصر","city":"اهواز","state":"کرمان","postcode":38622},"email":"پریا.کریمی@example.com","login":{"username":"organicbear371","password":"superfly","salt":"aFFofnvy","md5":"fc422a8784f4d4b48f1832d0094f34bb","sha1":"dd7d5ab9d3edf6a212025bc7c79ae2c1e64777bc","sha256":"e8fe13007a6c35252d35e6b569f3899e7aca01b183b4beb1f6fef631355e1174"},"dob":"1948-06-18 09:02:42","registered":"2005-03-02 01:11:21","phone":"083-30647026","cell":"0935-560-4068","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/55.jpg","medium":"https://randomuser.me/api/portraits/med/women/55.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/55.jpg"},"nat":"IR"},{"gender":"male","name":{"title":"mr","first":"mohamed","last":"roman"},"location":{"street":"3579 calle del prado","city":"zaragoza","state":"asturias","postcode":72815},"email":"mohamed.roman@example.com","login":{"username":"whitelion786","password":"roadrunn","salt":"ChOeSt8V","md5":"481962810ac904b45004d0ad2c68542d","sha1":"98bca33abe569c55b6134c806b19e80b3db3693f","sha256":"5e5db99ae103db6def5f0b100ded9e4a618e19a7b3366d98b4c04bfb9f7314e8"},"dob":"1988-09-19 03:20:43","registered":"2004-11-11 07:16:46","phone":"932-304-528","cell":"601-964-500","id":{"name":"DNI","value":"27000171-F"},"picture":{"large":"https://randomuser.me/api/portraits/men/13.jpg","medium":"https://randomuser.me/api/portraits/med/men/13.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/13.jpg"},"nat":"ES"},{"gender":"female","name":{"title":"ms","first":"eevi","last":"lampinen"},"location":{"street":"4288 nordenskiöldinkatu","city":"iitti","state":"åland","postcode":86078},"email":"eevi.lampinen@example.com","login":{"username":"silverleopard232","password":"canada","salt":"9K7SwI7e","md5":"7c40d985a9ecb5ba29f79a9c5d015a04","sha1":"ba90a1fdc3aaca71d4bf4859d97037d5d74b2872","sha256":"f7850a912b2a6f628a09bb600e92d0ffa645f16fd74d271bce25ed30c0f3c5f8"},"dob":"1979-07-17 19:02:20","registered":"2004-04-14 06:36:54","phone":"02-406-029","cell":"040-807-83-34","id":{"name":"HETU","value":"879-2629"},"picture":{"large":"https://randomuser.me/api/portraits/women/21.jpg","medium":"https://randomuser.me/api/portraits/med/women/21.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/21.jpg"},"nat":"FI"},{"gender":"female","name":{"title":"mrs","first":"angela","last":"austin"},"location":{"street":"2919 new road","city":"newport","state":"dyfed","postcode":"Z62 2TP"},"email":"angela.austin@example.com","login":{"username":"ticklishrabbit161","password":"bigdog1","salt":"tH8yvh28","md5":"39ee7014d46c0119b3067ba18428e3ba","sha1":"cecb98623220d553a8e436d5187ff77460d6407d","sha256":"c9d7a15808fdc4a42af8c242a2512c9e3e7ab16dd364a44c9973919859fc90f2"},"dob":"1961-02-22 03:52:14","registered":"2010-08-26 02:18:54","phone":"015395 80743","cell":"0774-241-838","id":{"name":"NINO","value":"RH 60 47 82 S"},"picture":{"large":"https://randomuser.me/api/portraits/women/56.jpg","medium":"https://randomuser.me/api/portraits/med/women/56.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/56.jpg"},"nat":"GB"},{"gender":"male","name":{"title":"mr","first":"emre","last":"durmaz"},"location":{"street":"8549 anafartalar cd","city":"bayburt","state":"kırşehir","postcode":83517},"email":"emre.durmaz@example.com","login":{"username":"whitefish122","password":"opus","salt":"XvkN3hFJ","md5":"b5eb23dcf8602fb6829661bb5417dbf1","sha1":"670e1b294e7f20fd9777d051d576b1ba04ed23f4","sha256":"a830c35175b42933c5ec5b0355edabce09f65e662daf0e524a326789e388cea7"},"dob":"1974-07-29 10:33:15","registered":"2015-12-03 12:03:15","phone":"(248)-981-0837","cell":"(437)-763-6034","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/31.jpg","medium":"https://randomuser.me/api/portraits/med/men/31.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/31.jpg"},"nat":"TR"},{"gender":"male","name":{"title":"mr","first":"magnus","last":"christensen"},"location":{"street":"1933 mariehøj","city":"nørre sundby","state":"hovedstaden","postcode":98320},"email":"magnus.christensen@example.com","login":{"username":"whitekoala252","password":"vikings","salt":"Gl7MCC28","md5":"45f0bd96ff51461489eafd2a084dfcc9","sha1":"2892f3848d5ad83c7664278f4ed1ed55e9f4c2c6","sha256":"acbc27484cefc45f64cae6e6bd95ad0bf8765f527fbd7451babee484a64a1c68"},"dob":"1974-01-28 18:34:57","registered":"2015-05-14 15:58:45","phone":"06051550","cell":"54725818","id":{"name":"CPR","value":"486806-3565"},"picture":{"large":"https://randomuser.me/api/portraits/men/62.jpg","medium":"https://randomuser.me/api/portraits/med/men/62.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/62.jpg"},"nat":"DK"},{"gender":"female","name":{"title":"mrs","first":"sedef","last":"erbay"},"location":{"street":"4029 mevlana cd","city":"yalova","state":"konya","postcode":53121},"email":"sedef.erbay@example.com","login":{"username":"purplesnake784","password":"tito","salt":"HS4y39tD","md5":"cb568271b96462f69b73629b4f08c0a6","sha1":"a60262bacae30f7093c116757a31ad5cf6b56594","sha256":"fe1f9b6450af9755fba08e2265d394de46804784afbbeb1a6ad0950ae4859d8d"},"dob":"1969-11-27 21:00:21","registered":"2010-04-26 12:40:38","phone":"(542)-039-1403","cell":"(416)-223-7543","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/82.jpg","medium":"https://randomuser.me/api/portraits/med/women/82.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/82.jpg"},"nat":"TR"},{"gender":"female","name":{"title":"miss","first":"dora","last":"dunn"},"location":{"street":"6650 dogwood ave","city":"green bay","state":"nebraska","postcode":29761},"email":"dora.dunn@example.com","login":{"username":"bigbear743","password":"bigfoot","salt":"CuY9Y1JB","md5":"2c8ed27001f29f3175de8253ef40575b","sha1":"35c1cf9fa41ce19d9fe3ad3f9389e253a2ea9c42","sha256":"93b47abd61b3ff64b2614ad2224117d49aa236cead2c2c2a75ecd72d2036db20"},"dob":"1969-09-05 12:04:23","registered":"2009-12-02 07:53:50","phone":"(646)-606-7885","cell":"(728)-989-0226","id":{"name":"SSN","value":"932-33-3286"},"picture":{"large":"https://randomuser.me/api/portraits/women/32.jpg","medium":"https://randomuser.me/api/portraits/med/women/32.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/32.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"elizabeth","last":"holt"},"location":{"street":"1302 victoria road","city":"tullamore","state":"clare","postcode":79510},"email":"elizabeth.holt@example.com","login":{"username":"blacklion179","password":"1222","salt":"fTCV3duW","md5":"c5f18be9e743667e1af9bac1bd30f444","sha1":"483a790f98d05da15832b2d8bb3a9855adfcabf3","sha256":"aec151333135935a344db1b674076904bab5703c18419254e293ff8abd0f9b0a"},"dob":"1970-02-04 23:49:01","registered":"2016-07-08 17:48:43","phone":"031-075-5073","cell":"081-860-6150","id":{"name":"PPS","value":"0597687T"},"picture":{"large":"https://randomuser.me/api/portraits/women/82.jpg","medium":"https://randomuser.me/api/portraits/med/women/82.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/82.jpg"},"nat":"IE"},{"gender":"male","name":{"title":"mr","first":"nathaniel","last":"robinson"},"location":{"street":"6112 plum st","city":"mackay","state":"western australia","postcode":4213},"email":"nathaniel.robinson@example.com","login":{"username":"ticklishduck617","password":"lefty","salt":"rQE9jOf1","md5":"9d7f0713b0d72d7a354d92e95a7f8f59","sha1":"b2ba1d46c080d537ec586b4638bddb1e9f68934a","sha256":"fe3016beefe6ed4447908e48a1fa79c0874bdf9202240bbfb47c075bfb5d2147"},"dob":"1969-08-01 03:51:08","registered":"2013-04-09 22:11:27","phone":"00-5948-9651","cell":"0474-328-243","id":{"name":"TFN","value":"608726387"},"picture":{"large":"https://randomuser.me/api/portraits/men/5.jpg","medium":"https://randomuser.me/api/portraits/med/men/5.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/5.jpg"},"nat":"AU"},{"gender":"female","name":{"title":"miss","first":"jeanne","last":"coleman"},"location":{"street":"4360 saddle dr","city":"coral springs","state":"new hampshire","postcode":89802},"email":"jeanne.coleman@example.com","login":{"username":"browncat424","password":"jenna","salt":"N2cPt6wu","md5":"08c78dfeb73478380cc5bc492236453a","sha1":"f5e00855a3680cb22d9330e87c697b3eee14fdec","sha256":"26c865928188d30d2a9d609d0960cae33a3eb23e04525639415b1e8640ef584e"},"dob":"1951-11-17 02:17:38","registered":"2011-02-15 04:12:43","phone":"(977)-915-6527","cell":"(677)-997-9428","id":{"name":"SSN","value":"594-13-2412"},"picture":{"large":"https://randomuser.me/api/portraits/women/32.jpg","medium":"https://randomuser.me/api/portraits/med/women/32.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/32.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"russell","last":"byrd"},"location":{"street":"2538 depaul dr","city":"roseburg","state":"new jersey","postcode":71841},"email":"russell.byrd@example.com","login":{"username":"orangelion502","password":"shei","salt":"pWyZgwny","md5":"d13a91d5e3fcbba3f99e7cacbc503254","sha1":"98ab9c47381776b777453a6cec3ae82de76d4719","sha256":"822795ebee058b3543c6836c9c396243cfdcab59f1254119b6a1d5b4a66005b1"},"dob":"1954-06-12 17:27:47","registered":"2003-05-06 05:26:28","phone":"(943)-496-4820","cell":"(960)-244-9040","id":{"name":"SSN","value":"332-51-4105"},"picture":{"large":"https://randomuser.me/api/portraits/men/75.jpg","medium":"https://randomuser.me/api/portraits/med/men/75.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/75.jpg"},"nat":"US"},{"gender":"male","name":{"title":"monsieur","first":"théo","last":"leroux"},"location":{"street":"3198 rue de l'église","city":"ballens","state":"luzern","postcode":9968},"email":"théo.leroux@example.com","login":{"username":"heavyduck770","password":"pictere","salt":"XOwZilC6","md5":"4d26ecea7d20c82c21399fa1b995fd49","sha1":"edc807d2fa8fec156a1ba7d54b89ff8fc03c7b13","sha256":"e946e1950ed458482e1d74633bb79f0f5940618e93cf3dcc46608e88cd6f2502"},"dob":"1960-04-28 10:40:03","registered":"2015-06-02 03:50:49","phone":"(432)-387-5371","cell":"(621)-313-8335","id":{"name":"AVS","value":"756.NJVD.INKI.63"},"picture":{"large":"https://randomuser.me/api/portraits/men/55.jpg","medium":"https://randomuser.me/api/portraits/med/men/55.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/55.jpg"},"nat":"CH"},{"gender":"female","name":{"title":"miss","first":"mestan","last":"velioğlu"},"location":{"street":"4859 bağdat cd","city":"bartın","state":"erzurum","postcode":85147},"email":"mestan.velioğlu@example.com","login":{"username":"yellowleopard234","password":"cosworth","salt":"oURbOXr0","md5":"c76cf230d2fae68f064d5570e7f089eb","sha1":"29bbd5b8ceb595f00c335fee5b3ed4f21189fe41","sha256":"c21d5478af2fdba39d27321ca144cb4b2d9c1f50c61c384c48cf067d545e00e7"},"dob":"1982-01-01 19:40:17","registered":"2011-03-19 06:39:19","phone":"(688)-903-1625","cell":"(500)-669-7105","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/76.jpg","medium":"https://randomuser.me/api/portraits/med/women/76.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/76.jpg"},"nat":"TR"},{"gender":"male","name":{"title":"mr","first":"malone","last":"perez"},"location":{"street":"8337 rue bony","city":"brest","state":"haute-marne","postcode":26968},"email":"malone.perez@example.com","login":{"username":"beautifulpanda320","password":"forrest","salt":"NRuxwb4z","md5":"1aaedc29b04da4b3ea0b14352e2ba0d0","sha1":"3c54a4daef87975a46108abdf7dd0e3343c556f8","sha256":"6b017559ad67c0e69d51b8333c3f077b95fc9cf380f6f4a7ecf24514157e59fc"},"dob":"1985-11-17 16:46:55","registered":"2002-10-04 10:54:10","phone":"04-14-80-04-54","cell":"06-43-92-85-73","id":{"name":"INSEE","value":"1851044397859 73"},"picture":{"large":"https://randomuser.me/api/portraits/men/55.jpg","medium":"https://randomuser.me/api/portraits/med/men/55.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/55.jpg"},"nat":"FR"},{"gender":"male","name":{"title":"mr","first":"mariano","last":"suarez"},"location":{"street":"8978 calle de bravo murillo","city":"toledo","state":"andalucía","postcode":43396},"email":"mariano.suarez@example.com","login":{"username":"organicfrog392","password":"zhuang","salt":"tI8SGVlt","md5":"90ba2ffb473b98e7a0c9d64c54d591cc","sha1":"4466be4eac8fb5512e841835e1e1fbda1b30bb83","sha256":"7b62b0f7d2f8564f764cf8bf6054dd39db0ceaae36aba9d2194d401f59e87f3b"},"dob":"1989-12-20 11:57:48","registered":"2016-01-08 18:00:46","phone":"959-188-121","cell":"618-835-210","id":{"name":"DNI","value":"51787197-L"},"picture":{"large":"https://randomuser.me/api/portraits/men/95.jpg","medium":"https://randomuser.me/api/portraits/med/men/95.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/95.jpg"},"nat":"ES"},{"gender":"female","name":{"title":"ms","first":"cathy","last":"fowler"},"location":{"street":"8591 church lane","city":"leicester","state":"surrey","postcode":"V84 9SH"},"email":"cathy.fowler@example.com","login":{"username":"redpeacock279","password":"ling","salt":"WlF8XVHE","md5":"eb508c3b7afc8a8aaabb20a0ec6b4d3e","sha1":"9aca399053f2aeb3fc4db2b9d5175ba2f01f52fd","sha256":"e994d7a9dd31d79a8214c8a83665634e1e7e2d8743d95224ff2bd7cd21859120"},"dob":"1993-05-21 20:56:16","registered":"2009-02-23 02:29:49","phone":"015395 32599","cell":"0788-838-644","id":{"name":"NINO","value":"XA 81 62 54 J"},"picture":{"large":"https://randomuser.me/api/portraits/women/86.jpg","medium":"https://randomuser.me/api/portraits/med/women/86.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/86.jpg"},"nat":"GB"},{"gender":"male","name":{"title":"mr","first":"keith","last":"lopez"},"location":{"street":"1582 oak lawn ave","city":"tamworth","state":"australian capital territory","postcode":7268},"email":"keith.lopez@example.com","login":{"username":"blackcat453","password":"muscle","salt":"tmqKfty6","md5":"907ea05301ed2039814e6f46981ebcab","sha1":"07f8d70f3ce12f211af194cb234e063a9495bac8","sha256":"145f9aaabea876f6b7aba24f270228d622f6451ffbdd4ed74aa5083dcee1c0da"},"dob":"1961-11-11 07:40:07","registered":"2004-09-24 13:18:16","phone":"06-3405-7646","cell":"0481-957-604","id":{"name":"TFN","value":"193860449"},"picture":{"large":"https://randomuser.me/api/portraits/men/71.jpg","medium":"https://randomuser.me/api/portraits/med/men/71.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/71.jpg"},"nat":"AU"},{"gender":"female","name":{"title":"ms","first":"eevi","last":"salonen"},"location":{"street":"8454 aleksanterinkatu","city":"oripää","state":"southern ostrobothnia","postcode":12443},"email":"eevi.salonen@example.com","login":{"username":"silverrabbit624","password":"surf","salt":"wCso6p96","md5":"ab9f8a3b6b52bf7f337e94e5af16ac80","sha1":"0eca47f1b4aabfaa34afc31b13df81999aa5918c","sha256":"1b268de1a936507d12dfeb605d67ee293274a4596ca2904898e335d95eeeb1f9"},"dob":"1962-09-17 18:27:15","registered":"2010-10-26 05:30:33","phone":"06-678-077","cell":"045-436-76-37","id":{"name":"HETU","value":"962-728R"},"picture":{"large":"https://randomuser.me/api/portraits/women/55.jpg","medium":"https://randomuser.me/api/portraits/med/women/55.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/55.jpg"},"nat":"FI"},{"gender":"female","name":{"title":"miss","first":"colleen","last":"gregory"},"location":{"street":"7206 karen dr","city":"mackay","state":"victoria","postcode":2818},"email":"colleen.gregory@example.com","login":{"username":"blackpanda169","password":"emmanuel","salt":"tqdEj7xM","md5":"509a6610ebb8c0e7961373aedc3104fb","sha1":"33518d9043889f1fcf2d92392b4a5fadaa901bf5","sha256":"96bbacb5a0dfb2f735d98a6428f71b8cd826d3f084e64b80ab963928188e79b1"},"dob":"1994-02-02 23:13:34","registered":"2010-04-25 00:57:04","phone":"00-5317-5021","cell":"0423-061-133","id":{"name":"TFN","value":"273003610"},"picture":{"large":"https://randomuser.me/api/portraits/women/3.jpg","medium":"https://randomuser.me/api/portraits/med/women/3.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/3.jpg"},"nat":"AU"},{"gender":"female","name":{"title":"ms","first":"vanessa","last":"ward"},"location":{"street":"3793 groveland terrace","city":"springfield","state":"texas","postcode":82762},"email":"vanessa.ward@example.com","login":{"username":"orangebear785","password":"dracula","salt":"yr9Z4uX9","md5":"c6d0f268b3ed25b1cff9c9468f61d5e3","sha1":"51c257398a797c8f24609bf01d6f63483dc8ebac","sha256":"678daf76a27f3986c232bb1af8be7f55893a7bdee67ecf5d3a91d2cd1c975f60"},"dob":"1972-12-22 16:48:32","registered":"2008-06-22 19:05:13","phone":"(425)-025-0233","cell":"(003)-476-4768","id":{"name":"SSN","value":"592-61-7767"},"picture":{"large":"https://randomuser.me/api/portraits/women/71.jpg","medium":"https://randomuser.me/api/portraits/med/women/71.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/71.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"sara","last":"kristensen"},"location":{"street":"9226 paltholmterrasserne","city":"ansager","state":"midtjylland","postcode":88303},"email":"sara.kristensen@example.com","login":{"username":"orangefrog816","password":"mingus","salt":"bIfBXnPN","md5":"ec1672a0ee819d698aa16da37ca5685c","sha1":"1778da0b51dac26f0fc88800d54d2b76697f377d","sha256":"11909b3cfb751dde432e6b0f288db28ca9e1d72ae97e5fcd642b7f720b67c1b5"},"dob":"1976-06-14 01:00:09","registered":"2012-12-10 00:13:13","phone":"03732126","cell":"64173003","id":{"name":"CPR","value":"779799-7832"},"picture":{"large":"https://randomuser.me/api/portraits/women/21.jpg","medium":"https://randomuser.me/api/portraits/med/women/21.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/21.jpg"},"nat":"DK"},{"gender":"male","name":{"title":"mr","first":"luís figo","last":"das neves"},"location":{"street":"9270 rua rio de janeiro ","city":"araçatuba","state":"distrito federal","postcode":99103},"email":"luís figo.dasneves@example.com","login":{"username":"beautifulsnake237","password":"bigpoppa","salt":"xTzzMQAb","md5":"483623a0b8b7187240d5ebc038b7f0f5","sha1":"3b670fa6fe41f13c36bf42719d4fca72ea0f7ca7","sha256":"0cdbe20431fea2c3ef2ce07993bbfabdb1ab913b955c48380da66aeb1ec84932"},"dob":"1976-11-06 06:37:21","registered":"2004-08-02 06:27:33","phone":"(83) 0387-2530","cell":"(09) 7671-1437","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/57.jpg","medium":"https://randomuser.me/api/portraits/med/men/57.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/57.jpg"},"nat":"BR"},{"gender":"female","name":{"title":"ms","first":"آنیتا","last":"سهيلي راد"},"location":{"street":"6209 موسیوند","city":"کرج","state":"فارس","postcode":27832},"email":"آنیتا.سهيليراد@example.com","login":{"username":"brownpeacock157","password":"woohoo","salt":"1zDje3LY","md5":"512b93ad5e6b502184df3893a9b37f73","sha1":"67ae62ecf64e5421c62319db8d22a6620efc5e5c","sha256":"1032c45593ba3059cb412c475db467ab8c91258623f304bce6bb2e57eccb70eb"},"dob":"1944-10-07 13:21:09","registered":"2005-10-14 12:40:59","phone":"039-64466829","cell":"0910-508-3145","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/60.jpg","medium":"https://randomuser.me/api/portraits/med/women/60.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/60.jpg"},"nat":"IR"},{"gender":"male","name":{"title":"mr","first":"آراد","last":"قاسمی"},"location":{"street":"1062 استاد نجات‌اللهی","city":"ساوه","state":"یزد","postcode":29353},"email":"آراد.قاسمی@example.com","login":{"username":"ticklishkoala372","password":"nostromo","salt":"qKuMX4un","md5":"c9453bafb77c9204362797bbe2aabad1","sha1":"d6ce8597e7ba99fef6a650ea7cc863e95f5554bc","sha256":"12b31f4ca1a1db150e7c7afbf0c6a3d559196f51822e4ce481feb78be4df484e"},"dob":"1952-03-01 17:12:59","registered":"2013-09-20 06:39:06","phone":"034-75040063","cell":"0979-490-1872","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/96.jpg","medium":"https://randomuser.me/api/portraits/med/men/96.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/96.jpg"},"nat":"IR"},{"gender":"female","name":{"title":"mrs","first":"lotte","last":"schmid"},"location":{"street":"8378 lessingstraße","city":"chemnitzer land","state":"niedersachsen","postcode":22539},"email":"lotte.schmid@example.com","login":{"username":"purpleladybug653","password":"tzpvaw","salt":"my2AK2ss","md5":"966d7502e27ac243de2410679810fd4c","sha1":"bc201822e1d9774e5d79074e7b3948df46fe3b43","sha256":"8315d9fc679040a15a943879d2beaff2335280d2f591965366ae453968a0a408"},"dob":"1968-08-28 21:24:42","registered":"2008-05-03 18:22:39","phone":"0106-8358988","cell":"0171-5736510","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/59.jpg","medium":"https://randomuser.me/api/portraits/med/women/59.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/59.jpg"},"nat":"DE"},{"gender":"female","name":{"title":"madame","first":"maélie","last":"guillot"},"location":{"street":"7554 rue denfert-rochereau","city":"chapelle-sur-moudon","state":"neuchâtel","postcode":5791},"email":"maélie.guillot@example.com","login":{"username":"bigduck160","password":"zildjian","salt":"78lTw7v8","md5":"7bddac3b58defadfe9126fe59b793be2","sha1":"14d37d4604aca616d3cfb6760c69d7b5d7468c30","sha256":"c4a6b1e9e9c7a7bf34a58b93a5c5bbffd4e16a456f3727261cc04e174f35c5ea"},"dob":"1981-06-07 12:50:31","registered":"2010-09-21 21:13:40","phone":"(672)-319-4472","cell":"(844)-796-8875","id":{"name":"AVS","value":"756.EXLU.XLNQ.29"},"picture":{"large":"https://randomuser.me/api/portraits/women/20.jpg","medium":"https://randomuser.me/api/portraits/med/women/20.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/20.jpg"},"nat":"CH"},{"gender":"male","name":{"title":"mr","first":"mason","last":"slawa"},"location":{"street":"4039 brock rd","city":"hampton","state":"new brunswick","postcode":30929},"email":"mason.slawa@example.com","login":{"username":"lazylion255","password":"amature","salt":"CwgGsn6x","md5":"362b2f28a96d3da1e0ec665469838085","sha1":"160d2fe95c4334cf85ef2453203ab43f8fad2452","sha256":"19996f762dec821bb393c8d1fa612bc8693d9cb190939c70a3df0e4e00c544ca"},"dob":"1963-03-20 17:38:21","registered":"2004-06-08 14:10:44","phone":"248-755-6937","cell":"994-397-4080","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/36.jpg","medium":"https://randomuser.me/api/portraits/med/men/36.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/36.jpg"},"nat":"CA"},{"gender":"female","name":{"title":"mrs","first":"eléonore","last":"le gall"},"location":{"street":"6425 grande rue","city":"orléans","state":"val-de-marne","postcode":85469},"email":"eléonore.legall@example.com","login":{"username":"bigpeacock980","password":"slayer","salt":"TQTrGKt5","md5":"6d9637c6a602b9f875477664337a870c","sha1":"abdef657136668f3cba0c0fbc2ec3c2f81f9e3be","sha256":"716c802dda0b646edc6327c856a092f1e1390c7affeb155f1da19cdbcf073eb3"},"dob":"1956-04-15 14:32:33","registered":"2012-07-13 16:37:52","phone":"02-19-24-60-50","cell":"06-13-80-19-53","id":{"name":"INSEE","value":"256304882561 94"},"picture":{"large":"https://randomuser.me/api/portraits/women/89.jpg","medium":"https://randomuser.me/api/portraits/med/women/89.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/89.jpg"},"nat":"FR"},{"gender":"female","name":{"title":"mrs","first":"nuria","last":"morales"},"location":{"street":"3574 calle de arganzuela","city":"las palmas de gran canaria","state":"castilla y león","postcode":80062},"email":"nuria.morales@example.com","login":{"username":"redsnake109","password":"carpet","salt":"mEtqCKGu","md5":"026c2605056681aad695b63752f6373a","sha1":"cc1d7676e8ab6995866e5b3b03bb48dd33679dfe","sha256":"4d320dd09d0a5feb5cf05855470661d308c00a47013b04cb8c1d5570bdabc7e4"},"dob":"1986-12-27 00:09:11","registered":"2016-02-11 05:27:57","phone":"989-944-484","cell":"692-709-848","id":{"name":"DNI","value":"46545622-N"},"picture":{"large":"https://randomuser.me/api/portraits/women/32.jpg","medium":"https://randomuser.me/api/portraits/med/women/32.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/32.jpg"},"nat":"ES"},{"gender":"female","name":{"title":"miss","first":"katherine","last":"chambers"},"location":{"street":"2204 grove road","city":"leicester","state":"county londonderry","postcode":"QZ2W 1BQ"},"email":"katherine.chambers@example.com","login":{"username":"bigbutterfly464","password":"camera","salt":"AgeJSvHL","md5":"0a23c990de2d4e7a9d74b04ffc37b49c","sha1":"2e8c117164203d37a365e86dc33686b521516a24","sha256":"06f734d5456bfa7b5714565eec7fd88363764bc0bef6762e7de5098468a87a79"},"dob":"1980-09-21 02:14:05","registered":"2013-06-23 11:27:03","phone":"016977 8385","cell":"0773-720-246","id":{"name":"NINO","value":"WH 92 38 84 C"},"picture":{"large":"https://randomuser.me/api/portraits/women/43.jpg","medium":"https://randomuser.me/api/portraits/med/women/43.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/43.jpg"},"nat":"GB"},{"gender":"female","name":{"title":"ms","first":"efigênia","last":"teixeira"},"location":{"street":"6261 rua principal","city":"jaraguá do sul","state":"bahia","postcode":63881},"email":"efigênia.teixeira@example.com","login":{"username":"silvercat929","password":"frosty","salt":"AbXMKJNh","md5":"cd4bfe3eac7b26d5f537133a0aab79ce","sha1":"10692196ac8298e5ea7fa3d031abb3cc4c8402a8","sha256":"2d4831a29bb80b52ac4b95cb82acfbab3220860788c2dfa386539c7456d9b913"},"dob":"1967-04-18 05:48:38","registered":"2012-04-11 23:58:57","phone":"(11) 8302-1307","cell":"(63) 2652-6274","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/62.jpg","medium":"https://randomuser.me/api/portraits/med/women/62.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/62.jpg"},"nat":"BR"},{"gender":"female","name":{"title":"mrs","first":"carolina","last":"iglesias"},"location":{"street":"7387 calle nebrija","city":"valladolid","state":"comunidad de madrid","postcode":66626},"email":"carolina.iglesias@example.com","login":{"username":"greenkoala272","password":"goodgirl","salt":"uUU8n1Pk","md5":"68e796fdb1aadccc4470cb6347da0cbc","sha1":"7d7553405e07e0f22613098f6c4478742ae8af3a","sha256":"9ce78c3f224bbe9da8fcf1211b6007b09e9761725a488b0d54953c9d4f180cc2"},"dob":"1965-09-17 23:29:10","registered":"2014-04-22 22:54:18","phone":"931-023-735","cell":"686-116-999","id":{"name":"DNI","value":"21009306-W"},"picture":{"large":"https://randomuser.me/api/portraits/women/88.jpg","medium":"https://randomuser.me/api/portraits/med/women/88.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/88.jpg"},"nat":"ES"},{"gender":"male","name":{"title":"mr","first":"barış","last":"mayhoş"},"location":{"street":"4486 bağdat cd","city":"adıyaman","state":"çanakkale","postcode":52233},"email":"barış.mayhoş@example.com","login":{"username":"greenmeercat541","password":"shooter","salt":"rZor3L6i","md5":"87701f3ffad8d811ab49ded3576f0d9b","sha1":"159eab69d434fffee7392d1732e1abe7e013708d","sha256":"d4c72717e28ab4e983bea22bd613d21f212925033235875200c7eca7636b86d8"},"dob":"1974-03-03 10:25:43","registered":"2012-07-28 19:23:17","phone":"(941)-603-2348","cell":"(691)-292-3365","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/29.jpg","medium":"https://randomuser.me/api/portraits/med/men/29.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/29.jpg"},"nat":"TR"},{"gender":"female","name":{"title":"miss","first":"iida","last":"hamalainen"},"location":{"street":"9198 korkeavuorenkatu","city":"sysmä","state":"southern ostrobothnia","postcode":19706},"email":"iida.hamalainen@example.com","login":{"username":"goldenbird764","password":"hill","salt":"D6mFveBm","md5":"c7a8443e602a7d1bc74c3bbec3f503da","sha1":"a7779c3d4b4cd3f483137c51c23718d7dff67fc0","sha256":"232372568887162435ead2b0411fc3a70562a77af04595c28c99fc5c469b409b"},"dob":"1990-12-08 12:05:11","registered":"2004-07-29 15:34:45","phone":"08-659-190","cell":"041-766-80-98","id":{"name":"HETU","value":"1790-490R"},"picture":{"large":"https://randomuser.me/api/portraits/women/94.jpg","medium":"https://randomuser.me/api/portraits/med/women/94.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/94.jpg"},"nat":"FI"},{"gender":"male","name":{"title":"mr","first":"آرتين","last":"پارسا"},"location":{"street":"5139 آزادی","city":"گلستان","state":"سیستان و بلوچستان","postcode":79740},"email":"آرتين.پارسا@example.com","login":{"username":"lazyelephant744","password":"dawn","salt":"xsZcely8","md5":"52a49a439f082e77997ecd41b3913647","sha1":"6523d6c01c0d789c407fc64747a50e18b3626090","sha256":"5639937e30a8b499f6eae05545b2f483ab07fbf052988bded536c4df423bb091"},"dob":"1993-07-18 21:15:32","registered":"2002-05-23 12:15:47","phone":"034-67151764","cell":"0972-978-9649","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/31.jpg","medium":"https://randomuser.me/api/portraits/med/men/31.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/31.jpg"},"nat":"IR"},{"gender":"female","name":{"title":"ms","first":"noémie","last":"young"},"location":{"street":"4710 alfred st","city":"field","state":"british columbia","postcode":94583},"email":"noémie.young@example.com","login":{"username":"silverdog669","password":"123456789","salt":"HrnS8N3l","md5":"5ba01a42c7b2c3ea262a841ed7d6cd25","sha1":"93df86ebd27cc257359fc8b1c0deeae1649110ef","sha256":"96364f8b5d0b6e16641c860433a97e9b90cece6df69c063b271a48bd6c71cc4c"},"dob":"1986-03-07 11:44:45","registered":"2011-07-28 16:29:27","phone":"283-951-3003","cell":"527-215-9392","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/94.jpg","medium":"https://randomuser.me/api/portraits/med/women/94.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/94.jpg"},"nat":"CA"},{"gender":"male","name":{"title":"mr","first":"finn","last":"roberts"},"location":{"street":"2067 maxwell road","city":"napier","state":"northland","postcode":79474},"email":"finn.roberts@example.com","login":{"username":"blackgorilla680","password":"monkey12","salt":"PDEYmMKk","md5":"a540352a74c9285081d4e002ed4b5def","sha1":"af7989d7c96863771f4a5c84873891e6e55286c9","sha256":"ec23506421bc9c895bc062dfe22103a857484f3f265ffc901368128c40d2369f"},"dob":"1953-12-18 10:40:52","registered":"2008-03-02 04:00:54","phone":"(590)-780-5851","cell":"(034)-163-9839","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/25.jpg","medium":"https://randomuser.me/api/portraits/med/men/25.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/25.jpg"},"nat":"NZ"},{"gender":"male","name":{"title":"monsieur","first":"anthony","last":"deschamps"},"location":{"street":"9520 place du 8 février 1962","city":"ogens","state":"schwyz","postcode":7854},"email":"anthony.deschamps@example.com","login":{"username":"goldenladybug375","password":"bear","salt":"lTgDokIM","md5":"24fe824a281b5414650efb04036ac331","sha1":"241dcac8f8264a6b2fa534072610bc76308fddbd","sha256":"5f38b8b34ca3ffd01e545ebf1148bee73d5030c429db3d73dc419fe9ed69c121"},"dob":"1984-07-21 00:29:44","registered":"2005-03-04 11:27:43","phone":"(230)-524-1864","cell":"(652)-955-2060","id":{"name":"AVS","value":"756.WZSI.NKQI.92"},"picture":{"large":"https://randomuser.me/api/portraits/men/95.jpg","medium":"https://randomuser.me/api/portraits/med/men/95.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/95.jpg"},"nat":"CH"},{"gender":"female","name":{"title":"ms","first":"thea","last":"mortensen"},"location":{"street":"1894 ægirsvej","city":"roskilde","state":"syddanmark","postcode":23411},"email":"thea.mortensen@example.com","login":{"username":"tinywolf252","password":"darklord","salt":"EBN5dOvt","md5":"c56ad787d5d552274da2c30f0f5b697f","sha1":"de77667b5bfb45c1f0d3d048368c67c8481b385e","sha256":"941e2905bef7455c511b05844398dd3e3ed9f6582916f95dc3e4daaefdc37ff5"},"dob":"1976-09-06 22:47:53","registered":"2004-12-12 05:58:44","phone":"52529049","cell":"92473777","id":{"name":"CPR","value":"871633-5916"},"picture":{"large":"https://randomuser.me/api/portraits/women/8.jpg","medium":"https://randomuser.me/api/portraits/med/women/8.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/8.jpg"},"nat":"DK"},{"gender":"male","name":{"title":"monsieur","first":"william","last":"bertrand"},"location":{"street":"8091 rue de l'église","city":"corcelles-le-jorat","state":"luzern","postcode":6279},"email":"william.bertrand@example.com","login":{"username":"silverpanda629","password":"getsome","salt":"xSKAxxcn","md5":"46f7b656dfbe371b9a816caaf5b2acb1","sha1":"508316a6ab64edc8463c2feb66eec09ac45f6f56","sha256":"d6dda85062a2b963f29642456df4c633f17b5765c7e3671c86a28217de312c03"},"dob":"1968-06-17 00:30:04","registered":"2004-01-09 06:06:53","phone":"(794)-529-1696","cell":"(711)-854-6848","id":{"name":"AVS","value":"756.JGOA.GMIZ.53"},"picture":{"large":"https://randomuser.me/api/portraits/men/6.jpg","medium":"https://randomuser.me/api/portraits/med/men/6.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/6.jpg"},"nat":"CH"},{"gender":"male","name":{"title":"mr","first":"mathéo","last":"muller"},"location":{"street":"4638 route de genas","city":"toulouse","state":"oise","postcode":90370},"email":"mathéo.muller@example.com","login":{"username":"yellowmouse841","password":"frost","salt":"lCte3Cxy","md5":"89dd28156ba2eb53f9d3081c01af777d","sha1":"6561413dda15315dc2bb2e037851b458cce58a0d","sha256":"8a539fb1939b7054a5b61e3d11f6319cf853f72a05416b7354663c03a3ce2640"},"dob":"1993-11-21 06:26:02","registered":"2012-05-12 02:19:03","phone":"05-02-23-58-02","cell":"06-54-67-35-17","id":{"name":"INSEE","value":"1931026652556 44"},"picture":{"large":"https://randomuser.me/api/portraits/men/65.jpg","medium":"https://randomuser.me/api/portraits/med/men/65.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/65.jpg"},"nat":"FR"},{"gender":"male","name":{"title":"mr","first":"nihal","last":"akay"},"location":{"street":"5239 tunalı hilmi cd","city":"van","state":"isparta","postcode":54402},"email":"nihal.akay@example.com","login":{"username":"browncat742","password":"door","salt":"DSd45PWZ","md5":"e0d09a5438aa571f3622cb96c098a52b","sha1":"9ff70a642620cc677ce42f23472951c0b023f763","sha256":"3f6767ad4f49ec6b5d28e95efb7883dbaa200851659a13f5a20df7162c088d77"},"dob":"1952-10-16 00:18:38","registered":"2012-03-01 21:37:56","phone":"(727)-406-6579","cell":"(512)-076-3896","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/51.jpg","medium":"https://randomuser.me/api/portraits/med/men/51.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/51.jpg"},"nat":"TR"},{"gender":"male","name":{"title":"mr","first":"lance","last":"olson"},"location":{"street":"6980 the drive","city":"bristol","state":"humberside","postcode":"LT0 8HJ"},"email":"lance.olson@example.com","login":{"username":"brownbutterfly350","password":"cohiba","salt":"TduJQcW7","md5":"3e19816cdf32561b9f86f55449bfed88","sha1":"2caf2777dd8b0f67e9e35658e29fd75bb097a707","sha256":"c66ce11faca82cb26d4a5f6a709c5ad2693453656eac10e4e1e9d16075fd0eae"},"dob":"1959-07-31 23:28:46","registered":"2016-08-05 17:36:57","phone":"017683 75438","cell":"0782-363-284","id":{"name":"NINO","value":"XC 84 88 81 H"},"picture":{"large":"https://randomuser.me/api/portraits/men/12.jpg","medium":"https://randomuser.me/api/portraits/med/men/12.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/12.jpg"},"nat":"GB"},{"gender":"male","name":{"title":"mr","first":"cesário","last":"araújo"},"location":{"street":"2139 rua amazonas ","city":"itapipoca","state":"paraíba","postcode":31476},"email":"cesário.araújo@example.com","login":{"username":"purplefrog935","password":"hardcore","salt":"oCb1ufLo","md5":"7bfbea1aeeda194a5b6a67d40f8e768f","sha1":"9422087b0ae9201355bb39ef42c44a6099efc884","sha256":"62851f8838e6aab543e02fd5ad01c4c5fdf8c99876512c27724fc582bfac142c"},"dob":"1965-10-30 17:44:35","registered":"2016-04-15 06:39:09","phone":"(20) 9796-5231","cell":"(42) 0302-6212","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/52.jpg","medium":"https://randomuser.me/api/portraits/med/men/52.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/52.jpg"},"nat":"BR"},{"gender":"male","name":{"title":"mr","first":"adrian","last":"möller"},"location":{"street":"6357 buchenweg","city":"görlitz","state":"niedersachsen","postcode":53600},"email":"adrian.möller@example.com","login":{"username":"blackmouse523","password":"trooper","salt":"oITxdvPF","md5":"762a8dbd7011eaa74e61709b6bb69967","sha1":"ddaed8e60588eec8f861523f75ab2ad209ff1776","sha256":"d1a95ca545b77615cf2c19d63f9ad3f5b404d8d6ea7603a48b2e483d77f40bc0"},"dob":"1990-08-23 03:29:57","registered":"2008-08-30 20:56:15","phone":"0302-7318029","cell":"0175-4985781","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/12.jpg","medium":"https://randomuser.me/api/portraits/med/men/12.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/12.jpg"},"nat":"DE"},{"gender":"male","name":{"title":"mr","first":"edgar","last":"carter"},"location":{"street":"2238 boghall road","city":"wicklow","state":"fingal","postcode":70945},"email":"edgar.carter@example.com","login":{"username":"blackgoose286","password":"blam","salt":"RZuBDvAd","md5":"44673f61e62570f56d66b0bfdf95f354","sha1":"9da02aac92e207a312619fdfca3636350e9b4d32","sha256":"c562393e203d98e42e5e48792e54ab4054f00ff86538b75db9aae46c538e2d2a"},"dob":"1948-01-08 19:58:17","registered":"2013-05-06 05:07:30","phone":"051-476-7017","cell":"081-935-3804","id":{"name":"PPS","value":"1898502T"},"picture":{"large":"https://randomuser.me/api/portraits/men/33.jpg","medium":"https://randomuser.me/api/portraits/med/men/33.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/33.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"mrs","first":"olivia","last":"murto"},"location":{"street":"6398 nordenskiöldinkatu","city":"vesanto","state":"päijät-häme","postcode":40238},"email":"olivia.murto@example.com","login":{"username":"silverbutterfly508","password":"ghost1","salt":"44z5JiyG","md5":"5bc694c51a74fd65139698dd8dc021b7","sha1":"54314741f5845357d570da4e3b8b0eba45dfb3d8","sha256":"a54c5e83522db4547bd97e71c585d58fbf55b79ef52170c11ec087b2a7af0460"},"dob":"1979-07-01 09:29:38","registered":"2004-12-28 17:54:45","phone":"05-800-792","cell":"045-528-58-42","id":{"name":"HETU","value":"679-516V"},"picture":{"large":"https://randomuser.me/api/portraits/women/15.jpg","medium":"https://randomuser.me/api/portraits/med/women/15.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/15.jpg"},"nat":"FI"},{"gender":"female","name":{"title":"mrs","first":"هلیا","last":"حیدری"},"location":{"street":"4049 میدان شمشیری","city":"گلستان","state":"یزد","postcode":59945},"email":"هلیا.حیدری@example.com","login":{"username":"lazycat942","password":"quest","salt":"V7uxfGNI","md5":"69b0c6f6207581f53c9433478751bbbe","sha1":"58eaa817335075243438ce67a1ee021a4e648f30","sha256":"bcf326e2475e264518fa49c8e8ab34ebea197b24e986190f7639d5a277c76340"},"dob":"1946-04-16 01:12:37","registered":"2003-01-14 13:00:42","phone":"025-49942298","cell":"0924-075-6618","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/5.jpg","medium":"https://randomuser.me/api/portraits/med/women/5.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/5.jpg"},"nat":"IR"},{"gender":"male","name":{"title":"mr","first":"darryl","last":"harris"},"location":{"street":"7527 mill road","city":"ratoath","state":"louth","postcode":97754},"email":"darryl.harris@example.com","login":{"username":"smallmeercat135","password":"susie","salt":"ix5TlqRb","md5":"e38c0ad9d44e615515e62e3efb3e2350","sha1":"b066e6d6b3c73e568a0c5051bcbdb8b00121ee3f","sha256":"43dcb243e0334264ec5c3bf44c6c02391b8c9b41f7a82b67f1a974ea8cf09aee"},"dob":"1975-02-27 21:17:35","registered":"2010-02-10 10:57:04","phone":"061-119-4122","cell":"081-649-7380","id":{"name":"PPS","value":"7650611T"},"picture":{"large":"https://randomuser.me/api/portraits/men/99.jpg","medium":"https://randomuser.me/api/portraits/med/men/99.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/99.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"miss","first":"isabel","last":"cano"},"location":{"street":"5907 calle de la democracia","city":"castellón de la plana","state":"galicia","postcode":18258},"email":"isabel.cano@example.com","login":{"username":"greenbutterfly741","password":"raistlin","salt":"bcgAWZbP","md5":"7ba25cb30d5bf733e0dabb723675f242","sha1":"92da2d37c6f27675329cedb11c9593d333e8054e","sha256":"076b1699afd9f96edb0f62c69d8b29051e05563af06c24a9f1e5b041b19e7549"},"dob":"1965-09-09 08:37:27","registered":"2009-01-28 14:10:44","phone":"923-658-965","cell":"624-529-746","id":{"name":"DNI","value":"04686160-I"},"picture":{"large":"https://randomuser.me/api/portraits/women/74.jpg","medium":"https://randomuser.me/api/portraits/med/women/74.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/74.jpg"},"nat":"ES"},{"gender":"female","name":{"title":"miss","first":"vilma","last":"latvala"},"location":{"street":"9246 aleksanterinkatu","city":"juva","state":"north karelia","postcode":59333},"email":"vilma.latvala@example.com","login":{"username":"purpleostrich737","password":"soccer1","salt":"20sbgePD","md5":"83dfe1245e9524872aa31f79eddb43e9","sha1":"931c127784d4b0d6c65d599cb15c770a7075080b","sha256":"42c3f67d602fdefd5df446e40511a72161dd37bbe2e499249cea6a0a71642726"},"dob":"1955-12-21 02:48:28","registered":"2008-04-05 18:04:35","phone":"02-981-381","cell":"049-200-91-91","id":{"name":"HETU","value":"1455-3005"},"picture":{"large":"https://randomuser.me/api/portraits/women/36.jpg","medium":"https://randomuser.me/api/portraits/med/women/36.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/36.jpg"},"nat":"FI"},{"gender":"male","name":{"title":"mr","first":"onur","last":"akyüz"},"location":{"street":"2648 mevlana cd","city":"İstanbul","state":"bartın","postcode":21897},"email":"onur.akyüz@example.com","login":{"username":"organicbutterfly982","password":"penny1","salt":"hn1Tvvdl","md5":"8947d3fc0601556eaa55b12a300a1da8","sha1":"aa1f1857b3576ede45ac9e450b4ba81715b6002f","sha256":"ba75d1ee491b80970c17fea2dc086cc288d8b311c7f00e3f8f2a58d5e8bc4952"},"dob":"1982-12-06 11:21:35","registered":"2012-05-21 06:08:22","phone":"(050)-534-7762","cell":"(065)-792-8534","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/58.jpg","medium":"https://randomuser.me/api/portraits/med/men/58.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/58.jpg"},"nat":"TR"},{"gender":"female","name":{"title":"miss","first":"deniz","last":"kıraç"},"location":{"street":"1810 tunalı hilmi cd","city":"şanlıurfa","state":"nevşehir","postcode":83544},"email":"deniz.kıraç@example.com","login":{"username":"beautifulelephant571","password":"grizzly","salt":"BGgqaOV6","md5":"5ec76e81015153efa9e283941ed7efe9","sha1":"523a3c3ea81fbd349ae8ec87c420acdd401dfb56","sha256":"45a7d68314cc9965b3b612815c93872a8bd5035db3536df78a1d622cce4529e6"},"dob":"1966-04-16 01:37:01","registered":"2011-08-08 18:06:55","phone":"(159)-712-4044","cell":"(258)-117-8766","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/86.jpg","medium":"https://randomuser.me/api/portraits/med/women/86.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/86.jpg"},"nat":"TR"},{"gender":"female","name":{"title":"ms","first":"vanesa","last":"moura"},"location":{"street":"9177 rua santa luzia ","city":"rio grande","state":"maranhão","postcode":59040},"email":"vanesa.moura@example.com","login":{"username":"ticklishbear186","password":"firefigh","salt":"3tISvjtn","md5":"979da24a41acd1b456586887e5ca3ba4","sha1":"99b74dba04e26fe0d98eaf755e1577385e9e8101","sha256":"806dc3d723e868ca85421f5366dcdee67697143eb159f5d5b83c67fa69d703ca"},"dob":"1969-11-10 01:09:21","registered":"2003-04-29 09:09:17","phone":"(13) 8313-7677","cell":"(19) 3350-2971","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/44.jpg","medium":"https://randomuser.me/api/portraits/med/women/44.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/44.jpg"},"nat":"BR"},{"gender":"male","name":{"title":"mr","first":"agustin","last":"castro"},"location":{"street":"9163 calle de tetuán","city":"gijón","state":"canarias","postcode":43098},"email":"agustin.castro@example.com","login":{"username":"orangeleopard942","password":"visa","salt":"7sp6EFLt","md5":"7bf1fbb29f38487938af3ebc2cd65795","sha1":"e658b8233998d3143836ca26b61f79237663a0f4","sha256":"593aa0b66b0737eb755e6df346be611c717a072ddfbe2876a7a308166fd05730"},"dob":"1972-01-19 12:00:25","registered":"2014-06-18 19:30:59","phone":"915-145-533","cell":"685-029-731","id":{"name":"DNI","value":"73396564-K"},"picture":{"large":"https://randomuser.me/api/portraits/men/96.jpg","medium":"https://randomuser.me/api/portraits/med/men/96.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/96.jpg"},"nat":"ES"},{"gender":"male","name":{"title":"mr","first":"lucas","last":"mccoy"},"location":{"street":"3682 camden ave","city":"chesapeake","state":"tennessee","postcode":22424},"email":"lucas.mccoy@example.com","login":{"username":"redlion798","password":"insanity","salt":"jxCR98HD","md5":"a7637c1baaf551bc2b6a2bbee6a66154","sha1":"45deb6d4f23b7be9cd552e26c5876c974c7a6cf4","sha256":"fb47769ddc4e062ea8745653803ce1e260b3193f7b48502bad18ac835e970926"},"dob":"1990-03-21 03:19:22","registered":"2009-05-05 11:51:06","phone":"(955)-824-6261","cell":"(370)-305-4594","id":{"name":"SSN","value":"994-80-9208"},"picture":{"large":"https://randomuser.me/api/portraits/men/26.jpg","medium":"https://randomuser.me/api/portraits/med/men/26.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/26.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"greta","last":"bender"},"location":{"street":"1568 beethovenstraße","city":"kamenz","state":"sachsen-anhalt","postcode":24315},"email":"greta.bender@example.com","login":{"username":"smallwolf393","password":"farmboy","salt":"FdRd2Gdw","md5":"8ba4f2b6fa2fcf0fd4b9fceeea96f0ca","sha1":"a5b45835171c1ee741b711fee84585ddd1fdeecf","sha256":"8fc6f67d7d901e96520742b1521d700209551e633182669180e6b9a7ab4432f7"},"dob":"1948-12-02 11:07:44","registered":"2007-07-18 16:06:40","phone":"0290-7120906","cell":"0170-5786306","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/77.jpg","medium":"https://randomuser.me/api/portraits/med/women/77.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/77.jpg"},"nat":"DE"},{"gender":"male","name":{"title":"mr","first":"jorge","last":"gregory"},"location":{"street":"2114 timber wolf trail","city":"reno","state":"nevada","postcode":36711},"email":"jorge.gregory@example.com","login":{"username":"crazytiger579","password":"stephen","salt":"qMt5KTEH","md5":"39facfc3ccef9acf1308ae4da3d6f903","sha1":"0a6e98677162317a959e2194f8d0003d4d35b6bb","sha256":"23de8670a449aaa2c307ac95e5adc1b14d3c3f63d7f3233d807e093ebd813a1e"},"dob":"1981-09-23 05:43:08","registered":"2015-03-14 23:08:22","phone":"(054)-607-9099","cell":"(204)-883-5737","id":{"name":"SSN","value":"337-31-9738"},"picture":{"large":"https://randomuser.me/api/portraits/men/36.jpg","medium":"https://randomuser.me/api/portraits/med/men/36.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/36.jpg"},"nat":"US"},{"gender":"male","name":{"title":"monsieur","first":"thomas","last":"joly"},"location":{"street":"2745 avenue du fort-caire","city":"peyres-possens","state":"thurgau","postcode":9293},"email":"thomas.joly@example.com","login":{"username":"goldensnake726","password":"alexander","salt":"v1n5q42p","md5":"fe9efcb54fb2d55a2b8d2f5560609b9d","sha1":"318be5d63fe951262f3725f9f93ca4db6364389a","sha256":"db0e6c990d47ceb079e6dbcc7cdf40b230f41e33a7ce74fe89155f4891860326"},"dob":"1957-10-17 21:31:06","registered":"2012-11-14 17:49:44","phone":"(931)-158-8116","cell":"(133)-172-8230","id":{"name":"AVS","value":"756.NORG.POVC.10"},"picture":{"large":"https://randomuser.me/api/portraits/men/18.jpg","medium":"https://randomuser.me/api/portraits/med/men/18.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/18.jpg"},"nat":"CH"},{"gender":"male","name":{"title":"mr","first":"stian","last":"pander"},"location":{"street":"9607 korte minrebroederstraat","city":"hillegom","state":"noord-brabant","postcode":10821},"email":"stian.pander@example.com","login":{"username":"lazyrabbit331","password":"nuan","salt":"tCa4AmDv","md5":"2060fbbd67fa8e25c3f326438dbc8bd2","sha1":"9bf5183cd79ba57a1014eddd23dc6334a2240f0a","sha256":"d19d53f2ac4adbb10a615f2129910540f8e3f7f2f64c3454ee5c1f8f5e2056ca"},"dob":"1969-08-29 09:10:00","registered":"2004-05-01 02:56:04","phone":"(423)-652-5230","cell":"(240)-260-7849","id":{"name":"BSN","value":"34277924"},"picture":{"large":"https://randomuser.me/api/portraits/men/62.jpg","medium":"https://randomuser.me/api/portraits/med/men/62.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/62.jpg"},"nat":"NL"},{"gender":"male","name":{"title":"mr","first":"aidan","last":"evans"},"location":{"street":"3136 gloucester street","city":"invercargill","state":"northland","postcode":25288},"email":"aidan.evans@example.com","login":{"username":"orangebutterfly228","password":"tomtom","salt":"7kP8q5YJ","md5":"20ba1ffc71d90249c7d93db919e80711","sha1":"eed75d68ec7d77f3d9d64737c24882fc971eea45","sha256":"b261fc2c1e9aab4941d751f623a0d9f5fefd51a569be816279df808d31c0c54d"},"dob":"1994-03-15 22:09:29","registered":"2013-01-21 22:49:02","phone":"(334)-541-5481","cell":"(809)-482-8720","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/3.jpg","medium":"https://randomuser.me/api/portraits/med/men/3.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/3.jpg"},"nat":"NZ"},{"gender":"male","name":{"title":"mr","first":"jimi","last":"waara"},"location":{"street":"5349 korkeavuorenkatu","city":"sonkajärvi","state":"satakunta","postcode":99392},"email":"jimi.waara@example.com","login":{"username":"smallgoose786","password":"circus","salt":"gz0BV2cP","md5":"f4a65823c3d57b26322724017be084d6","sha1":"563893a6df310d48a34b94cccdc65f06e76df30b","sha256":"78dcf3eded4309a5d78ce678e650a34f21f31234291ab50b16d2dbc493dfb60b"},"dob":"1975-04-02 02:24:41","registered":"2004-11-25 19:35:48","phone":"02-281-873","cell":"047-072-26-15","id":{"name":"HETU","value":"675-4911"},"picture":{"large":"https://randomuser.me/api/portraits/men/14.jpg","medium":"https://randomuser.me/api/portraits/med/men/14.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/14.jpg"},"nat":"FI"},{"gender":"male","name":{"title":"mr","first":"alex","last":"wilson"},"location":{"street":"2818 maunganui road","city":"taupo","state":"canterbury","postcode":27337},"email":"alex.wilson@example.com","login":{"username":"organickoala975","password":"aptiva","salt":"4RHG5Uwf","md5":"1c923e40675ece09257d0e66c37c480f","sha1":"5d02ec74be84c3d09709d4b5c55717328809a0c0","sha256":"6e2ee121a418facf6eaab7be7ca225431282fd73daa144a38a9a09b70e13f0c5"},"dob":"1948-02-10 05:08:06","registered":"2002-05-01 03:34:55","phone":"(134)-436-4476","cell":"(713)-998-7271","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/51.jpg","medium":"https://randomuser.me/api/portraits/med/men/51.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/51.jpg"},"nat":"NZ"},{"gender":"female","name":{"title":"ms","first":"lilja","last":"huhta"},"location":{"street":"3047 hermiankatu","city":"tyrnävä","state":"northern ostrobothnia","postcode":50784},"email":"lilja.huhta@example.com","login":{"username":"crazybear498","password":"aberdeen","salt":"baVKpLPD","md5":"7c421a0af04623b1878fa1767e8eb734","sha1":"a41fd9a91534a36505d96e45252366037bed187c","sha256":"bef37f8b2b47efa869a7d16aedea7ecfd3c5b037036817ac75a94c4ed84540d6"},"dob":"1946-09-22 02:06:12","registered":"2003-12-18 06:26:08","phone":"09-173-232","cell":"041-265-00-60","id":{"name":"HETU","value":"846-662N"},"picture":{"large":"https://randomuser.me/api/portraits/women/20.jpg","medium":"https://randomuser.me/api/portraits/med/women/20.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/20.jpg"},"nat":"FI"},{"gender":"female","name":{"title":"mrs","first":"asuncion","last":"martinez"},"location":{"street":"7193 calle de segovia","city":"la palma","state":"cantabria","postcode":15224},"email":"asuncion.martinez@example.com","login":{"username":"bigelephant693","password":"family","salt":"mZbfRlpH","md5":"5d5f790bc86b2d47faf344c59fc4d703","sha1":"2e26b9714c8f06cf0a0a6428553731b23579025f","sha256":"ac0d2af2a8aaced32182cc00d9a27a221f27dd1b12c4543bd9a78b3d12735dc2"},"dob":"1986-07-20 04:12:22","registered":"2008-07-26 12:31:41","phone":"948-772-383","cell":"665-735-742","id":{"name":"DNI","value":"06193994-I"},"picture":{"large":"https://randomuser.me/api/portraits/women/69.jpg","medium":"https://randomuser.me/api/portraits/med/women/69.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/69.jpg"},"nat":"ES"},{"gender":"male","name":{"title":"mr","first":"victor","last":"jørgensen"},"location":{"street":"5418 hestehaven","city":"amager","state":"syddanmark","postcode":77864},"email":"victor.jørgensen@example.com","login":{"username":"brownrabbit780","password":"chip","salt":"PjL9ODIK","md5":"9a794af93930fc81cddb2e9d9856e816","sha1":"522e26a07660dd8e25c884c2b4742635218a9929","sha256":"cc7acd3c8d7430f8f135bdd33c411c43f3fa967ddc906bcecbe970e672864d7b"},"dob":"1966-04-30 04:33:46","registered":"2004-07-22 07:19:30","phone":"55134853","cell":"94480689","id":{"name":"CPR","value":"733782-9404"},"picture":{"large":"https://randomuser.me/api/portraits/men/99.jpg","medium":"https://randomuser.me/api/portraits/med/men/99.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/99.jpg"},"nat":"DK"},{"gender":"male","name":{"title":"mr","first":"jonas","last":"mortensen"},"location":{"street":"2982 kildevangen","city":"viby j.","state":"nordjylland","postcode":95145},"email":"jonas.mortensen@example.com","login":{"username":"silverfrog492","password":"scooby1","salt":"wFvPoDMJ","md5":"602eb2871f2f59a5c0d7d5de73202502","sha1":"a34c173e1a180dcff6a405f6b1d763bdf865ed69","sha256":"7261d864eab0961f509a3f72b2c95f4781ca5c90cd1aa8b12394196f1736c0a4"},"dob":"1955-01-20 16:34:26","registered":"2008-11-17 20:19:58","phone":"45738662","cell":"73852795","id":{"name":"CPR","value":"602839-8625"},"picture":{"large":"https://randomuser.me/api/portraits/men/64.jpg","medium":"https://randomuser.me/api/portraits/med/men/64.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/64.jpg"},"nat":"DK"},{"gender":"male","name":{"title":"mr","first":"mimoso","last":"de souza"},"location":{"street":"8117 rua santo antônio ","city":"cuiabá","state":"tocantins","postcode":92847},"email":"mimoso.desouza@example.com","login":{"username":"yellowpeacock651","password":"smart","salt":"GWujGraX","md5":"f7140e0f030eb582df004e0054c3ea0b","sha1":"cc5d2da0fbe074c5973a2dee8d457cc26d821720","sha256":"9d41e9e57e3800679f744d112c44f4c30b721455dbd2bcca4491f7f01bffe6e6"},"dob":"1967-09-26 20:41:43","registered":"2016-03-08 22:33:19","phone":"(16) 9191-4401","cell":"(47) 0829-3835","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/71.jpg","medium":"https://randomuser.me/api/portraits/med/men/71.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/71.jpg"},"nat":"BR"},{"gender":"female","name":{"title":"mrs","first":"katherine","last":"mcdonalid"},"location":{"street":"6745 park avenue","city":"sheffield","state":"clwyd","postcode":"EP05 3DH"},"email":"katherine.mcdonalid@example.com","login":{"username":"blackfish369","password":"anthony","salt":"ML8ryb1v","md5":"2387d99b7108d0bf278f5279b5d17375","sha1":"21ad6bb435326b6799c7c158f550c16484d67b07","sha256":"f92be6823e2d717f298046e9452dc17dbe8e20044120b0baef49ece572c46fe1"},"dob":"1967-10-26 17:58:07","registered":"2005-04-10 12:42:45","phone":"015394 21641","cell":"0746-938-320","id":{"name":"NINO","value":"OM 80 50 73 W"},"picture":{"large":"https://randomuser.me/api/portraits/women/95.jpg","medium":"https://randomuser.me/api/portraits/med/women/95.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/95.jpg"},"nat":"GB"},{"gender":"female","name":{"title":"mademoiselle","first":"justine","last":"bonnet"},"location":{"street":"1832 rue de l'abbé-soulange-bodin","city":"yens","state":"fribourg","postcode":2751},"email":"justine.bonnet@example.com","login":{"username":"heavyostrich691","password":"646464","salt":"gYdcokig","md5":"d9344fdb81b99ce182208a05df27daa0","sha1":"bfb8b1ad75a178b32e9492360ed04900a29b8e4e","sha256":"649c27c45a453c7a9b1a7f16a39094dcd92c00c746e0fe7a935740ad74bebf1e"},"dob":"1990-05-18 23:03:44","registered":"2006-06-22 15:56:24","phone":"(766)-887-4809","cell":"(987)-621-8391","id":{"name":"AVS","value":"756.ZTKP.SKXF.03"},"picture":{"large":"https://randomuser.me/api/portraits/women/35.jpg","medium":"https://randomuser.me/api/portraits/med/women/35.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/35.jpg"},"nat":"CH"},{"gender":"male","name":{"title":"mr","first":"elias","last":"schmidt"},"location":{"street":"6774 wiesenstraße","city":"goslar","state":"sachsen-anhalt","postcode":26534},"email":"elias.schmidt@example.com","login":{"username":"beautifulcat616","password":"ajax","salt":"Bhvp2ZJX","md5":"9441c9c27243b5200c4ecb155a1b9525","sha1":"6ea38fdf9c843991e4704af450a5e3a1fe9e2113","sha256":"2da6f41ff227d04579e31ed495e50fd62c66b0d6cd443e2d2e6b87a7e00c13dc"},"dob":"1957-08-19 01:07:20","registered":"2012-03-11 21:55:03","phone":"0501-7075359","cell":"0177-3485445","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/14.jpg","medium":"https://randomuser.me/api/portraits/med/men/14.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/14.jpg"},"nat":"DE"},{"gender":"male","name":{"title":"mr","first":"benjamin","last":"kern"},"location":{"street":"8154 mühlenweg","city":"recklinghausen","state":"nordrhein-westfalen","postcode":49465},"email":"benjamin.kern@example.com","login":{"username":"redgoose228","password":"velvet","salt":"LVvRVkCh","md5":"f3524d1e4b2d87a9acbaa3e51e202c12","sha1":"0f37428d6e8e69dcbb4681b93cd41167e144fae5","sha256":"cc794024ce160a853d236d0e1a4fcf4ee472f499509bb962552bab21ec879b70"},"dob":"1953-06-02 12:59:16","registered":"2016-07-21 22:28:10","phone":"0537-8254812","cell":"0176-0485173","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/22.jpg","medium":"https://randomuser.me/api/portraits/med/men/22.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/22.jpg"},"nat":"DE"},{"gender":"female","name":{"title":"ms","first":"rosie","last":"west"},"location":{"street":"1934 the avenue","city":"arklow","state":"south dublin","postcode":70673},"email":"rosie.west@example.com","login":{"username":"purpleostrich764","password":"lespaul","salt":"J1kPgqBQ","md5":"69749f6f0cbb8ab2398262f649d59fa8","sha1":"f0fa2a91a82f21d00b438c98b57b306134405254","sha256":"8f9b89ead2372eda4ce28345a4e39a6ceb4837bebf974bfdbe3e976f9290dc53"},"dob":"1947-03-27 01:51:50","registered":"2014-09-27 19:36:53","phone":"021-611-9408","cell":"081-094-4375","id":{"name":"PPS","value":"4736297T"},"picture":{"large":"https://randomuser.me/api/portraits/women/14.jpg","medium":"https://randomuser.me/api/portraits/med/women/14.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/14.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"miss","first":"wendy","last":"marshall"},"location":{"street":"1110 valley view ln","city":"palm bay","state":"florida","postcode":39273},"email":"wendy.marshall@example.com","login":{"username":"smallswan234","password":"queenie","salt":"slkGUKVl","md5":"53ac462afa1efadd9a6c104e0da8cf96","sha1":"4bf611cb47db8fdcab061709489c7e14f2ea556a","sha256":"438d7116d2ef9dafdf417683e57cea714ad151b84bcff79eac910d3d1d2c706c"},"dob":"1947-01-11 17:45:53","registered":"2003-01-18 00:11:18","phone":"(353)-693-7394","cell":"(393)-816-0375","id":{"name":"SSN","value":"958-22-4766"},"picture":{"large":"https://randomuser.me/api/portraits/women/41.jpg","medium":"https://randomuser.me/api/portraits/med/women/41.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/41.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"terry","last":"hall"},"location":{"street":"2752 mockingbird hill","city":"sydney","state":"western australia","postcode":8987},"email":"terry.hall@example.com","login":{"username":"beautifulpeacock296","password":"bobcat","salt":"KhnVkOEj","md5":"4bb4225f0750ebc2dfbc7a9e7278dca2","sha1":"35b58fac71d15002740dddf576dcfd41da9acb23","sha256":"5ec52e0aa5467b2f18ef35cde9256c46a1840c89db6a7bf95c839839c3559ce4"},"dob":"1961-01-01 20:58:39","registered":"2012-11-19 17:18:35","phone":"00-5169-5202","cell":"0406-174-298","id":{"name":"TFN","value":"671679241"},"picture":{"large":"https://randomuser.me/api/portraits/men/55.jpg","medium":"https://randomuser.me/api/portraits/med/men/55.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/55.jpg"},"nat":"AU"},{"gender":"female","name":{"title":"mrs","first":"kristin","last":"shelton"},"location":{"street":"8937 the crescent","city":"armagh","state":"highlands and islands","postcode":"A67 1ZS"},"email":"kristin.shelton@example.com","login":{"username":"blackcat607","password":"ghetto","salt":"TpT3KJna","md5":"1a389e7b357ecc48f718ec8da90704d7","sha1":"edc766b41d4072258d2a357e8b2aff4157b3d543","sha256":"fd1f31a1a3b062c1c8f4d50c7a4ab02d3e191efff8424bd402931e0a129c4be1"},"dob":"1986-09-09 06:29:35","registered":"2012-08-07 12:27:37","phone":"016973 93680","cell":"0710-786-524","id":{"name":"NINO","value":"WJ 46 67 96 B"},"picture":{"large":"https://randomuser.me/api/portraits/women/6.jpg","medium":"https://randomuser.me/api/portraits/med/women/6.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/6.jpg"},"nat":"GB"},{"gender":"male","name":{"title":"mr","first":"leevi","last":"ylitalo"},"location":{"street":"3056 mechelininkatu","city":"lumparland","state":"tavastia proper","postcode":44091},"email":"leevi.ylitalo@example.com","login":{"username":"ticklishgoose697","password":"viagra","salt":"tAvcWUmC","md5":"517ed534211ec311760de5039e5d0d92","sha1":"ec17ca5e1224c9ab0f96a0b793b5969834882303","sha256":"f289febcf95786515206f237961c8c2035ed3dbe96160b49da8fedd5bff8b607"},"dob":"1952-01-24 11:47:27","registered":"2004-06-10 18:40:16","phone":"09-587-367","cell":"045-744-73-48","id":{"name":"HETU","value":"452-275H"},"picture":{"large":"https://randomuser.me/api/portraits/men/69.jpg","medium":"https://randomuser.me/api/portraits/med/men/69.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/69.jpg"},"nat":"FI"},{"gender":"female","name":{"title":"madame","first":"hanaé","last":"pierre"},"location":{"street":"6557 rue dumenge","city":"crissier","state":"st. gallen","postcode":1907},"email":"hanaé.pierre@example.com","login":{"username":"ticklishfrog812","password":"teddy","salt":"1Wlb5h3M","md5":"129e74aa675fe702a78ab1fc71c46134","sha1":"a9b2a72765e96d5da6d366fd439c275e1f7701c8","sha256":"bd57f07a416dd6b889f03903bb60168228333a1c1eb3c62884fd33fb964f7917"},"dob":"1964-07-31 23:27:32","registered":"2007-11-18 16:57:58","phone":"(291)-720-0838","cell":"(324)-270-1772","id":{"name":"AVS","value":"756.WOKS.PECK.78"},"picture":{"large":"https://randomuser.me/api/portraits/women/95.jpg","medium":"https://randomuser.me/api/portraits/med/women/95.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/95.jpg"},"nat":"CH"},{"gender":"male","name":{"title":"mr","first":"batuhan","last":"van den brandt"},"location":{"street":"7229 mariaplaats","city":"aalsmeer","state":"groningen","postcode":62332},"email":"batuhan.vandenbrandt@example.com","login":{"username":"smallsnake822","password":"billbill","salt":"CNvQSpJI","md5":"eb6e6d3de7f9ac341114a42b86b41b00","sha1":"ac8954ae4d9f426ae8f8c1eab40157c456f561d7","sha256":"d588ce42e4c4767583f6445609a128ececf6b75dd50a6e49f8c3173e03ff4535"},"dob":"1965-10-26 00:23:23","registered":"2006-01-25 17:43:32","phone":"(430)-326-2377","cell":"(831)-522-6816","id":{"name":"BSN","value":"23150234"},"picture":{"large":"https://randomuser.me/api/portraits/men/85.jpg","medium":"https://randomuser.me/api/portraits/med/men/85.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/85.jpg"},"nat":"NL"},{"gender":"female","name":{"title":"ms","first":"astrid","last":"madsen"},"location":{"street":"4325 solsortvej","city":"lintrup","state":"sjælland","postcode":61695},"email":"astrid.madsen@example.com","login":{"username":"organicrabbit217","password":"irene","salt":"QLhWR0ZG","md5":"98070b3cc78363f6fb4d08b5d7a2e1ca","sha1":"5512478d773b767d907b2f5f7db2c1d46988a5ec","sha256":"62352356d70e7fb4b2bd26bd8debe988fd2166685f85a386ce445b2899cd80cf"},"dob":"1947-12-06 18:02:20","registered":"2015-10-03 21:17:56","phone":"00032405","cell":"18906457","id":{"name":"CPR","value":"160107-5422"},"picture":{"large":"https://randomuser.me/api/portraits/women/26.jpg","medium":"https://randomuser.me/api/portraits/med/women/26.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/26.jpg"},"nat":"DK"},{"gender":"female","name":{"title":"mrs","first":"lara","last":"schubert"},"location":{"street":"4898 danziger straße","city":"rottweil","state":"schleswig-holstein","postcode":89675},"email":"lara.schubert@example.com","login":{"username":"blueelephant796","password":"1002","salt":"sk2ZLeGi","md5":"af3c1fb3c9f384ef94d7a01b72f5d298","sha1":"d7fd785e8cc9fe23de4e02d9ef021ec5e788cc73","sha256":"f22c65c713ec154ed6f11b3e15ef2c6d6e580d6e4587788185e7fd2093c0108b"},"dob":"1958-04-11 19:12:54","registered":"2004-02-07 00:40:50","phone":"0697-0043253","cell":"0179-2672033","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/87.jpg","medium":"https://randomuser.me/api/portraits/med/women/87.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/87.jpg"},"nat":"DE"},{"gender":"female","name":{"title":"ms","first":"sofia","last":"olsen"},"location":{"street":"5042 skovtoften","city":"horsens","state":"danmark","postcode":53830},"email":"sofia.olsen@example.com","login":{"username":"silverbutterfly362","password":"colombia","salt":"iJZUjuLj","md5":"155a97d927e4a1ec0acc86192bfd8429","sha1":"1226983b8dc9b4f6f7e06fde8a376dba8c4c0ae7","sha256":"b0cc5209c541c6397d20dcb664e3affeb0c4af751a2decd2d813dbad9eec0550"},"dob":"1955-04-02 13:07:52","registered":"2008-04-01 01:37:58","phone":"96364881","cell":"33858806","id":{"name":"CPR","value":"646119-8288"},"picture":{"large":"https://randomuser.me/api/portraits/women/44.jpg","medium":"https://randomuser.me/api/portraits/med/women/44.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/44.jpg"},"nat":"DK"},{"gender":"female","name":{"title":"miss","first":"addison","last":"turner"},"location":{"street":"3474 theodosia street","city":"hamilton","state":"marlborough","postcode":22998},"email":"addison.turner@example.com","login":{"username":"smalldog585","password":"diamond","salt":"2AYEPuQr","md5":"79bcba1b5fd33b42aeb59e4980a73287","sha1":"48c9beea4c02971feb31054e8dfb9c93cafb1cf9","sha256":"5392bf60e2379889e24b35d833f2ba76c4face4830a73dff8a4653e96b04040a"},"dob":"1985-05-27 23:43:19","registered":"2011-07-11 21:10:53","phone":"(893)-270-0208","cell":"(223)-945-8121","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/59.jpg","medium":"https://randomuser.me/api/portraits/med/women/59.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/59.jpg"},"nat":"NZ"},{"gender":"male","name":{"title":"monsieur","first":"léo","last":"martinez"},"location":{"street":"7002 rue de la mairie","city":"bettens","state":"neuchâtel","postcode":1576},"email":"léo.martinez@example.com","login":{"username":"tinyelephant811","password":"konyor","salt":"ihCQ49Lr","md5":"7a0ae95e4794a01fa3de28e2dedeec97","sha1":"02b38ed20466829c72f59bda539c60b418185dd0","sha256":"ce4cef50ef04a256e0ff2342d0afaf16cb04ba1e07a9ee7b50c17c2817983c75"},"dob":"1982-07-05 14:29:24","registered":"2014-12-02 10:32:45","phone":"(817)-317-4706","cell":"(602)-365-8441","id":{"name":"AVS","value":"756.ONZC.EPRQ.74"},"picture":{"large":"https://randomuser.me/api/portraits/men/18.jpg","medium":"https://randomuser.me/api/portraits/med/men/18.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/18.jpg"},"nat":"CH"},{"gender":"female","name":{"title":"ms","first":"alisa","last":"korpi"},"location":{"street":"2467 mannerheimintie","city":"ypäjä","state":"åland","postcode":95941},"email":"alisa.korpi@example.com","login":{"username":"greengorilla428","password":"paradox","salt":"MXjuohKi","md5":"9be0531c9bee70ad42688db35b334416","sha1":"2180a10424a97f4a8bbde58df357facedf71c09d","sha256":"8ee69696e49c61291f4a8c8696bb9fca150c453bd53a4b65997e4e890e1dd215"},"dob":"1981-03-04 08:28:23","registered":"2008-01-15 00:19:31","phone":"04-466-928","cell":"046-255-57-30","id":{"name":"HETU","value":"581-0341"},"picture":{"large":"https://randomuser.me/api/portraits/women/71.jpg","medium":"https://randomuser.me/api/portraits/med/women/71.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/71.jpg"},"nat":"FI"},{"gender":"female","name":{"title":"ms","first":"ariane","last":"patel"},"location":{"street":"7987 oak st","city":"trenton","state":"saskatchewan","postcode":19639},"email":"ariane.patel@example.com","login":{"username":"organictiger869","password":"airport","salt":"Sl5dYfYQ","md5":"805b47605cd358cb216c9aaffedfa52d","sha1":"6f7e2e71db40396bdfb4da7b145eed84fab9538f","sha256":"33270a0f30219b5070d42e349b09f5fe9efc146571c26e3cd2a8ad40bb8dfc48"},"dob":"1988-01-23 23:09:25","registered":"2009-06-13 20:51:58","phone":"714-920-4938","cell":"905-375-2965","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/88.jpg","medium":"https://randomuser.me/api/portraits/med/women/88.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/88.jpg"},"nat":"CA"},{"gender":"female","name":{"title":"mrs","first":"juliette","last":"gagnon"},"location":{"street":"8894 george st","city":"fauquier","state":"british columbia","postcode":16375},"email":"juliette.gagnon@example.com","login":{"username":"orangecat953","password":"marriage","salt":"K0IDJ9Hq","md5":"7e130c8fa05eeaa7db309faaa4f210e4","sha1":"23be4fffff1330e282e4c37864876a4c09088438","sha256":"6adaa1fd560d6533bac08317afa29ae63f643f65f1b0f1b74f64d9f99f318db1"},"dob":"1962-02-08 07:44:03","registered":"2013-02-06 20:02:54","phone":"744-247-0343","cell":"132-991-6677","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/65.jpg","medium":"https://randomuser.me/api/portraits/med/women/65.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/65.jpg"},"nat":"CA"},{"gender":"male","name":{"title":"mr","first":"antoine","last":"girard"},"location":{"street":"6990 rue louis-garrand","city":"nantes","state":"nord","postcode":75416},"email":"antoine.girard@example.com","login":{"username":"biggorilla916","password":"thumbs","salt":"JMPPTUJJ","md5":"4df2c02cc6169adff1fd09477e1b4bf3","sha1":"73c05cfcbe60a182317df9af80ee76b00980855b","sha256":"960b04bee7187e7707d8669cad1726111ed1887249b02be02eebd97bc5199131"},"dob":"1986-01-24 03:07:51","registered":"2011-10-06 19:16:28","phone":"05-96-76-57-28","cell":"06-45-90-20-86","id":{"name":"INSEE","value":"186064490369 55"},"picture":{"large":"https://randomuser.me/api/portraits/men/70.jpg","medium":"https://randomuser.me/api/portraits/med/men/70.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/70.jpg"},"nat":"FR"},{"gender":"female","name":{"title":"miss","first":"inmaculada","last":"moreno"},"location":{"street":"5674 avenida de américa","city":"albacete","state":"aragón","postcode":65722},"email":"inmaculada.moreno@example.com","login":{"username":"ticklishdog811","password":"nine","salt":"nZ0u5In2","md5":"cba268ac53a96bdafb1d4f2845f465fa","sha1":"d14adc31f92230b3e1ca60cc0bebb173ee95ba5f","sha256":"3b117fa0cd8c47fcad6ef3554e20d2b650e5362ede68fa6f11810af1572876c2"},"dob":"1953-07-27 02:46:12","registered":"2007-02-21 17:49:14","phone":"920-572-590","cell":"674-862-053","id":{"name":"DNI","value":"66147293-A"},"picture":{"large":"https://randomuser.me/api/portraits/women/24.jpg","medium":"https://randomuser.me/api/portraits/med/women/24.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/24.jpg"},"nat":"ES"},{"gender":"female","name":{"title":"mrs","first":"sofie","last":"schulte"},"location":{"street":"7118 schulweg","city":"ludwigslust","state":"schleswig-holstein","postcode":99051},"email":"sofie.schulte@example.com","login":{"username":"redleopard333","password":"zhuang","salt":"bV3ulFfT","md5":"661bceceba9815141dd943d85d80d7f0","sha1":"1d3a5e26a337b29e90387c924917458a87361602","sha256":"282711b768e9187b308d30ef9a9b7ea43e87f81130d3ef4bf8df04412e3ba36b"},"dob":"1976-02-29 12:02:26","registered":"2004-10-22 11:59:55","phone":"0980-2292415","cell":"0175-2637134","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/49.jpg","medium":"https://randomuser.me/api/portraits/med/women/49.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/49.jpg"},"nat":"DE"},{"gender":"female","name":{"title":"miss","first":"esmirna","last":"vieira"},"location":{"street":"7154 beco dos namorados","city":"rio grande","state":"amazonas","postcode":67825},"email":"esmirna.vieira@example.com","login":{"username":"orangekoala599","password":"dudley","salt":"cBgUs01N","md5":"daba02c5a81ceb7f122a510c0ac23ea4","sha1":"33eab81ae1cd93838560d8291ab0451cd2e666b8","sha256":"202b42240fb9b82e5b2b0d1220e4b3aa685c883213a15d3eaa07cd599f4bc4a7"},"dob":"1974-07-29 03:52:06","registered":"2003-11-28 13:41:33","phone":"(65) 8362-9278","cell":"(67) 7771-6868","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/12.jpg","medium":"https://randomuser.me/api/portraits/med/women/12.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/12.jpg"},"nat":"BR"},{"gender":"female","name":{"title":"ms","first":"verena","last":"wiese"},"location":{"street":"4382 mühlweg","city":"schierbrok","state":"baden-württemberg","postcode":15866},"email":"verena.wiese@example.com","login":{"username":"tinyswan682","password":"snoopy","salt":"HzwoDHhG","md5":"d3a9ec43bcc9532ce1f5c2933f3b5b77","sha1":"aa8ae2efdc0e2020bfc201f73276c90c461eb307","sha256":"845b964bf0d84068c1b545847d838ccfa4a5bef2f729d7243fd984b263d5d2a8"},"dob":"1956-01-04 06:40:14","registered":"2015-01-06 19:13:41","phone":"0480-7392547","cell":"0179-7106535","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/10.jpg","medium":"https://randomuser.me/api/portraits/med/women/10.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/10.jpg"},"nat":"DE"},{"gender":"male","name":{"title":"mr","first":"jo","last":"roossien"},"location":{"street":"9505 kanaalstraat","city":"waterland","state":"flevoland","postcode":78902},"email":"jo.roossien@example.com","login":{"username":"goldenrabbit305","password":"nineinch","salt":"v6hRCegc","md5":"c0dc4b1aaf2831b64528eabbb9220e77","sha1":"e7f4bb0da271d1cc92581c36a7e381ff32944508","sha256":"adea58f944ed5f3c833deec56be0dccb12945e768fc5f64808ae74d4f63394f0"},"dob":"1983-06-04 15:43:20","registered":"2002-07-07 16:34:32","phone":"(190)-491-3163","cell":"(475)-903-5579","id":{"name":"BSN","value":"72728147"},"picture":{"large":"https://randomuser.me/api/portraits/men/25.jpg","medium":"https://randomuser.me/api/portraits/med/men/25.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/25.jpg"},"nat":"NL"},{"gender":"male","name":{"title":"mr","first":"lauri","last":"wiitala"},"location":{"street":"8203 tehtaankatu","city":"turku","state":"kymenlaakso","postcode":93177},"email":"lauri.wiitala@example.com","login":{"username":"tinyostrich539","password":"thuglife","salt":"DDqwkZgi","md5":"a430681319d0b01b798dbb606bc6f806","sha1":"dddfc01142d4e3e9b72a805002545601ddfeef8e","sha256":"9583a3951c410846440dc9762af40f61f8aab91a4514679a4eb57adfaaa9bb5b"},"dob":"1993-02-22 17:59:54","registered":"2012-07-25 21:13:43","phone":"08-185-405","cell":"040-570-11-23","id":{"name":"HETU","value":"293-0131"},"picture":{"large":"https://randomuser.me/api/portraits/men/30.jpg","medium":"https://randomuser.me/api/portraits/med/men/30.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/30.jpg"},"nat":"FI"},{"gender":"male","name":{"title":"mr","first":"josef","last":"jackson"},"location":{"street":"1309 boghall road","city":"skerries","state":"galway city","postcode":97900},"email":"josef.jackson@example.com","login":{"username":"goldenostrich488","password":"sparkle","salt":"7n8Vkz8p","md5":"047bd9fa861113fabd3cc486c1d7ee62","sha1":"6e5b2d08a08d3d603e98f06e9459e292239b8618","sha256":"22c10b8be8538864d9089ca342c848b0278424da46a1593caebc808df7beb664"},"dob":"1979-02-28 09:47:54","registered":"2005-08-26 21:32:11","phone":"061-898-5674","cell":"081-865-5288","id":{"name":"PPS","value":"4918254T"},"picture":{"large":"https://randomuser.me/api/portraits/men/46.jpg","medium":"https://randomuser.me/api/portraits/med/men/46.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/46.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"miss","first":"alicia","last":"matthews"},"location":{"street":"5853 e sandy lake rd","city":"busselton","state":"australian capital territory","postcode":7839},"email":"alicia.matthews@example.com","login":{"username":"orangefish813","password":"sixty9","salt":"NY5tgIVB","md5":"8e3787ea4f4e1e1da93529f2ae839aa0","sha1":"114cb0ba43ab6628161c31b61eb30af2f75ef1bf","sha256":"aa4f0551074b4df2202907592098dadcd5a35cce9f7a4a2616e78186e534e4a5"},"dob":"1983-05-02 15:57:11","registered":"2010-02-21 04:26:00","phone":"05-4545-1542","cell":"0464-607-508","id":{"name":"TFN","value":"002732634"},"picture":{"large":"https://randomuser.me/api/portraits/women/45.jpg","medium":"https://randomuser.me/api/portraits/med/women/45.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/45.jpg"},"nat":"AU"},{"gender":"male","name":{"title":"mr","first":"rodney","last":"hopkins"},"location":{"street":"2172 novara avenue","city":"ennis","state":"clare","postcode":12795},"email":"rodney.hopkins@example.com","login":{"username":"organicgoose861","password":"girl","salt":"nQ66TTKu","md5":"3539bccd6aa19a431da013cf794d229e","sha1":"417f6164f32136dcf5d80ef43420399cfcec576f","sha256":"81bee6f0a21ea2b5c6acbddf1ea777cf1c111223e14f19eaf16b3c15f3191f09"},"dob":"1971-11-03 18:36:50","registered":"2007-02-21 16:26:10","phone":"011-629-1710","cell":"081-087-8163","id":{"name":"PPS","value":"5742195T"},"picture":{"large":"https://randomuser.me/api/portraits/men/98.jpg","medium":"https://randomuser.me/api/portraits/med/men/98.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/98.jpg"},"nat":"IE"},{"gender":"male","name":{"title":"mr","first":"arnaud","last":"harris"},"location":{"street":"4864 balmoral st","city":"borden","state":"nunavut","postcode":66722},"email":"arnaud.harris@example.com","login":{"username":"blackgoose740","password":"dragon1","salt":"P3NqDSbK","md5":"bcadee131d6f74221a5165b3abd05a33","sha1":"8dea108163fa122dc7bfb403b6888c599b8da0fc","sha256":"ec02e1fdcc07ee4dcb34e3255ab2fbeaf6a66da4f8b3f3a2594e6a5a452bf63a"},"dob":"1962-07-05 21:39:16","registered":"2006-03-06 16:00:43","phone":"023-886-9973","cell":"361-077-2402","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/20.jpg","medium":"https://randomuser.me/api/portraits/med/men/20.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/20.jpg"},"nat":"CA"},{"gender":"female","name":{"title":"madame","first":"lena","last":"martinez"},"location":{"street":"4054 rue bony","city":"froideville","state":"aargau","postcode":4969},"email":"lena.martinez@example.com","login":{"username":"smallpanda713","password":"thanks","salt":"QXRdfgzz","md5":"da0e961f2fa7e32fee58eaf987b16462","sha1":"7d57a878e650c48eae94b90e4ae021cb6574b257","sha256":"501e0de5b4cc2734279f1f90830debc5395d38ba656fd2a594c034005064a3b7"},"dob":"1956-08-20 19:20:43","registered":"2014-04-15 15:14:56","phone":"(826)-824-9581","cell":"(122)-545-9317","id":{"name":"AVS","value":"756.KSUB.XWLK.18"},"picture":{"large":"https://randomuser.me/api/portraits/women/55.jpg","medium":"https://randomuser.me/api/portraits/med/women/55.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/55.jpg"},"nat":"CH"},{"gender":"male","name":{"title":"mr","first":"ryan","last":"jones"},"location":{"street":"1124 balmoral st","city":"elgin","state":"newfoundland and labrador","postcode":50641},"email":"ryan.jones@example.com","login":{"username":"smallbear672","password":"charger","salt":"eiRoFuKN","md5":"4009224d52707f6702e387a62c2b1dd2","sha1":"4760dbae60bc6ca7a86538fb0df357e93edaffb7","sha256":"06c56afa38d9c8cd4c9ef1d57266a1a2d3d99ec0223a2a88d4f75508f737fb9a"},"dob":"1953-07-03 01:22:55","registered":"2010-10-31 09:12:04","phone":"509-223-9264","cell":"819-870-7269","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/90.jpg","medium":"https://randomuser.me/api/portraits/med/men/90.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/90.jpg"},"nat":"CA"},{"gender":"female","name":{"title":"miss","first":"afet","last":"tekand"},"location":{"street":"9136 vatan cd","city":"kırıkkale","state":"gaziantep","postcode":84981},"email":"afet.tekand@example.com","login":{"username":"tinylion127","password":"godfather","salt":"t44by7fe","md5":"86999583dc2e3b0f65997976e5eb1ced","sha1":"365bf1d76f22e76a6c81e104c7a3971f077ea61e","sha256":"783c0b0c786ac048ffca9f7c26a02277271ef6503a59ffab3abf6971a953055f"},"dob":"1948-10-22 08:24:34","registered":"2002-06-11 12:49:00","phone":"(252)-259-9328","cell":"(090)-584-5232","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/94.jpg","medium":"https://randomuser.me/api/portraits/med/women/94.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/94.jpg"},"nat":"TR"},{"gender":"male","name":{"title":"mr","first":"louis","last":"king"},"location":{"street":"7803 dickens street","city":"whanganui","state":"hawke's bay","postcode":71846},"email":"louis.king@example.com","login":{"username":"silvergoose653","password":"superstar","salt":"cvdtK5wl","md5":"953519388f09bb6920b9f1e0cec08a00","sha1":"10436f3dd690af18da1bbc0c4b05623de6346186","sha256":"701a837401f0e18d73084f50b8890e09e572a897799e07bacae646923eb2d8b9"},"dob":"1947-02-10 22:09:28","registered":"2003-06-21 14:49:28","phone":"(934)-375-9269","cell":"(614)-685-5175","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/47.jpg","medium":"https://randomuser.me/api/portraits/med/men/47.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/47.jpg"},"nat":"NZ"},{"gender":"male","name":{"title":"mr","first":"eli","last":"dean"},"location":{"street":"8421 park lane","city":"portsmouth","state":"northamptonshire","postcode":"V76 2UL"},"email":"eli.dean@example.com","login":{"username":"redgorilla496","password":"picturs","salt":"mzpzuhdf","md5":"d18cc297e0739c8726ca0c56e6229ee3","sha1":"1648c9b26a204dd5b80fd0f00237333fe69e2f86","sha256":"d03d768f30bafd26e1dd4e83376742302a6a8dc5d5a3724df5c26f62958d0110"},"dob":"1952-09-21 21:42:13","registered":"2011-03-02 14:57:36","phone":"015242 52174","cell":"0700-079-069","id":{"name":"NINO","value":"BK 26 60 37 D"},"picture":{"large":"https://randomuser.me/api/portraits/men/11.jpg","medium":"https://randomuser.me/api/portraits/med/men/11.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/11.jpg"},"nat":"GB"},{"gender":"female","name":{"title":"miss","first":"paige","last":"james"},"location":{"street":"6418 dame street","city":"portarlington","state":"waterford","postcode":11388},"email":"paige.james@example.com","login":{"username":"heavyladybug581","password":"landon","salt":"h2Omr94C","md5":"7630cd355f031ad86b0a3ea4f09756a6","sha1":"f311767cce53f3179dbd0d5a9b053c4cadeb5c14","sha256":"35d5ce8bd59e0bed067fb0fd4d8fca5ca26e07fef0cf9a4707c52cf9f7596f69"},"dob":"1945-05-25 00:54:36","registered":"2013-10-18 13:47:04","phone":"041-058-5391","cell":"081-193-2013","id":{"name":"PPS","value":"5418120T"},"picture":{"large":"https://randomuser.me/api/portraits/women/81.jpg","medium":"https://randomuser.me/api/portraits/med/women/81.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/81.jpg"},"nat":"IE"},{"gender":"male","name":{"title":"mr","first":"kent","last":"wade"},"location":{"street":"9048 adams st","city":"high point","state":"new jersey","postcode":28737},"email":"kent.wade@example.com","login":{"username":"organicmeercat110","password":"deacon","salt":"SMrCEmaW","md5":"f07e2d3c7e57471fb56940e951232475","sha1":"f7f1c4ab4cbc018c74ed7cc6e778fd9f6583624d","sha256":"4b59e10fc50663c3dc9ccaffa7a46e7165195244d72522df204c1747c702572b"},"dob":"1976-08-22 08:18:17","registered":"2012-05-25 09:49:30","phone":"(832)-981-6012","cell":"(190)-583-1860","id":{"name":"SSN","value":"345-82-7993"},"picture":{"large":"https://randomuser.me/api/portraits/men/92.jpg","medium":"https://randomuser.me/api/portraits/med/men/92.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/92.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"mille","last":"pedersen"},"location":{"street":"6482 jeppe aakjærs vej","city":"ryslinge","state":"midtjylland","postcode":10153},"email":"mille.pedersen@example.com","login":{"username":"bigbear289","password":"salem","salt":"KGAd5L7Y","md5":"dd81a607e4e1de80b933997844948253","sha1":"b54ed08a43ea325ac353cf1d21efae47cb5255bd","sha256":"ea8c68cae6de897e29ed62a67161736a9c17811559b43dcea416235ba23df6fb"},"dob":"1954-12-24 07:40:39","registered":"2002-10-09 23:22:51","phone":"67272898","cell":"90278665","id":{"name":"CPR","value":"191062-7288"},"picture":{"large":"https://randomuser.me/api/portraits/men/55.jpg","medium":"https://randomuser.me/api/portraits/med/men/55.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/55.jpg"},"nat":"DK"},{"gender":"male","name":{"title":"mr","first":"tijl","last":"uil"},"location":{"street":"7527 wijde begijnestraat","city":"hillegom","state":"drenthe","postcode":26966},"email":"tijl.uil@example.com","login":{"username":"ticklishwolf242","password":"march","salt":"vs2yMMZW","md5":"d2e986099f2c3f0f3be287ae6beb350d","sha1":"7cd6a7f16867b9f5e95b8e0a55463244c680ab15","sha256":"031b2a5b0e1208cef91fd1040082b26ccdc4a87d4b1ba98b47cefa9542e91470"},"dob":"1977-01-01 05:50:16","registered":"2015-07-31 12:09:52","phone":"(690)-568-2595","cell":"(188)-036-9621","id":{"name":"BSN","value":"19587095"},"picture":{"large":"https://randomuser.me/api/portraits/men/81.jpg","medium":"https://randomuser.me/api/portraits/med/men/81.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/81.jpg"},"nat":"NL"},{"gender":"female","name":{"title":"miss","first":"silje","last":"andersen"},"location":{"street":"4282 langgade","city":"lundby","state":"sjælland","postcode":46079},"email":"silje.andersen@example.com","login":{"username":"purplewolf802","password":"cold","salt":"PFDY7wc7","md5":"aab241b30fa9d4c4d4757ed5d6fcdbda","sha1":"162257dd4226224297c10db8aa279b3b2a234af8","sha256":"03596b5491a565ba4c22d12853eeae87b868bb28c9ed0c42827ffcc7f704ce79"},"dob":"1946-07-17 11:20:54","registered":"2013-12-24 08:29:21","phone":"76180624","cell":"92947829","id":{"name":"CPR","value":"596904-3103"},"picture":{"large":"https://randomuser.me/api/portraits/women/50.jpg","medium":"https://randomuser.me/api/portraits/med/women/50.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/50.jpg"},"nat":"DK"},{"gender":"male","name":{"title":"mr","first":"نيما","last":"کریمی"},"location":{"street":"6218 دیباجی","city":"اهواز","state":"خراسان جنوبی","postcode":96245},"email":"نيما.کریمی@example.com","login":{"username":"orangeelephant221","password":"callisto","salt":"Vv1EDbdy","md5":"9ff26188a5f87dfb2b9c024077390d69","sha1":"8ec05b5409b537f0334a9493acb56bd934b28ea8","sha256":"4e90384a393522c7ead6d2a4afd446f7d27867242ccba33ae81d8b608c965168"},"dob":"1973-09-13 12:09:40","registered":"2012-09-14 06:11:24","phone":"043-06219106","cell":"0964-418-6945","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/13.jpg","medium":"https://randomuser.me/api/portraits/med/men/13.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/13.jpg"},"nat":"IR"},{"gender":"male","name":{"title":"mr","first":"quévin","last":"novaes"},"location":{"street":"5543 rua são luiz ","city":"eunápolis","state":"rio grande do norte","postcode":52389},"email":"quévin.novaes@example.com","login":{"username":"smallbutterfly929","password":"johnny","salt":"IWf5eTsQ","md5":"8cd8a38d5b77d37678ee938b9c560cfa","sha1":"248def1d8de114efcaa18c96780496f71b94b33e","sha256":"778246e9f3b11a840e2103fa8c4a22289a966a7d182a36e8026ee61b91cae49f"},"dob":"1959-05-03 10:12:58","registered":"2002-07-31 03:39:09","phone":"(76) 3772-4853","cell":"(30) 5657-3583","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/53.jpg","medium":"https://randomuser.me/api/portraits/med/men/53.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/53.jpg"},"nat":"BR"},{"gender":"male","name":{"title":"mr","first":"vílmar","last":"de souza"},"location":{"street":"9543 rua dom pedro ii ","city":"arapiraca","state":"sergipe","postcode":15594},"email":"vílmar.desouza@example.com","login":{"username":"silvergorilla225","password":"bigboobs","salt":"O4HjK5uB","md5":"f82f869962c2227a4f8c0b25475a6adf","sha1":"5dfb831d86afedb7e844dd53f896493ea6e6ac75","sha256":"8066cf535fdae89f4a88929dfaeab1d5347a9470fb9baf6d37aefef7e3868626"},"dob":"1962-09-23 02:34:45","registered":"2006-07-24 07:49:20","phone":"(06) 8840-4188","cell":"(74) 5506-5129","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/11.jpg","medium":"https://randomuser.me/api/portraits/med/men/11.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/11.jpg"},"nat":"BR"}],"info":{"seed":"a79941f1b459a00a","results":125,"page":1,"version":"1.1"}} diff --git a/dev-resources/json/json10b.json b/dev-resources/json/json10b.json new file mode 100644 index 00000000..33ab937f --- /dev/null +++ b/dev-resources/json/json10b.json @@ -0,0 +1 @@ +{"imu":42} \ No newline at end of file diff --git a/dev-resources/json/json10k.json b/dev-resources/json/json10k.json new file mode 100644 index 00000000..9f50a417 --- /dev/null +++ b/dev-resources/json/json10k.json @@ -0,0 +1 @@ +{"results":[{"gender":"male","name":{"title":"mr","first":"علی رضا","last":"محمدخان"},"location":{"street":"4326 پارک دانشجو","city":"آبادان","state":"خوزستان","postcode":36902},"email":"علی رضا.محمدخان@example.com","login":{"username":"lazypeacock819","password":"taxman","salt":"peX2qakA","md5":"0c39ef1320ec7f799065f3b3385a2f4e","sha1":"cd51cda2b75943b111707094d8a5652542d2dff0","sha256":"a1f97d14b6a878b963482de8d6aa789f5baaf9872e510031028b213241787a73"},"dob":"1953-04-25 02:27:20","registered":"2004-10-03 21:41:05","phone":"050-46102037","cell":"0990-753-1209","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/24.jpg","medium":"https://randomuser.me/api/portraits/med/men/24.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/24.jpg"},"nat":"IR"},{"gender":"female","name":{"title":"ms","first":"andrea","last":"peña"},"location":{"street":"7112 calle de la almudena","city":"la palma","state":"islas baleares","postcode":63878},"email":"andrea.peña@example.com","login":{"username":"purpleleopard218","password":"harvard","salt":"hc9Uu10H","md5":"0d1c50b840053c61f68eb11b9ff5c44b","sha1":"5bd624f5e4567f6340cb00a07d6d9cdb2046b219","sha256":"839fee4ad0d19068b4dab72546bed62fe48ae69456e4b1b383125484510950b7"},"dob":"1953-01-27 09:21:17","registered":"2005-07-01 21:44:40","phone":"986-752-877","cell":"623-685-112","id":{"name":"DNI","value":"93357290-Y"},"picture":{"large":"https://randomuser.me/api/portraits/women/81.jpg","medium":"https://randomuser.me/api/portraits/med/women/81.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/81.jpg"},"nat":"ES"},{"gender":"female","name":{"title":"miss","first":"sue","last":"romero"},"location":{"street":"247 white oak dr","city":"mackay","state":"new south wales","postcode":1327},"email":"sue.romero@example.com","login":{"username":"orangefish402","password":"llll","salt":"AjO4nICn","md5":"19521ff63dc4e49e85c5a80ed219231c","sha1":"dde550b31afc7ff7d852e4b3252e1fa5070e00e3","sha256":"d7b83280c4eb3b095295af9b7ef51b306fc3c7df3843c26bfec320da42bbf16f"},"dob":"1952-01-13 15:26:37","registered":"2014-04-04 13:07:34","phone":"01-5269-1704","cell":"0492-962-203","id":{"name":"TFN","value":"599157736"},"picture":{"large":"https://randomuser.me/api/portraits/women/13.jpg","medium":"https://randomuser.me/api/portraits/med/women/13.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/13.jpg"},"nat":"AU"},{"gender":"female","name":{"title":"mrs","first":"donna","last":"murphy"},"location":{"street":"8988 north road","city":"greystones","state":"kilkenny","postcode":53668},"email":"donna.murphy@example.com","login":{"username":"silverkoala656","password":"33333333","salt":"wWUk5zn2","md5":"9172751676aa17561fdd3174dd4c9326","sha1":"5c073d90d70e6e72c70e8c08dde95734cdad840e","sha256":"6fe569f123ad796a7ff0649f542a2333ccacd92bd70ca6d52d64cd317cdd0a33"},"dob":"1969-09-12 21:14:56","registered":"2012-06-10 23:04:02","phone":"061-625-5539","cell":"081-759-2651","id":{"name":"PPS","value":"7736182T"},"picture":{"large":"https://randomuser.me/api/portraits/women/68.jpg","medium":"https://randomuser.me/api/portraits/med/women/68.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/68.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"mademoiselle","first":"marion","last":"faure"},"location":{"street":"4623 rue de l'abbé-roger-derry","city":"gollion","state":"bern","postcode":1333},"email":"marion.faure@example.com","login":{"username":"yellowbear160","password":"747474","salt":"ZIx9zcNs","md5":"15969c42e7eaf5f2ce0492b86a165393","sha1":"7c578c86f87b28a0f396a0f14d1ce3a870b31d16","sha256":"fe1bc95f4fdbb789c80d5912c576074e03fa3ab509a6de3e6fe9ad256d67233d"},"dob":"1946-02-10 21:20:20","registered":"2005-03-07 01:57:56","phone":"(805)-136-2619","cell":"(066)-198-2825","id":{"name":"AVS","value":"756.TAAE.FXMI.39"},"picture":{"large":"https://randomuser.me/api/portraits/women/20.jpg","medium":"https://randomuser.me/api/portraits/med/women/20.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/20.jpg"},"nat":"CH"},{"gender":"female","name":{"title":"ms","first":"carmen","last":"ellis"},"location":{"street":"90 bruce st","city":"hobart","state":"south australia","postcode":7153},"email":"carmen.ellis@example.com","login":{"username":"smallrabbit833","password":"berkeley","salt":"wWW0PXS7","md5":"16cdf0978f51bcede9fe63fbf52c7744","sha1":"99bf5b7219f65c2f19a6e1b7bfe9642a8c6465a4","sha256":"d96f60965aedf1f82f2b59b1789e32230bd26495a1b7257df8efc1e92bcf537d"},"dob":"1960-12-15 09:15:17","registered":"2007-06-30 17:58:06","phone":"02-5809-6469","cell":"0428-863-957","id":{"name":"TFN","value":"346283503"},"picture":{"large":"https://randomuser.me/api/portraits/women/85.jpg","medium":"https://randomuser.me/api/portraits/med/women/85.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/85.jpg"},"nat":"AU"},{"gender":"female","name":{"title":"miss","first":"emma","last":"gregory"},"location":{"street":"8541 mill road","city":"birmingham","state":"berkshire","postcode":"T3E 2XL"},"email":"emma.gregory@example.com","login":{"username":"goldenrabbit210","password":"cameron1","salt":"UvELNRRe","md5":"0db2f9fd269b3c43d3b906f46ebf5d78","sha1":"4881220c87d85434553f31be9d79893a1f8e35fa","sha256":"a6349fffe4c01b245d2d7107059dac008711174fd88201c908736dedc3b6448e"},"dob":"1947-05-04 06:23:14","registered":"2015-03-16 01:40:15","phone":"016977 97466","cell":"0795-686-594","id":{"name":"NINO","value":"PL 94 41 63 V"},"picture":{"large":"https://randomuser.me/api/portraits/women/82.jpg","medium":"https://randomuser.me/api/portraits/med/women/82.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/82.jpg"},"nat":"GB"},{"gender":"female","name":{"title":"miss","first":"debbie","last":"gilbert"},"location":{"street":"7338 grange road","city":"letterkenny","state":"tipperary","postcode":52466},"email":"debbie.gilbert@example.com","login":{"username":"heavygoose267","password":"coventry","salt":"NS7ZrqkE","md5":"775729a0cf119f1c32fdab5bf93e1927","sha1":"15052613cdce515dc8e1fccaa0c9f9a584e48faa","sha256":"4cb3c00151faf26ed85e9ba61f22376973e755f5219633b0247a69e7ef22bc01"},"dob":"1987-02-05 19:15:58","registered":"2005-10-14 13:25:45","phone":"031-061-6514","cell":"081-331-8027","id":{"name":"PPS","value":"9152780T"},"picture":{"large":"https://randomuser.me/api/portraits/women/69.jpg","medium":"https://randomuser.me/api/portraits/med/women/69.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/69.jpg"},"nat":"IE"},{"gender":"female","name":{"title":"ms","first":"charlene","last":"miller"},"location":{"street":"2718 oak lawn ave","city":"chesapeake","state":"rhode island","postcode":16733},"email":"charlene.miller@example.com","login":{"username":"bluetiger146","password":"older","salt":"tCyeeeyO","md5":"d567deed2bd685e872c7672844d416cc","sha1":"35dd6ce7ab488a5b1a4eed2d136860c8a0e1d5dd","sha256":"c5eb257b13d5bef4ba16cd7fd7189c1c7d0e09967a44d80ebc14e12e9aa73d10"},"dob":"1982-02-22 18:45:05","registered":"2010-06-04 18:47:51","phone":"(048)-109-3917","cell":"(867)-929-6436","id":{"name":"SSN","value":"172-89-2931"},"picture":{"large":"https://randomuser.me/api/portraits/women/93.jpg","medium":"https://randomuser.me/api/portraits/med/women/93.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/93.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"آرمین","last":"نكو نظر"},"location":{"street":"5745 میرزای شیرازی","city":"ساری","state":"سمنان","postcode":68243},"email":"آرمین.نكونظر@example.com","login":{"username":"heavymouse181","password":"daewoo","salt":"lAREYXd7","md5":"0cfffb14d991d31eeb27dc04734c2595","sha1":"65a84f96764d5abf58ffcc0df42ec8632a51cb05","sha256":"adad007af1894f671f58d841321a8db8ca4cd44073c3d1d1f443bf737b49da94"},"dob":"1981-12-12 14:53:24","registered":"2007-04-02 21:59:32","phone":"089-20174880","cell":"0999-186-4226","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/men/90.jpg","medium":"https://randomuser.me/api/portraits/med/men/90.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/90.jpg"},"nat":"IR"},{"gender":"female","name":{"title":"miss","first":"sheila","last":"dean"},"location":{"street":"8647 robinson rd","city":"grants pass","state":"nevada","postcode":48562},"email":"sheila.dean@example.com","login":{"username":"smallelephant691","password":"qian","salt":"M7a9TwKA","md5":"0814e040674d1081eb2f690a1b0d4ef3","sha1":"47dbb30166d7af1c35eb5ad45106bd328b5f095e","sha256":"5c687ab2e9a13108c280467f4ef20c092a49d9b5be722c586e9a40db708e1bf9"},"dob":"1991-07-13 13:12:06","registered":"2008-11-27 02:19:50","phone":"(877)-584-7016","cell":"(981)-462-9845","id":{"name":"SSN","value":"295-99-5901"},"picture":{"large":"https://randomuser.me/api/portraits/women/24.jpg","medium":"https://randomuser.me/api/portraits/med/women/24.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/24.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"olivia","last":"hein"},"location":{"street":"9022 mühlenweg","city":"holzminden","state":"thüringen","postcode":65296},"email":"olivia.hein@example.com","login":{"username":"orangeleopard758","password":"excite","salt":"QdkX2c25","md5":"68052177fb719d2e57a52da40318e2fe","sha1":"cb00df46d06887e0732b3ff94bba37ed33413a64","sha256":"89147b5a4ee19723cc367fc2b7f0a4a482ce692076111bd48212b88a6d74873a"},"dob":"1988-05-02 15:15:45","registered":"2010-01-24 00:08:23","phone":"0601-9202186","cell":"0179-7462091","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/26.jpg","medium":"https://randomuser.me/api/portraits/med/women/26.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/26.jpg"},"nat":"DE"},{"gender":"male","name":{"title":"mr","first":"mathias","last":"johansen"},"location":{"street":"2875 gyvelvej","city":"askeby","state":"midtjylland","postcode":88770},"email":"mathias.johansen@example.com","login":{"username":"bigmeercat405","password":"hughes","salt":"tRVWblrQ","md5":"69220f7f2fda0a922024babf5c71f548","sha1":"64264d1f3703fdb529e4d7e2a2ce4c7bfe5e4ea6","sha256":"ad73321a24ddf3c9cc9b23e056c97e50b006cfde75c8a1f1fbb3d06e5ab04b82"},"dob":"1957-04-07 17:58:27","registered":"2003-05-10 09:57:39","phone":"13309317","cell":"70639222","id":{"name":"CPR","value":"197517-4938"},"picture":{"large":"https://randomuser.me/api/portraits/men/35.jpg","medium":"https://randomuser.me/api/portraits/med/men/35.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/35.jpg"},"nat":"DK"}],"info":{"seed":"b13cc7728ab0cf73","results":13,"page":1,"version":"1.1"}} diff --git a/dev-resources/json/json1k.json b/dev-resources/json/json1k.json new file mode 100644 index 00000000..04389e61 --- /dev/null +++ b/dev-resources/json/json1k.json @@ -0,0 +1 @@ +{"results":[{"gender":"male","name":{"title":"mr","first":"morris","last":"lambert"},"location":{"street":"7239 hillcrest rd","city":"nowra","state":"australian capital territory","postcode":7541},"email":"morris.lambert@example.com","login":{"username":"smallbird414","password":"carole","salt":"yO9OBSsk","md5":"658323a603522238fb32a86b82eafd55","sha1":"289f6e9a8ccd42b539e0c43283e788aeb8cd0f6e","sha256":"57bca99b2b4e78aa2171eda4db3f35e7631ca3b30f157bdc7ea089a855c66668"},"dob":"1950-07-13 09:18:34","registered":"2012-04-07 00:05:32","phone":"08-2274-7839","cell":"0452-558-702","id":{"name":"TFN","value":"740213762"},"picture":{"large":"https://randomuser.me/api/portraits/men/95.jpg","medium":"https://randomuser.me/api/portraits/med/men/95.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/95.jpg"},"nat":"AU"}],"info":{"seed":"fb0c2b3c7cedc7af","results":1,"page":1,"version":"1.1"}} diff --git a/doc/README.md b/doc/README.md index b52bc1f6..d2c35d89 100644 --- a/doc/README.md +++ b/doc/README.md @@ -7,21 +7,31 @@ * First-class [route data](./basics/route_data.md) * Bi-directional routing * [Pluggable coercion](./coercion/coercion.md) ([schema](https://github.com/plumatic/schema) & [clojure.spec](https://clojure.org/about/spec)) +* Helpers for [ring](./ring/ring.html) & [the browser](./frontend/basics.html) * Extendable * Modular * [Fast](performance.md) Modules: +* `reitit` - all bundled * `reitit-core` - the routing core -* [`reitit-ring`](ring/ring.md) with [data-driven middleware](https://metosin.github.io/reitit/ring/data_driven_middleware.html) +* `reitit-ring` - a [ring router](./ring/ring.md) +* `reitit-middleware` - [common middleware](./ring/default_middleware.md) for `reitit-ring` * `reitit-spec` [clojure.spec](https://clojure.org/about/spec) coercion * `reitit-schema` [Schema](https://github.com/plumatic/schema) coercion * `reitit-swagger` [Swagger2](https://swagger.io/) apidocs * `reitit-swagger-ui` Integrated [Swagger UI](https://github.com/swagger-api/swagger-ui). * [`reitit-frontend`](frontend/basics.md) Tools for frontend routing. -To use Reitit, add the following dependency to your project: +Bubblin' under: + +* `reitit-http` http-routing with Pedestal-style Interceptors (WIP) +* `reitit-sieppari` support for [Sieppari](https://github.com/metosin/sieppari) Interceptors (WIP) + +## Latest version + +All bundled: ```clj [metosin/reitit "0.2.0-SNAPSHOT"] @@ -31,15 +41,28 @@ Optionally, the parts can be required separately: ```clj [metosin/reitit-core "0.2.0-SNAPSHOT"] -[metosin/reitit-ring "0.2.0-SNAPSHOT"] + +;; coercion [metosin/reitit-spec "0.2.0-SNAPSHOT"] [metosin/reitit-schema "0.2.0-SNAPSHOT"] + +;; ring helpers +[metosin/reitit-ring "0.2.0-SNAPSHOT"] +[metosin/reitit-middleware "0.2.0-SNAPSHOT"] + +;; swagger-support for ring & http [metosin/reitit-swagger "0.2.0-SNAPSHOT"] [metosin/reitit-swagger-ui "0.2.0-SNAPSHOT"] -[metosin/frontend "0.1.4-SNAPSHOT"] + +;; frontend helpers (alpha) +[metosin/reitit-frontend "0.2.0-SNAPSHOT"] + +;; http with interceptors (alpha) +[metosin/reitit-http "0.2.0-SNAPSHOT"] +[metosin/reitit-sieppari "0.2.0-SNAPSHOT"] ``` -For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/). +There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians Slack](http://clojurians.net/) for discussion & help. # Examples diff --git a/examples/http/.gitignore b/examples/http/.gitignore new file mode 100644 index 00000000..c53038ec --- /dev/null +++ b/examples/http/.gitignore @@ -0,0 +1,11 @@ +/target +/classes +/checkouts +pom.xml +pom.xml.asc +*.jar +*.class +/.lein-* +/.nrepl-port +.hgignore +.hg/ diff --git a/examples/http/README.md b/examples/http/README.md new file mode 100644 index 00000000..3fe225c4 --- /dev/null +++ b/examples/http/README.md @@ -0,0 +1,14 @@ +# Http with Swagger example + +## Usage + +```clj +> lein repl +(start) +``` + +Go with browser to http://localhost:3000 + +## License + +Copyright © 2018 Metosin Oy diff --git a/examples/http/project.clj b/examples/http/project.clj new file mode 100644 index 00000000..60f6406d --- /dev/null +++ b/examples/http/project.clj @@ -0,0 +1,6 @@ +(defproject ring-example "0.1.0-SNAPSHOT" + :description "Reitit Ring App with Swagger" + :dependencies [[org.clojure/clojure "1.9.0"] + [ring "1.6.3"] + [metosin/reitit "0.2.0-SNAPSHOT"]] + :repl-options {:init-ns example.server}) diff --git a/examples/http/src/example/server.clj b/examples/http/src/example/server.clj new file mode 100644 index 00000000..17f4f694 --- /dev/null +++ b/examples/http/src/example/server.clj @@ -0,0 +1,22 @@ +(ns example.server + (:require [reitit.http :as http] + [reitit.ring :as ring] + [reitit.interceptor.sieppari] + [ring.adapter.jetty :as jetty])) + +(def app + (http/ring-handler + (http/router + ["/" {:get (fn [request] + {:status 200 + :body "hello!"})}]) + (ring/routes + (ring/create-default-handler)) + {:executor reitit.interceptor.sieppari/executor})) + +(defn start [] + (jetty/run-jetty #'app {:port 3000, :join? false, :async? true}) + (println "server running in port 3000")) + +(comment + (start)) diff --git a/modules/reitit-core/src/reitit/core.cljc b/modules/reitit-core/src/reitit/core.cljc index 70a5680a..88503b2c 100644 --- a/modules/reitit-core/src/reitit/core.cljc +++ b/modules/reitit-core/src/reitit/core.cljc @@ -335,7 +335,7 @@ (str ":single-static-path-router requires exactly 1 static route: " compiled-routes) {:routes compiled-routes}))) (let [[n :as names] (find-names compiled-routes opts) - [[p data result] :as compiled] compiled-routes + [[p data result]] compiled-routes p #?(:clj (.intern ^String p) :cljs p) match (->Match p data result {} p) routes (uncompile-routes compiled-routes)] diff --git a/modules/reitit-core/src/reitit/interceptor.cljc b/modules/reitit-core/src/reitit/interceptor.cljc index 8f9cfd0c..a5139c0a 100644 --- a/modules/reitit-core/src/reitit/interceptor.cljc +++ b/modules/reitit-core/src/reitit/interceptor.cljc @@ -8,7 +8,20 @@ (into-interceptor [this data opts])) (defrecord Interceptor [name enter leave error]) -(defrecord Endpoint [data interceptors]) +(defrecord Endpoint [data interceptors queue]) +(defrecord Context [request response exception]) + +(defprotocol Executor + (queue + [this interceptors] + "takes a sequence of interceptors and compiles them to queue for the executor") + (execute + [this interceptors request] + [this interceptors request respond raise] + "executes the interceptor chain")) + +(defn context [request] + (map->Context {:request request})) (def ^:dynamic *max-compile-depth* 10) @@ -44,9 +57,13 @@ #?(:clj clojure.lang.Fn :cljs function) - (into-interceptor [this _ _] - (map->Interceptor - {:enter this})) + (into-interceptor [this data opts] + (into-interceptor + {:name ::handler + ::handler this + :enter (fn [ctx] + (assoc ctx :response (this (:request ctx))))} + data opts)) #?(:clj clojure.lang.PersistentArrayMap :cljs cljs.core.PersistentArrayMap) @@ -78,45 +95,33 @@ nil (into-interceptor [_ _ _])) -(defn- ensure-handler! [path data scope] - (when-not (:handler data) - (throw (ex-info - (str "path \"" path "\" doesn't have a :handler defined" - (if scope (str " for " scope))) - (merge {:path path, :data data} - (if scope {:scope scope})))))) - -(defn- expand-and-transform - [interceptors data {:keys [::transform] :or {transform identity} :as opts}] - (->> interceptors - (keep #(into-interceptor % data opts)) - (transform) - (keep #(into-interceptor % data opts)) - (into []))) - ;; ;; public api ;; (defn chain "Creates a Interceptor chain out of sequence of IntoInterceptor - and optionally a handler. Optionally takes route data and (Router) opts." - ([interceptors handler data] - (chain interceptors handler data nil)) - ([interceptors handler data opts] - (let [interceptor (some-> (into-interceptor handler data opts) - (assoc :name (:name data)))] - (-> (expand-and-transform interceptors data opts) - (cond-> interceptor (conj interceptor)))))) + Optionally takes route data and (Router) opts." + ([interceptors] + (chain interceptors nil nil)) + ([interceptors data] + (chain interceptors data nil)) + ([interceptors data {:keys [::transform] :or {transform identity} :as opts}] + (->> interceptors + (keep #(into-interceptor % data opts)) + (transform) + (keep #(into-interceptor % data opts)) + (into [])))) (defn compile-result ([route opts] (compile-result route opts nil)) - ([[path {:keys [interceptors handler] :as data}] opts scope] - (ensure-handler! path data scope) - (map->Endpoint - {:interceptors (chain interceptors handler data opts) - :data data}))) + ([[_ {:keys [interceptors handler] :as data}] {:keys [::queue] :as opts} _] + (let [chain (chain (into (vec interceptors) [handler]) data opts)] + (map->Endpoint + {:interceptors chain + :queue ((or queue identity) chain) + :data data})))) (defn router "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with @@ -131,8 +136,8 @@ Options: - | key | description | - | --------------------------------|-------------| + | key | description + | --------------------------------|------------- | `:reitit.interceptor/transform` | Function of [Interceptor] => [Interceptor] to transform the expanded Interceptors (default: identity). | `:reitit.interceptor/registry` | Map of `keyword => IntoInterceptor` to replace keyword references into Interceptor diff --git a/modules/reitit-http/project.clj b/modules/reitit-http/project.clj new file mode 100644 index 00000000..9adf42ac --- /dev/null +++ b/modules/reitit-http/project.clj @@ -0,0 +1,10 @@ +(defproject metosin/reitit-http "0.2.0-SNAPSHOT" + :description "Reitit: HTTP routing with interceptors" + :url "https://github.com/metosin/reitit" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :plugins [[lein-parent "0.3.2"]] + :parent-project {:path "../../project.clj" + :inherit [:deploy-repositories :managed-dependencies]} + :dependencies [[metosin/reitit-core] + [metosin/reitit-ring]]) diff --git a/modules/reitit-http/src/reitit/http.cljc b/modules/reitit-http/src/reitit/http.cljc new file mode 100644 index 00000000..373df4db --- /dev/null +++ b/modules/reitit-http/src/reitit/http.cljc @@ -0,0 +1,124 @@ +(ns reitit.http + (:require [meta-merge.core :refer [meta-merge]] + [reitit.interceptor :as interceptor] + [reitit.ring :as ring] + [reitit.core :as r] + [reitit.impl :as impl])) + +(defrecord Endpoint [data interceptors queue handler path method]) + +(defn coerce-handler [[path data] {:keys [expand] :as opts}] + [path (reduce + (fn [acc method] + (if (contains? acc method) + (update acc method expand opts) + acc)) data ring/http-methods)]) + +(defn compile-result [[path data] opts] + (let [[top childs] (ring/group-keys data) + compile (fn [[path data] opts scope] + (interceptor/compile-result [path data] opts scope)) + ->endpoint (fn [p d m s] + (let [compiled (compile [p d] opts s)] + (-> compiled + (map->Endpoint) + (assoc :path p) + (assoc :method m)))) + ->methods (fn [any? data] + (reduce + (fn [acc method] + (cond-> acc + any? (assoc method (->endpoint path data method nil)))) + (ring/map->Methods {}) + ring/http-methods))] + (if-not (seq childs) + (->methods true top) + (reduce-kv + (fn [acc method data] + (let [data (meta-merge top data)] + (assoc acc method (->endpoint path data method method)))) + (->methods (:handler top) data) + childs)))) + +(defn router + "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with + support for http-methods and Interceptors. See [docs](https://metosin.github.io/reitit/) + for details. + + Example: + + (router + [\"/api\" {:interceptors [format-i oauth2-i]} + [\"/users\" {:get get-user + :post update-user + :delete {:interceptors [delete-i] + :handler delete-user}}]]) + + See router options from [[reitit.core/router]] and [[reitit.middleware/router]]." + ([data] + (router data nil)) + ([data opts] + (let [opts (meta-merge {:coerce coerce-handler, :compile compile-result} opts)] + (r/router data opts)))) + +(defn ring-handler + "Creates a ring-handler out of a http-router, + a default ring-handler and options map, with the following keys: + + | key | description | + | ----------------|-------------| + | `:executor` | `reitit.interceptor.Executor` for the interceptor chain + | `:interceptors` | Optional sequence of interceptors that are always run before any other interceptors, even for the default handler" + [router default-handler {:keys [executor interceptors]}] + (let [default-handler (or default-handler (fn ([_]) ([_ respond _] (respond nil)))) + default-queue (->> [default-handler] + (concat interceptors) + (map #(interceptor/into-interceptor % nil (r/options router))) + (interceptor/queue executor)) + router-opts (-> (r/options router) + (assoc ::interceptor/queue (partial interceptor/queue executor)) + (cond-> (seq interceptors) + (update-in [:data :interceptors] (partial into (vec interceptors))))) + router (reitit.http/router (r/routes router) router-opts)] + (with-meta + (fn + ([request] + (if-let [match (r/match-by-path router (:uri request))] + (let [method (:request-method request) + path-params (:path-params match) + endpoint (-> match :result method) + interceptors (or (:queue endpoint) (:interceptors endpoint)) + request (-> request + (impl/fast-assoc :path-params path-params) + (impl/fast-assoc ::r/match match) + (impl/fast-assoc ::r/router router))] + (or (interceptor/execute executor interceptors request) + (interceptor/execute executor default-queue request))) + (interceptor/execute executor default-queue request))) + ([request respond raise] + (let [default #(interceptor/execute executor default-queue % respond raise)] + (if-let [match (r/match-by-path router (:uri request))] + (let [method (:request-method request) + path-params (:path-params match) + endpoint (-> match :result method) + interceptors (or (:queue endpoint) (:interceptors endpoint)) + request (-> request + (impl/fast-assoc :path-params path-params) + (impl/fast-assoc ::r/match match) + (impl/fast-assoc ::r/router router)) + respond' (fn [response] + (if response + (respond response) + (default request)))] + (if interceptors + (interceptor/execute executor interceptors request respond' raise) + (default request))) + (default request))) + nil)) + {::r/router router}))) + +(defn get-router [handler] + (-> handler meta ::r/router)) + +(defn get-match [request] + (::r/match request)) diff --git a/modules/reitit-http/src/reitit/http/coercion.cljc b/modules/reitit-http/src/reitit/http/coercion.cljc new file mode 100644 index 00000000..e14019a7 --- /dev/null +++ b/modules/reitit-http/src/reitit/http/coercion.cljc @@ -0,0 +1,53 @@ +(ns reitit.http.coercion + (:require [reitit.coercion :as coercion] + [reitit.spec :as rs] + [reitit.impl :as impl])) + +(def coerce-request-interceptor + "Interceptor for pluggable request coercion. + Expects a :coercion of type `reitit.coercion/Coercion` + and :parameters from route data, otherwise does not mount." + {:name ::coerce-request + :spec ::rs/parameters + :compile (fn [{:keys [coercion parameters]} opts] + (if (and coercion parameters) + (let [coercers (coercion/request-coercers coercion parameters opts)] + {:enter + (fn [ctx] + (let [request (:request ctx) + coerced (coercion/coerce-request coercers request) + request (impl/fast-assoc request :parameters coerced)] + (assoc ctx :request request)))})))}) + +(def coerce-response-interceptor + "Interceptor for pluggable response coercion. + Expects a :coercion of type `reitit.coercion/Coercion` + and :responses from route data, otherwise does not mount." + {:name ::coerce-response + :spec ::rs/responses + :compile (fn [{:keys [coercion responses]} opts] + (if (and coercion responses) + (let [coercers (coercion/response-coercers coercion responses opts)] + {:leave + (fn [ctx] + (let [response (coercion/coerce-response coercers (:request ctx) (:response ctx))] + (assoc ctx :response response)))})))}) + +(def coerce-exceptions-interceptor + "Interceptor for handling coercion exceptions. + Expects a :coercion of type `reitit.coercion/Coercion` + and :parameters or :responses from route data, otherwise does not mount." + {:name ::coerce-exceptions + :compile (fn [{:keys [coercion parameters responses]} _] + (if (and coercion (or parameters responses)) + {:error (fn [ctx] + (let [data (ex-data (:error ctx))] + (if-let [status (case (:type data) + ::coercion/request-coercion 400 + ::coercion/response-coercion 500 + nil)] + (let [response {:status status, :body (coercion/encode-error data)}] + (-> ctx + (assoc :response response) + (assoc :error nil))) + ctx)))}))}) diff --git a/modules/reitit-http/src/reitit/http/spec.cljc b/modules/reitit-http/src/reitit/http/spec.cljc new file mode 100644 index 00000000..2834a705 --- /dev/null +++ b/modules/reitit-http/src/reitit/http/spec.cljc @@ -0,0 +1,23 @@ +(ns reitit.http.spec + (:require [clojure.spec.alpha :as s] + [reitit.ring.spec :as rrs] + [reitit.interceptor :as interceptor] + [reitit.spec :as rs])) + +;; +;; Specs +;; + +(s/def ::interceptors (s/coll-of (partial satisfies? interceptor/IntoInterceptor))) + +(s/def ::data + (s/keys :opt-un [::rs/handler ::rs/name ::interceptors])) + +;; +;; Validator +;; + +(defn validate-spec! + [routes {:keys [spec ::rs/explain] :or {explain s/explain-str, spec ::data}}] + (when-let [problems (rrs/validate-route-data routes :interceptors spec)] + (rs/throw-on-problems! problems explain))) diff --git a/modules/reitit-ring/src/reitit/ring.cljc b/modules/reitit-ring/src/reitit/ring.cljc index 1c03e4f0..f74b0e85 100644 --- a/modules/reitit-ring/src/reitit/ring.cljc +++ b/modules/reitit-ring/src/reitit/ring.cljc @@ -3,22 +3,76 @@ [reitit.middleware :as middleware] [reitit.core :as r] [reitit.impl :as impl] - #?@(:clj [ - [ring.util.mime-type :as mime-type] - [ring.util.response :as response]]) + #?@(:clj [[ring.util.mime-type :as mime-type] + [ring.util.response :as response]]) [clojure.string :as str])) (def http-methods #{:get :head :post :put :delete :connect :options :trace :patch}) (defrecord Methods [get head post put delete connect options trace patch]) (defrecord Endpoint [data handler path method middleware]) -(defn- group-keys [data] +(defn ^:no-wiki group-keys [data] (reduce-kv (fn [[top childs] k v] (if (http-methods k) [top (assoc childs k v)] [(assoc top k v) childs])) [{} {}] data)) +(defn coerce-handler [[path data] {:keys [expand] :as opts}] + [path (reduce + (fn [acc method] + (if (contains? acc method) + (update acc method expand opts) + acc)) data http-methods)]) + +(defn compile-result [[path data] opts] + (let [[top childs] (group-keys data) + ->endpoint (fn [p d m s] + (-> (middleware/compile-result [p d] opts s) + (map->Endpoint) + (assoc :path p) + (assoc :method m))) + ->methods (fn [any? data] + (reduce + (fn [acc method] + (cond-> acc + any? (assoc method (->endpoint path data method nil)))) + (map->Methods {}) + http-methods))] + (if-not (seq childs) + (->methods true top) + (reduce-kv + (fn [acc method data] + (let [data (meta-merge top data)] + (assoc acc method (->endpoint path data method method)))) + (->methods (:handler top) data) + childs)))) + +;; +;; public api +;; + +(defn router + "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with + support for http-methods and Middleware. See [docs](https://metosin.github.io/reitit/) + for details. + + Example: + + (router + [\"/api\" {:middleware [wrap-format wrap-oauth2]} + [\"/users\" {:get get-user + :post update-user + :delete {:middleware [wrap-delete] + :handler delete-user}}]]) + + See router options from [[reitit.core/router]] and [[reitit.middleware/router]]." + ([data] + (router data nil)) + ([data opts] + (let [opts (meta-merge {:coerce coerce-handler, :compile compile-result} opts)] + (r/router data opts)))) + (defn routes "Create a ring handler by combining several handlers into one." [& handlers] @@ -55,7 +109,7 @@ (if-let [match (::r/match request)] (let [method (:request-method request :any) result (:result match) - handler? (or (-> result method :handler) (-> result :any :handler)) + handler? (or (-> result method) (-> result :any)) error-handler (if handler? not-acceptable method-not-allowed)] (error-handler request)) (not-found request))) @@ -156,7 +210,8 @@ (impl/fast-assoc ::r/match match) (impl/fast-assoc ::r/router router))] ((routes handler default-handler) request respond raise)) - (default-handler request respond raise)))) + (default-handler request respond raise)) + nil)) {::r/router router})))) (defn get-router [handler] @@ -164,54 +219,3 @@ (defn get-match [request] (::r/match request)) - -(defn coerce-handler [[path data] {:keys [expand] :as opts}] - [path (reduce - (fn [acc method] - (if (contains? acc method) - (update acc method expand opts) - acc)) data http-methods)]) - -(defn compile-result [[path data] opts] - (let [[top childs] (group-keys data) - ->endpoint (fn [p d m s] - (-> (middleware/compile-result [p d] opts s) - (map->Endpoint) - (assoc :path p) - (assoc :method m))) - ->methods (fn [any? data] - (reduce - (fn [acc method] - (cond-> acc - any? (assoc method (->endpoint path data method nil)))) - (map->Methods {}) - http-methods))] - (if-not (seq childs) - (->methods true top) - (reduce-kv - (fn [acc method data] - (let [data (meta-merge top data)] - (assoc acc method (->endpoint path data method method)))) - (->methods (:handler top) data) - childs)))) - -(defn router - "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with - support for http-methods and Middleware. See [docs](https://metosin.github.io/reitit/) - for details. - - Example: - - (router - [\"/api\" {:middleware [wrap-format wrap-oauth2]} - [\"/users\" {:get get-user - :post update-user - :delete {:middleware [wrap-delete] - :handler delete-user}}]]) - - See router options from [[reitit.core/router]] and [[reitit.middleware/router]]." - ([data] - (router data nil)) - ([data opts] - (let [opts (meta-merge {:coerce coerce-handler, :compile compile-result} opts)] - (r/router data opts)))) diff --git a/modules/reitit-ring/src/reitit/ring/coercion.cljc b/modules/reitit-ring/src/reitit/ring/coercion.cljc index e5c91da2..489c058e 100644 --- a/modules/reitit-ring/src/reitit/ring/coercion.cljc +++ b/modules/reitit-ring/src/reitit/ring/coercion.cljc @@ -5,7 +5,7 @@ (defn handle-coercion-exception [e respond raise] (let [data (ex-data e)] - (if-let [status (condp = (:type data) + (if-let [status (case (:type data) ::coercion/request-coercion 400 ::coercion/response-coercion 500 nil)] diff --git a/modules/reitit-ring/src/reitit/ring/spec.cljc b/modules/reitit-ring/src/reitit/ring/spec.cljc index 9039482a..1ec586be 100644 --- a/modules/reitit-ring/src/reitit/ring/spec.cljc +++ b/modules/reitit-ring/src/reitit/ring/spec.cljc @@ -7,7 +7,7 @@ ;; Specs ;; -(s/def ::middleware (s/coll-of #(satisfies? middleware/IntoMiddleware %))) +(s/def ::middleware (s/coll-of (partial satisfies? middleware/IntoMiddleware))) (s/def ::data (s/keys :req-un [::rs/handler] @@ -26,11 +26,12 @@ :non-specs non-specs}))) (s/merge-spec-impl (vec specs) (vec specs) nil)) -(defn- validate-ring-route-data [routes spec] +(defn validate-route-data [routes key spec] (->> (for [[p _ c] routes - [method {:keys [data middleware] :as endpoint}] c + [method {:keys [data] :as endpoint}] c :when endpoint - :let [mw-specs (seq (keep :spec middleware)) + :let [target (key endpoint) + mw-specs (seq (keep :spec target)) specs (keep identity (into [spec] mw-specs)) spec (merge-specs specs)]] (when-let [problems (and spec (s/explain-data spec data))] @@ -39,5 +40,5 @@ (defn validate-spec! [routes {:keys [spec ::rs/explain] :or {explain s/explain-str, spec ::data}}] - (when-let [problems (validate-ring-route-data routes spec)] + (when-let [problems (validate-route-data routes :middleware spec)] (rs/throw-on-problems! problems explain))) diff --git a/modules/reitit-sieppari/project.clj b/modules/reitit-sieppari/project.clj new file mode 100644 index 00000000..16d14129 --- /dev/null +++ b/modules/reitit-sieppari/project.clj @@ -0,0 +1,10 @@ +(defproject metosin/reitit-sieppari "0.2.0-SNAPSHOT" + :description "Reitit: Sieppari Interceptors" + :url "https://github.com/metosin/reitit" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :plugins [[lein-parent "0.3.2"]] + :parent-project {:path "../../project.clj" + :inherit [:deploy-repositories :managed-dependencies]} + :dependencies [[metosin/reitit-core] + [metosin/sieppari]]) diff --git a/modules/reitit-sieppari/src/reitit/interceptor/sieppari.clj b/modules/reitit-sieppari/src/reitit/interceptor/sieppari.clj new file mode 100644 index 00000000..e7d0faed --- /dev/null +++ b/modules/reitit-sieppari/src/reitit/interceptor/sieppari.clj @@ -0,0 +1,18 @@ +(ns reitit.interceptor.sieppari + (:require [reitit.interceptor :as interceptor] + [sieppari.queue :as queue] + [sieppari.core :as sieppari])) + +(def executor + (reify + interceptor/Executor + (queue [_ interceptors] + (queue/into-queue + (map + (fn [{:keys [::interceptor/handler] :as interceptor}] + (or handler interceptor)) + interceptors))) + (execute [_ interceptors request] + (sieppari/execute interceptors request)) + (execute [_ interceptors request respond raise] + (sieppari/execute interceptors request respond raise)))) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index c17f4fb5..bb92607f 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -13,7 +13,7 @@ (s/def ::summary string?) (s/def ::description string?) -(s/def ::swagger (s/keys :req-un [::id])) +(s/def ::swagger (s/keys :opt-un [::id])) (s/def ::spec (s/keys :opt-un [::swagger ::no-doc ::tags ::summary ::description])) (def swagger-feature diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj index 0dba44f6..5c1dff83 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -7,10 +7,12 @@ :parent-project {:path "../../project.clj" :inherit [:deploy-repositories :managed-dependencies]} :dependencies [[metosin/reitit-core] - [metosin/reitit-ring] - [metosin/reitit-middleware] [metosin/reitit-spec] [metosin/reitit-schema] + [metosin/reitit-ring] + [metosin/reitit-middleware] + [metosin/reitit-http] [metosin/reitit-swagger] [metosin/reitit-swagger-ui] - [metosin/reitit-frontend]]) + [metosin/reitit-frontend] + [metosin/reitit-sieppari]]) diff --git a/perf-test/clj/reitit/json_size_perf.cljc b/perf-test/clj/reitit/json_size_perf.cljc new file mode 100644 index 00000000..b9004f09 --- /dev/null +++ b/perf-test/clj/reitit/json_size_perf.cljc @@ -0,0 +1,86 @@ +(ns reitit.json-size-perf + (:require [criterium.core :as cc] + [reitit.perf-utils :refer :all] + [reitit.ring :as ring] + [muuntaja.middleware :as mm] + [reitit.coercion.spec] + [reitit.ring.coercion] + [jsonista.core :as j])) + +;; +;; start repl with `lein perf repl` +;; perf measured with the following setup: +;; +;; Model Name: MacBook Pro +;; Model Identifier: MacBookPro113 +;; Processor Name: Intel Core i7 +;; Processor Speed: 2,5 GHz +;; Number of Processors: 1 +;; Total Number of Cores: 4 +;; L2 Cache (per Core): 256 KB +;; L3 Cache: 6 MB +;; Memory: 16 GB +;; + +(defn test! [] + (let [json-request (fn [data] + {:uri "/echo" + :request-method :post + :headers {"content-type" "application/json" + "accept" "application/json"} + :body (j/write-value-as-string data)}) + request-stream (fn [request] + (let [b (.getBytes ^String (:body request))] + (fn [] + (assoc request :body (java.io.ByteArrayInputStream. b))))) + app (ring/ring-handler + (ring/router + ["/echo" + {:post {:parameters {:body any?} + :coercion reitit.coercion.spec/coercion + :handler (fn [request] + (let [body (-> request :parameters :body)] + {:status 200 + :body body}))}}] + {:data {:middleware [mm/wrap-format + reitit.ring.coercion/coerce-request-middleware]}}))] + (doseq [file ["dev-resources/json/json10b.json" + "dev-resources/json/json100b.json" + "dev-resources/json/json1k.json" + "dev-resources/json/json10k.json" + "dev-resources/json/json100k.json"] + :let [data (j/read-value (slurp file)) + request (json-request data) + request! (request-stream request)]] + + "10b" + ;; 38µs (c-api 1.x) + ;; 14µs (c-api 2.0.0-alpha21) + ;; 6µs + + "100b" + ;; 74µs (c-api 1.x) + ;; 16µs (c-api 2.0.0-alpha21) + ;; 8µs + + "1k" + ;; 322µs (c-api 1.x) + ;; 24µs (c-api 2.0.0-alpha21) + ;; 16µs + + "10k" + ;; 3300µs (c-api 1.x) + ;; 120µs (c-api 2.0.0-alpha21) + ;; 110µs + + "100k" + ;; 10600µs (c-api 1.x) + ;; 1100µs (c-api 2.0.0-alpha21) + ;; 1100µs + + (title file) + #_(println (-> (request!) app :body slurp)) + (cc/quick-bench (app (request!)))))) + +(comment + (test!)) diff --git a/perf-test/clj/reitit/middleware_interceptor_perf.clj b/perf-test/clj/reitit/middleware_interceptor_perf.clj index 1079533d..1fcb9507 100644 --- a/perf-test/clj/reitit/middleware_interceptor_perf.clj +++ b/perf-test/clj/reitit/middleware_interceptor_perf.clj @@ -5,6 +5,8 @@ [reitit.interceptor :as interceptor] reitit.chain + sieppari.queue + sieppari.core io.pedestal.interceptor io.pedestal.interceptor.chain)) @@ -34,37 +36,80 @@ (def +items+ 10) (defn expected! [x] - (assert (= (range +items+) (:values x)))) + (println x) + #_(assert (= (range +items+) (:values x)))) (defn middleware [handler value] (fn [request] - (let [values (or (:values request) [])] - (handler (assoc request :values (conj values value)))))) + (handler request))) + +(def map-request {}) +(def record-request (map->RequestOrContext map-request)) (defn middleware-test [] (let [mw (map (fn [value] [middleware value]) (range +items+)) - app (middleware/chain mw identity) - map-request {} - record-request (map->RequestOrContext map-request)] + app (middleware/chain mw identity)] ;; 1000ns + ;; 18ns (identity) (title "middleware - map") (expected! (app map-request)) (cc/quick-bench (app map-request)) ;; 365ns + ;; 21ns (identity) (title "middleware - record") (expected! (app record-request)) (cc/quick-bench (app record-request)) - ;; 6900ns + ;; 6900ns + ;; 10000ns (identity) (title "middleware - dynamic") (expected! ((middleware/chain mw identity) record-request)) (cc/quick-bench ((middleware/chain mw identity) record-request)))) +(defn sieppari-test [] + (let [interceptors (conj + (mapv + (fn [value] + {:enter identity}) + (range +items+)) + identity) + queue (sieppari.queue/into-queue interceptors) + app (fn [req] (sieppari.core/execute interceptors req)) + app2 (fn [req] (sieppari.core/execute queue req))] + + ;; 5500ns + ;; 4000ns (identity) + (title "sieppari - map") + (expected! (app map-request)) + (cc/quick-bench + (app map-request)) + + ;; 4600ns + ;; 3800ns (identity) + (title "sieppari - record") + (expected! (app record-request)) + (cc/quick-bench + (app record-request)) + + ;; 2200ns + ;; 1300ns (identity) + (title "sieppari - map (compiled queue)") + (expected! (app2 map-request)) + (cc/quick-bench + (app2 map-request)) + + ;; 1600ns + ;; 1300ns (identity) + (title "sieppari - record (compiled queue)") + (expected! (app2 record-request)) + (cc/quick-bench + (app2 record-request)))) + ;; ;; Reduce ;; @@ -108,25 +153,15 @@ (defn pedestal-chain-text [] (let [is (map io.pedestal.interceptor/interceptor (map (fn [value] - {:enter (interceptor value)}) (range +items+))) + {:enter identity}) (range +items+))) ctx (io.pedestal.interceptor.chain/enqueue nil is)] ;; 8400ns + ;; 7200ns (identity) (title "pedestal") (cc/quick-bench (io.pedestal.interceptor.chain/execute ctx)))) -#_(defn pedestal-tuned-chain-text [] - (let [is (map io.pedestal.interceptor/interceptor - (map (fn [value] - {:enter (interceptor value)}) (range +items+))) - ctx (reitit.chain/map->Context (reitit.chain/enqueue nil is))] - - ;; 67 µs - (title "pedestal - tuned") - (cc/quick-bench - (reitit.chain/execute ctx)))) - ;; ;; Naive chain ;; @@ -239,8 +274,8 @@ (comment (interceptor-test) (middleware-test) + (sieppari-test) (pedestal-chain-text) - (pedestal-tuned-chain-text) (interceptor-chain-test)) ; Middleware (static chain) => 5µs diff --git a/project.clj b/project.clj index 6a425083..f09c32d6 100644 --- a/project.clj +++ b/project.clj @@ -11,20 +11,23 @@ :managed-dependencies [[metosin/reitit "0.2.0-SNAPSHOT"] [metosin/reitit-core "0.2.0-SNAPSHOT"] - [metosin/reitit-ring "0.2.0-SNAPSHOT"] - [metosin/reitit-middleware "0.2.0-SNAPSHOT"] [metosin/reitit-spec "0.2.0-SNAPSHOT"] [metosin/reitit-schema "0.2.0-SNAPSHOT"] + [metosin/reitit-ring "0.2.0-SNAPSHOT"] + [metosin/reitit-middleware "0.2.0-SNAPSHOT"] + [metosin/reitit-http "0.2.0-SNAPSHOT"] [metosin/reitit-swagger "0.2.0-SNAPSHOT"] [metosin/reitit-swagger-ui "0.2.0-SNAPSHOT"] [metosin/reitit-frontend "0.2.0-SNAPSHOT"] + [metosin/reitit-sieppari "0.2.0-SNAPSHOT"] [meta-merge "1.0.0"] [ring/ring-core "1.6.3"] [metosin/spec-tools "0.7.1"] [metosin/schema-tools "0.10.3"] [metosin/ring-swagger-ui "2.2.10"] - [metosin/muuntaja "0.6.0-alpha1"] - [metosin/jsonista "0.2.1"]] + [metosin/muuntaja "0.6.0-alpha3"] + [metosin/jsonista "0.2.1"] + [metosin/sieppari "0.0.0-alpha4"]] :plugins [[jonase/eastwood "0.2.6"] [lein-doo "0.1.10"] @@ -39,12 +42,14 @@ :source-paths ["modules/reitit/src" "modules/reitit-core/src" "modules/reitit-ring/src" + "modules/reitit-http/src" "modules/reitit-middleware/src" "modules/reitit-spec/src" "modules/reitit-schema/src" "modules/reitit-swagger/src" "modules/reitit-swagger-ui/src" - "modules/reitit-frontend/src"] + "modules/reitit-frontend/src" + "modules/reitit-sieppari/src"] :dependencies [[org.clojure/clojure "1.9.0"] [org.clojure/clojurescript "1.10.339"] @@ -57,8 +62,9 @@ [ring "1.6.3"] [ikitommi/immutant-web "3.0.0-alpha1"] - [metosin/muuntaja "0.6.0-alpha1"] + [metosin/muuntaja "0.6.0-alpha3"] [metosin/ring-swagger-ui "2.2.10"] + [metosin/sieppari "0.0.0-alpha4"] [metosin/jsonista "0.2.1"] [criterium "0.4.4"] @@ -77,6 +83,7 @@ [ikitommi/immutant-web "3.0.0-alpha1"] [io.pedestal/pedestal.route "0.5.4"] [org.clojure/core.async "0.4.474"] + [metosin/sieppari "0.0.0-alpha4"] [yada "1.2.13"] [ring/ring-defaults "0.3.1"] [ataraxy "0.4.0"] diff --git a/scripts/lein-modules b/scripts/lein-modules index 17eefffc..1a95289f 100755 --- a/scripts/lein-modules +++ b/scripts/lein-modules @@ -3,6 +3,17 @@ set -e # Modules -for ext in reitit-core reitit-ring reitit-middleware reitit-spec reitit-schema reitit-swagger reitit-swagger-ui reitit-frontend reitit; do +for ext in \ + reitit-core \ + reitit-spec \ + reitit-schema \ + reitit-ring \ + reitit-middleware \ + reitit-http \ + reitit-swagger \ + reitit-swagger-ui \ + reitit-frontend \ + reitit-sieppari \ + reitit; do cd modules/$ext; lein "$@"; cd ../..; done diff --git a/test/clj/reitit/http_test.clj b/test/clj/reitit/http_test.clj new file mode 100644 index 00000000..ac843d43 --- /dev/null +++ b/test/clj/reitit/http_test.clj @@ -0,0 +1,422 @@ +(ns reitit.http-test + "just Clojure before Sieppari is ported into cljs" + (:require [clojure.test :refer [deftest testing is]] + [clojure.set :as set] + [reitit.interceptor :as interceptor] + [reitit.interceptor.sieppari :as sieppari] + [reitit.http :as http] + [reitit.ring :as ring] + [reitit.core :as r])) + +(defn interceptor [name] + {:enter (fn [ctx] (update-in ctx [:request ::i] (fnil conj []) name))}) + +(defn handler [{:keys [::i]}] + {:status 200 :body (conj i :ok)}) + +(deftest http-router-test + + (testing "http-handler" + (let [api-interceptor (interceptor :api) + router (http/router + ["/api" {:interceptors [api-interceptor]} + ["/all" handler] + ["/get" {:get handler}] + ["/users" {:interceptors [[interceptor :users]] + :get handler + :post {:handler handler + :interceptors [[interceptor :post]]} + :handler handler}]]) + app (http/ring-handler router nil {:executor sieppari/executor})] + + (testing "router can be extracted" + (is (= (r/routes router) + (r/routes (http/get-router app))))) + + (testing "not found" + (is (= nil (app {:uri "/favicon.ico"})))) + + (testing "catch all handler" + (is (= {:status 200, :body [:api :ok]} + (app {:uri "/api/all" :request-method :get})))) + + (testing "just get handler" + (is (= {:status 200, :body [:api :ok]} + (app {:uri "/api/get" :request-method :get}))) + (is (= nil (app {:uri "/api/get" :request-method :post})))) + + (testing "expanded method handler" + (is (= {:status 200, :body [:api :users :ok]} + (app {:uri "/api/users" :request-method :get})))) + + (testing "method handler with middleware" + (is (= {:status 200, :body [:api :users :post :ok]} + (app {:uri "/api/users" :request-method :post})))) + + (testing "fallback handler" + (is (= {:status 200, :body [:api :users :ok]} + (app {:uri "/api/users" :request-method :put})))) + + (testing "3-arity" + (let [result (atom nil) + respond (partial reset! result), raise ::not-called] + (app {:uri "/api/users" :request-method :post} respond raise) + (is (= {:status 200, :body [:api :users :post :ok]} + @result)))))) + + (testing "named routes" + (let [router (http/router + [["/api" + ["/all" {:handler handler :name ::all}] + ["/get" {:get {:handler handler :name ::HIDDEN} + :name ::get}] + ["/users" {:get handler + :post handler + :handler handler + :name ::users}]]]) + app (http/ring-handler router nil {:executor sieppari/executor})] + + (testing "router can be extracted" + (is (= (r/routes router) + (r/routes (http/get-router app))))) + + (testing "only top-level route names are matched" + (is (= [::all ::get ::users] + (r/route-names router)))) + + (testing "all named routes can be matched" + (doseq [name (r/route-names router)] + (is (= name (-> (r/match-by-name router name) :data :name)))))))) + +(def enforce-roles-interceptor + {:enter (fn [{{:keys [::roles] :as request} :request :as ctx}] + (let [required (some-> request (http/get-match) :data ::roles)] + (if (and (seq required) (not (set/intersection required roles))) + (-> ctx + (assoc :response {:status 403, :body "forbidden"}) + (assoc :queue nil)) + ctx)))}) + +(deftest enforcing-data-rules-at-runtime-test + (let [handler (constantly {:status 200, :body "ok"}) + app (http/ring-handler + (http/router + [["/api" + ["/ping" handler] + ["/admin" {::roles #{:admin}} + ["/ping" handler]]]] + {:data {:interceptors [enforce-roles-interceptor]}}) + nil {:executor sieppari/executor})] + + (testing "public handler" + (is (= {:status 200, :body "ok"} + (app {:uri "/api/ping" :request-method :get})))) + + (testing "runtime-enforced handler" + (testing "without needed roles" + (is (= {:status 403 :body "forbidden"} + (app {:uri "/api/admin/ping" + :request-method :get})))) + (testing "with needed roles" + (is (= {:status 200, :body "ok"} + (app {:uri "/api/admin/ping" + :request-method :get + ::roles #{:admin}}))))))) + +(deftest default-handler-test + (let [response {:status 200, :body "ok"} + router (http/router + [["/ping" {:get (constantly response)}] + ["/pong" (constantly nil)]]) + app (http/ring-handler router nil {:executor sieppari/executor})] + + (testing "match" + (is (= response (app {:request-method :get, :uri "/ping"})))) + + (testing "no match" + (testing "with defaults" + (testing "route doesn't match yields nil" + (is (= nil (app {:request-method :get, :uri "/"})))) + (testing "method doesn't match yields nil" + (is (= nil (app {:request-method :post, :uri "/ping"})))) + (testing "handler rejects yields nil" + (is (= nil (app {:request-method :get, :uri "/pong"}))))) + + (testing "with default http responses" + (let [app (http/ring-handler + router + (ring/create-default-handler) + {:executor sieppari/executor})] + (testing "route doesn't match yields 404" + (is (= 404 (:status (app {:request-method :get, :uri "/"}))))) + (testing "method doesn't match yields 405" + (is (= 405 (:status (app {:request-method :post, :uri "/ping"}))))) + (testing "handler rejects yields nil" + (is (= 406 (:status (app {:request-method :get, :uri "/pong"}))))))) + + (testing "with custom http responses" + (let [app (http/ring-handler + router + (ring/create-default-handler + {:not-found (constantly {:status -404}) + :method-not-allowed (constantly {:status -405}) + :not-acceptable (constantly {:status -406})}) + {:executor sieppari/executor})] + (testing "route doesn't match" + (is (= -404 (:status (app {:request-method :get, :uri "/"}))))) + (testing "method doesn't match" + (is (= -405 (:status (app {:request-method :post, :uri "/ping"}))))) + (testing "handler rejects" + (is (= -406 (:status (app {:request-method :get, :uri "/pong"})))))))))) + +(deftest async-http-test + (let [promise #(let [value (atom ::nil)] + (fn + ([] @value) + ([x] + (reset! value x)))) + response {:status 200, :body "ok"} + router (http/router + [["/ping" {:get (fn [_] response)}] + ["/pong" (fn [_] nil)]]) + app (http/ring-handler router nil {:executor sieppari/executor})] + + (testing "match" + (let [respond (promise) + raise (promise)] + (app {:request-method :get, :uri "/ping"} respond raise) + (is (= response (respond))) + (is (= ::nil (raise))))) + + (testing "no match" + + (testing "with defaults" + (testing "route doesn't match" + (let [respond (promise) + raise (promise)] + (app {:request-method :get, :uri "/"} respond raise) + (is (= nil (respond))) + (is (= ::nil (raise))))) + (testing "method doesn't match" + (let [respond (promise) + raise (promise)] + (app {:request-method :post, :uri "/ping"} respond raise) + (is (= nil (respond))) + (is (= ::nil (raise))))) + (testing "handler rejects" + (let [respond (promise) + raise (promise)] + (app {:request-method :get, :uri "/pong"} respond raise) + (is (= nil (respond))) + (is (= ::nil (raise)))))) + + (testing "with default http responses" + + (let [app (http/ring-handler router (ring/create-default-handler) {:executor sieppari/executor})] + (testing "route doesn't match" + (let [respond (promise) + raise (promise)] + (app {:request-method :get, :uri "/"} respond raise) + (is (= 404 (:status (respond)))) + (is (= ::nil (raise))))) + (testing "method doesn't match" + (let [respond (promise) + raise (promise)] + (app {:request-method :post, :uri "/ping"} respond raise) + (is (= 405 (:status (respond)))) + (is (= ::nil (raise))))) + (testing "if handler rejects" + (let [respond (promise) + raise (promise)] + (app {:request-method :get, :uri "/pong"} respond raise) + (is (= 406 (:status (respond)))) + (is (= ::nil (raise)))))))))) + +(deftest interceptor-transform-test + (let [interceptor (fn [name] {:name name + :enter (fn [ctx] + (update-in ctx [:request ::i] (fnil conj []) name))}) + handler (fn [{:keys [::i]}] {:status 200 :body (conj i :ok)}) + request {:uri "/api/avaruus" :request-method :get} + create (fn [options] + (http/ring-handler + (http/router + ["/api" {:interceptors [(interceptor :olipa)]} + ["/avaruus" {:interceptors [(interceptor :kerran)] + :get {:handler handler + :interceptors [(interceptor :avaruus)]}}]] + options) + nil + {:executor sieppari/executor}))] + + (testing "by default, all middleware are applied in order" + (let [app (create nil)] + (is (= {:status 200, :body [:olipa :kerran :avaruus :ok]} + (app request))))) + + (testing "middleware can be re-ordered" + (let [app (create {::interceptor/transform (partial sort-by :name)})] + (is (= {:status 200, :body [:avaruus :kerran :olipa :ok]} + (app request))))) + + (testing "adding debug middleware between middleware" + (let [app (create {::interceptor/transform #(interleave % (repeat (interceptor "debug")))})] + (is (= {:status 200, :body [:olipa "debug" :kerran "debug" :avaruus "debug" :ok]} + (app request))))))) + +(deftest resource-handler-test + (let [redirect (fn [uri] {:status 302, :body "", :headers {"Location" uri}}) + request (fn [uri] {:uri uri, :request-method :get})] + (testing "inside a router" + + (testing "from root" + (let [app (http/ring-handler + (http/router + ["/*" (ring/create-resource-handler)]) + (ring/create-default-handler) + {:executor sieppari/executor})] + (testing test + (testing "different file-types" + (let [response (app (request "/hello.json"))] + (is (= "application/json" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "{\"hello\": \"file\"}" (slurp (:body response))))) + (let [response (app (request "/hello.xml"))] + (is (= "text/xml" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body response)))))) + + (testing "index-files" + (let [response (app (request "/docs"))] + (is (= (redirect "/docs/index.html") response))) + (let [response (app (request "/docs/"))] + (is (= (redirect "/docs/index.html") response)))) + + (testing "not found" + (let [response (app (request "/not-found"))] + (is (= 404 (:status response))))) + + (testing "3-arity" + (let [result (atom nil) + respond (partial reset! result) + raise ::not-called] + (app (request "/hello.xml") respond raise) + (is (= "text/xml" (get-in @result [:headers "Content-Type"]))) + (is (get-in @result [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body @result))))))))) + + (testing "from path" + (let [app (http/ring-handler + (http/router + ["/files/*" (ring/create-resource-handler)]) + (ring/create-default-handler) + {:executor sieppari/executor}) + request #(request (str "/files" %)) + redirect #(redirect (str "/files" %))] + (testing test + (testing "different file-types" + (let [response (app (request "/hello.json"))] + (is (= "application/json" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "{\"hello\": \"file\"}" (slurp (:body response))))) + (let [response (app (request "/hello.xml"))] + (is (= "text/xml" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body response)))))) + + (testing "index-files" + (let [response (app (request "/docs"))] + (is (= (redirect "/docs/index.html") response))) + (let [response (app (request "/docs/"))] + (is (= (redirect "/docs/index.html") response)))) + + (testing "not found" + (let [response (app (request "/not-found"))] + (is (= 404 (:status response))))) + + (testing "3-arity" + (let [result (atom nil) + respond (partial reset! result) + raise ::not-called] + (app (request "/hello.xml") respond raise) + (is (= "text/xml" (get-in @result [:headers "Content-Type"]))) + (is (get-in @result [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body @result)))))))))) + + (testing "outside a router" + + (testing "from root" + (let [app (http/ring-handler + (http/router []) + (ring/routes + (ring/create-resource-handler {:path "/"}) + (ring/create-default-handler)) + {:executor sieppari/executor})] + (testing test + (testing "different file-types" + (let [response (app (request "/hello.json"))] + (is (= "application/json" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "{\"hello\": \"file\"}" (slurp (:body response))))) + (let [response (app (request "/hello.xml"))] + (is (= "text/xml" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body response)))))) + + (testing "index-files" + (let [response (app (request "/docs"))] + (is (= (redirect "/docs/index.html") response))) + (let [response (app (request "/docs/"))] + (is (= (redirect "/docs/index.html") response)))) + + (testing "not found" + (let [response (app (request "/not-found"))] + (is (= 404 (:status response))))) + + (testing "3-arity" + (let [result (atom nil) + respond (partial reset! result) + raise ::not-called] + (app (request "/hello.xml") respond raise) + (is (= "text/xml" (get-in @result [:headers "Content-Type"]))) + (is (get-in @result [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body @result))))))))) + + (testing "from path" + (let [app (http/ring-handler + (http/router []) + (ring/routes + (ring/create-resource-handler {:path "/files"}) + (ring/create-default-handler)) + {:executor sieppari/executor}) + request #(request (str "/files" %)) + redirect #(redirect (str "/files" %))] + (testing test + (testing "different file-types" + (let [response (app (request "/hello.json"))] + (is (= "application/json" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "{\"hello\": \"file\"}" (slurp (:body response))))) + (let [response (app (request "/hello.xml"))] + (is (= "text/xml" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body response)))))) + + (testing "index-files" + (let [response (app (request "/docs"))] + (is (= (redirect "/docs/index.html") response))) + (let [response (app (request "/docs/"))] + (is (= (redirect "/docs/index.html") response)))) + + (testing "not found" + (let [response (app (request "/not-found"))] + (is (= 404 (:status response))))) + + (testing "3-arity" + (let [result (atom nil) + respond (partial reset! result) + raise ::not-called] + (app (request "/hello.xml") respond raise) + (is (= "text/xml" (get-in @result [:headers "Content-Type"]))) + (is (get-in @result [:headers "Last-Modified"])) + (is (= "file\n" (slurp (:body @result)))))))))))) diff --git a/test/cljc/reitit/interceptor_test.cljc b/test/cljc/reitit/interceptor_test.cljc index 2c374b7d..cecc7a8a 100644 --- a/test/cljc/reitit/interceptor_test.cljc +++ b/test/cljc/reitit/interceptor_test.cljc @@ -5,32 +5,39 @@ #?(:clj (:import (clojure.lang ExceptionInfo)))) +(def ctx (interceptor/context [])) + (defn execute [interceptors ctx] (as-> ctx $ (reduce #(%2 %1) $ (keep :enter interceptors)) - (reduce #(%2 %1) $ (reverse (keep :leave interceptors))))) + (reduce #(%2 %1) $ (reverse (keep :leave interceptors))) + (:response $))) -(def ctx []) +(defn f [value ctx] + (update ctx :request conj value)) + +(defn kws [k qk] + (keyword (namespace qk) (str (name k) "_" (name qk)))) (defn interceptor [value] {:name value - :enter #(conj % value) - :leave #(conj % value)}) + :enter #(update % :request (fnil conj []) (kws :enter value)) + :leave #(update % :response (fnil conj []) (kws :leave value))}) (defn enter [value] {:name value - :enter #(conj % value)}) + :enter (partial f value)}) -(defn handler [ctx] - (conj ctx :ok)) +(defn handler [request] + (conj request :ok)) (defn create ([interceptors] - (create interceptors nil)) + (create interceptors nil)) ([interceptors opts] (let [chain (interceptor/chain - interceptors - handler :data opts)] + (conj interceptors handler) + :data opts)] (partial execute chain)))) (deftest expand-interceptor-test @@ -41,8 +48,8 @@ (let [calls (atom 0) enter (fn [value] (swap! calls inc) - (fn [ctx] - (conj ctx value)))] + {:enter (fn [ctx] + (update ctx :request conj value))})] (testing "as function" (reset! calls 0) @@ -73,14 +80,14 @@ (testing "as map" (reset! calls 0) - (let [app (create [{:enter (enter :value)}])] + (let [app (create [{:enter (:enter (enter :value))}])] (dotimes [_ 10] (is (= [:value :ok] (app ctx))) (is (= 1 @calls))))) (testing "as Interceptor" (reset! calls 0) - (let [app (create [(interceptor/map->Interceptor {:enter (enter :value)})])] + (let [app (create [(interceptor/map->Interceptor {:enter (:enter (enter :value))})])] (dotimes [_ 10] (is (= [:value :ok] (app ctx))) (is (= 1 @calls))))))) @@ -90,12 +97,12 @@ i1 (fn [value] {:compile (fn [data _] (swap! calls inc) - (fn [ctx] - (into ctx [data value])))}) + {:enter (fn [ctx] + (update ctx :request into [data value]))})}) i3 (fn [value] - {:compile (fn [data _] + {:compile (fn [_ _] (swap! calls inc) - {:compile (fn [data _] + {:compile (fn [_ _] (swap! calls inc) (i1 value))})})] @@ -137,16 +144,10 @@ (let [handler (interceptor/interceptor-handler router)] (fn [path] (when-let [interceptors (handler path)] - (execute interceptors []))))) + (execute interceptors ctx))))) (deftest interceptor-handler-test - (testing "all paths should have a handler" - (is (thrown-with-msg? - ExceptionInfo - #"path \"/ping\" doesn't have a :handler defined" - (interceptor/router ["/ping"])))) - (testing "interceptor-handler" (let [api-interceptor (interceptor :api) router (interceptor/router @@ -164,36 +165,37 @@ (is (= [:ok] (app "/ping")))) (testing "with interceptor" - (is (= [:api :ok :api] (app "/api/ping")))) + (is (= [:enter_api :ok :leave_api] (app "/api/ping")))) (testing "with nested interceptor" - (is (= [:api :admin :ok :admin :api] (app "/api/admin/ping")))) + (is (= [:enter_api :enter_admin :ok :leave_admin :leave_api] (app "/api/admin/ping")))) (testing ":compile interceptor can be unmounted at creation-time" (let [i1 {:name ::i1, :compile (constantly (interceptor ::i1))} i2 {:name ::i2, :compile (constantly nil)} i3 (interceptor ::i3) router (interceptor/router - ["/api" {:name ::api - :interceptors [i1 i2 i3 i2] + ["/api" {:interceptors [i1 i2 i3 i2] :handler handler}]) app (create-app router)] - (is (= [::i1 ::i3 :ok ::i3 ::i1] (app "/api"))) + (is (= [::enter_i1 ::enter_i3 :ok ::leave_i3 ::leave_i1] (app "/api"))) (testing "routes contain list of actually applied interceptors" - (is (= [::i1 ::i3 ::api] (->> (r/compiled-routes router) - first - last - :interceptors - (map :name))))) + (is (= [::i1 ::i3 ::interceptor/handler] + (->> (r/compiled-routes router) + first + last + :interceptors + (map :name))))) (testing "match contains list of actually applied interceptors" - (is (= [::i1 ::i3 ::api] (->> "/api" - (r/match-by-path router) - :result - :interceptors - (map :name)))))))))) + (is (= [::i1 ::i3 ::interceptor/handler] + (->> "/api" + (r/match-by-path router) + :result + :interceptors + (map :name)))))))))) (deftest chain-test (testing "chain can produce interceptor chain of any IntoInterceptor" @@ -204,12 +206,12 @@ i5 {:compile (fn [{:keys [mount?]} _] (when mount? (interceptor ::i5)))} - chain1 (interceptor/chain [i1 i2 i3 i4 i5] handler {:mount? true}) - chain2 (interceptor/chain [i1 i2 i3 i4 i5] handler {:mount? false}) - chain3 (interceptor/chain [i1 i2 i3 i4 i5] nil {:mount? false})] - (is (= [::i1 ::i3 ::i4 ::i5 :ok ::i5 ::i4 ::i3 ::i1] (execute chain1 []))) - (is (= [::i1 ::i3 ::i4 :ok ::i4 ::i3 ::i1] (execute chain2 []))) - (is (= [::i1 ::i3 ::i4 ::i4 ::i3 ::i1] (execute chain3 [])))))) + chain1 (interceptor/chain [i1 i2 i3 i4 i5 handler] {:mount? true}) + chain2 (interceptor/chain [i1 i2 i3 i4 i5 handler] {:mount? false}) + chain3 (interceptor/chain [i1 i2 i3 i4 i5] {:mount? false})] + (is (= [::enter_i1 ::enter_i3 ::enter_i4 ::enter_i5 :ok ::leave_i5 ::leave_i4 ::leave_i3 ::leave_i1] (execute chain1 ctx))) + (is (= [::enter_i1 ::enter_i3 ::enter_i4 :ok ::leave_i4 ::leave_i3 ::leave_i1] (execute chain2 ctx))) + (is (= [::leave_i4 ::leave_i3 ::leave_i1] (execute chain3 ctx)))))) (deftest interceptor-transform-test (let [debug-i (enter ::debug) @@ -227,7 +229,10 @@ (is (= [::olipa ::kerran ::avaruus :ok] (app "/ping"))))) (testing "interceptors can be re-ordered" - (let [app (create {::interceptor/transform (partial sort-by :name)})] + (let [app (create {::interceptor/transform (fn [interceptors] + (concat + (sort-by :name (butlast interceptors)) + [(last interceptors)]))})] (is (= [::avaruus ::kerran ::olipa :ok] (app "/ping"))))) (testing "adding debug interceptor between interceptors"