O que nossa aplicação web faz Processa requests e gera respostas
Operações CRUD via HTTP
Biblioteca de aplicações web mais utilizada no clojure.
Utilizaremos para construir o nosso serviço web.
Consiste de 4 componentes:
-
Requests
Mapa de entrada
-
Responses
Mapa de saída
-
Handlers
Função que recebe um único argumento (Mapa da Request)
e devolve uma única saída (Mapa da Saída)
-
Middleware
Request Map → Handler → Response Map
Biblioteca compacta para roteamento
Como servidor. Software que permite a interação com o servidor através da rede
REST: Representation State Transfer
-
Adicionar as dependências do
ring/ring-core
e doring/ring-jetty-adapter
em um arquivo deps.edn -
Define um handler que sempre retorna 200 para qualquer request
(defn handler [request]
{:status 200 :body "Hello World!"})
- Inicia o Jetty web server, passando o handler e opções
(require '[ring.adapter.jetty :refer [run-jetty]])
(def app (run-jetty handler
{:port 8080
:join? false}))
:join?
opção para bloquear o REPL ao rodar o servidor
Para parar o servidor
(.stop app)
Queremos aceitar requests para múltiplas rotas e métodos
O objeto de request possui:
- URI
- Request-Method
Para isso utilizaremos o Compojure
Adicionar a dependência do compojure/compojure
(require '[compojure.route :as route])
(require '[compojure.core :refer :all])
(def route
(GET "/hello" request "Hello World!"))
GET
: Macro que define uma rota do método GET"/Hello"
: Rotarequest
: binding da request em símbolos para usar na função da rotaHello World
: O corpo da rota, onde adicionaremos a lógica
(defroutes routes
(GET "/hello" request "Hello!")
(GET "/hello" request "Hello 2")
;; --- demais rotas
)
Ao buscar uma rota desconhecida tomamos um erro, podemos adicionar uma rota padrão para redirecionar quando não t
(require '[compojure.route :as route])
(defroutes routes
(GET "/hello" request "Hello!")
(GET "/hello" request "Hello 2")
(route/not-found "Rota não encontrada")
)
💡 Se atente para deixar a rota de "Not found" por último
Permite programar tratamentos genéricos que deveriam ser aplicados em todas as requisições
(defn custom-middleware
[handler]
(fn [request]
(->> request
;; manipula a request
handler
;; manipula a resposta)))
Pode tratar a request antes de chamar o handler e/ou a resposta após a execução do handler.
Múltiplos tipos de cliente podem aceitar diferentes formatos de resposta, um frontend JS prefere enviar e receber payloads em JSON enquanto aplicações em Clojure Script vão preferir EDN.
;;EDN
{:chave-exemplo "valor exemplo"}
;;JSON
{"chaveExemplo": "valor exemplo"}
Muuntaja: Ferramenta para fazer negociação de conteúdo e formatação de requisição e resposta, permite lidar com as exigências de formatos dos clientes mantendo a aplicação agnóstica a isso.
-
Adicionar a dependência do
metosin/muuntaja
-
Adicionar referência do muuntaja
(require '[muuntaja.middleware :as middleware])
- Adicionar uma rota complexa
(require '[compojure.core :refer :all])
(defroutes my-routes
(GET "/estruturada" request
{:body {:a 1
:b #{1 2}
:c "outra coisa"}}))
- rodar o app
(require '[ring.adapter.jetty :refer [run-jetty]])
(run-jetty (middleware/wrap-format my-routes) {:port 8080 :join? false})
$ curl -i http://localhost:8080/estruturada
$ curl -i http://localhost:8080/estruturada -H "accept: application/edn"
Emacs:
(server
(:require [compojure.core :refer [defroutes DELETE GET PUT]]
[compojure.route :as route]))
(def db (atom {}))
(defroutes service-routes
(GET "/entidade" request
{:body
(when-let [entidade (@db :data)])})
(PUT "/entidade" request
(swap! db assoc :data (:body-params request))
{:status 201})
(DELETE "/enntidade" request
(swap! db dissoc :data))
(route/not-found "Not found"))