Skip to content

Commit 927d7c7

Browse files
committed
add lesson 14
1 parent 92c5ee8 commit 927d7c7

File tree

7 files changed

+200
-0
lines changed

7 files changed

+200
-0
lines changed

otus-14/.gitignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/target
2+
/classes
3+
/checkouts
4+
profiles.clj
5+
pom.xml
6+
pom.xml.asc
7+
*.jar
8+
*.class
9+
/.lein-*
10+
/.nrepl-port
11+
/.prepl-port
12+
.hgignore
13+
.hg/

otus-14/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# otus-14
2+
3+
Библиотеки, используемые в проекте:
4+
5+
- [ring](https://github.com/ring-clojure/ring) — фундамент
6+
- [ring-defaults](https://github.com/ring-clojure/ring-defaults) — разумные умолчания для типовых задач ("сайт", "API")
7+
- [compojure](https://github.com/weavejester/compojure) — роутер
8+
- [hiccup](https://github.com/weavejester/hiccup) — DSL для генерации HTML
9+
- [cheshire](https://github.com/dakrone/cheshire) — кодировщик/декодировщик JSON
10+
- [compojure-api](https://github.com/metosin/compojure-api) — надстройка над compojure, помогающая генерировать Swagger Spec

otus-14/homework/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# spec-faker
2+
3+
Вам нужно создать Web-приложение, способное генерировать примеры данных, основываясь на предоставленной пользователем спецификации.
4+
5+
Подзадачи:
6+
7+
1. `GET /` без параметров показывает страницу с формой для ввода спецификации.
8+
2. `GET /` с параметром "spec" генерирует пример данных по переданной спецификации. Параметр принимает спецификацию в виде *URL-encoded JSON*. Стоит предусмотреть валидацию спецификации и возврат статуса "Bad request", если спецификация не валидна.
9+
3. `POST /`, отправляемый формой, делает перенаправление на `/?spec=...`. Здесь тоже стоит проверить валидность спецификации (поможет выделение функции проверки и использование оной в обоих сценариях).
10+
4. Для приложения нужно описать Swagger Spec и настроить [ring-swagger](https://github.com/metosin/ring-swagger) на показ Swagger UI.
11+
12+
Поскольку параметр "spec" получается "динамически типизирован", но при этом предполагает содержимое, совместимое со Swagger [Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#schema-object), то и тип в Swagger Spec у него будет "object" с перечислением полей вроде "type".
13+
14+
Реализовывать всё многобразие способов описания данных, поддерживаемое стандартом OpenAPI **не нужно**. Достаточно будет поддержки не вложенных объектов с полями-примитивами.

otus-14/homework/project.clj

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(defproject spec-faker "0.1.0-SNAPSHOT"
2+
:description "A simple Web-app that can fake for you some data using your Swagger spec"
3+
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
4+
:url "https://www.eclipse.org/legal/epl-2.0/"}
5+
:dependencies [[org.clojure/clojure "1.10.1"]
6+
[ring/ring-core "1.10.0"]
7+
[ring/ring-jetty-adapter "1.10.0"]
8+
[ring/ring-defaults "0.3.4"]
9+
[compojure "1.7.0"]
10+
[hiccup "1.0.5"]
11+
[cheshire "5.11.0"]]
12+
:main ^:skip-aot spec-faker.core
13+
:target-path "target/%s"
14+
:profiles {:uberjar {:aot :all
15+
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(ns spec-faker.core
2+
(:require [ring.adapter.jetty :refer [run-jetty]]
3+
[compojure.core :refer :all]
4+
[hiccup.core :refer [html]])
5+
(:gen-class))
6+
7+
(defn -main
8+
[& args]
9+
(run-jetty
10+
(routes
11+
(GET "/" []
12+
(html [:h1 "Hello World!"])))
13+
{:port 8000}))

otus-14/project.clj

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(defproject otus-14 "0.1.0-SNAPSHOT"
2+
:description "FIXME: write description"
3+
:url "http://example.com/FIXME"
4+
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
5+
:url "https://www.eclipse.org/legal/epl-2.0/"}
6+
:dependencies [[org.clojure/clojure "1.10.1"]
7+
[ring/ring-core "1.10.0"]
8+
[ring/ring-devel "1.10.0"]
9+
[ring/ring-jetty-adapter "1.10.0"]
10+
[ring/ring-defaults "0.3.4"]
11+
[compojure "1.7.0"]
12+
[hiccup "1.0.5"]
13+
[cheshire "5.11.0"]]
14+
:main ^:skip-aot otus-14.core
15+
:target-path "target/%s"
16+
:profiles {:uberjar {:aot :all
17+
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})

otus-14/src/otus_14/core.clj

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
(ns otus-14.core
2+
(:require [ring.adapter.jetty :refer [run-jetty]]
3+
[ring.handler.dump :refer [handle-dump]]
4+
[ring.util.response :refer [redirect]]
5+
[ring.middleware.reload :refer [wrap-reload]]
6+
[ring.middleware.params :refer [wrap-params]]
7+
[ring.middleware.keyword-params :refer [wrap-keyword-params]]
8+
[compojure.core :refer :all]
9+
[compojure.route :as route]
10+
[compojure.coercions :refer [as-int]]
11+
[hiccup.core :refer [html]]
12+
[hiccup.util :refer [url]]
13+
[cheshire.core :refer [generate-string]])
14+
(:gen-class))
15+
16+
;; * handler
17+
18+
(defn handler [req]
19+
{:status 200
20+
:body "Hello world!"})
21+
22+
(def app
23+
(-> #'handler
24+
wrap-keyword-params
25+
wrap-params))
26+
27+
;; * huccup
28+
29+
(defn page [title & body]
30+
[:html
31+
[:head
32+
[:title title]]
33+
[:body
34+
body]])
35+
36+
(defn handler [req]
37+
{:status 200
38+
:headers {"Content-Type" "text/html"}
39+
:body
40+
(html
41+
(page
42+
"Index"
43+
[:h1 {:style "color: red;"} "Hello world!"]
44+
[:ul
45+
(map (fn [x]
46+
[:li (str x)])
47+
(range 10))]))})
48+
49+
;; * compojure
50+
51+
(defn greet-page [name]
52+
(html
53+
(page
54+
"greet"
55+
(if (nil? name)
56+
[:form {:method "POST"}
57+
[:label "Name"]
58+
[:input {:name "name"}]
59+
[:button {:type "submit"} "Greet"]]
60+
[:h1 (str "Hello, " name "!")]))))
61+
62+
(defroutes router
63+
(GET "/" []
64+
(html
65+
(page
66+
"Index"
67+
[:h1 "Hello world!"])))
68+
69+
(GET "/greet" [name] (greet-page name))
70+
71+
(POST "/greet" [name]
72+
(redirect (str (url "/greet" {:name name}))))
73+
74+
(GET "/dump" req
75+
(handle-dump req))
76+
77+
(GET "/json-dump" []
78+
{:headers {"Content-Type" "application/json"}
79+
:body
80+
(generate-string
81+
{:users
82+
[{:name "Bob"
83+
:admin false
84+
:pets [{:name "Tom"
85+
:age 4}]}]})})
86+
87+
(GET "/add" [x :<< as-int
88+
y :<< as-int]
89+
(html [:h1 (+ x y)]))
90+
91+
(GET "/blog/:user-id/post/:post-id" [user-id post-id]
92+
(handle-dump {:user-id user-id
93+
:post-id post-id}))
94+
95+
(route/not-found
96+
(html
97+
(page
98+
"Page not found"
99+
[:h1 "Oops!"]))))
100+
101+
(def app
102+
(-> #'router
103+
wrap-keyword-params
104+
wrap-params))
105+
106+
;; * Jetty
107+
108+
(comment
109+
(run-jetty #'app {:join? false
110+
:port 8000})
111+
)
112+
113+
(defn -main
114+
"I don't do a whole lot ... yet."
115+
[& args]
116+
(run-jetty
117+
(wrap-reload app)
118+
{:port 8000}))

0 commit comments

Comments
 (0)