Here I will build an example of om.next end to end app with frontend
communicating with backend both using clojure.
The repository is here: gh:marianoguerra-atik/om-next-e2e, each commit is one step
here, some commits are simple changes that I don't cover here.
Click on the links to go to the diff of that specific part.
Setup
Start by creating a new clojure project with leiningen:
lein new om-next-e2e
Basic Logging and HTTP Server
Jump to this commit with:
git checkout 32842e95abc4960b32488a51110fe7d7e385be88
To test run:
lein run
You should see:
14:55:22.179 [main] INFO om-next-e2e.core - Starting Server at
localhost:8080/
14:55:22.778 INFO [org.projectodd.wunderboss.web.Web] (main) Registered
web context /
On another terminal using httpie (httpie.org):
$ http get localhost:8080/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 12
Date: Thu, 26 Nov 2015 13:55:24 GMT
Server: undertow
Hello world!
Basic Routing with Bidi
This handlers (action and query) just return 200 and the body with some extra
content.
Jump to this commit with:
git checkout 03b95c397b1c7d21cafe7a9a21efebc7df5b6b41
Let's try it, first let's try the not found handler:
$ http get localhost:8080/lala
HTTP/1.1 404 Not Found
Content-Length: 9
Server: undertow
Not Found
Let's check that doing get on a route that handles only post returns 404 (for REST purists it should be 405, I know):
$ http get localhost:8080/action
HTTP/1.1 404 Not Found
Content-Length: 9
Server: undertow
Not Found
Let's send some content to action as json for now:
$ http post localhost:8080/action name=lala
HTTP/1.1 200 OK
Content-Length: 24
Server: undertow
action: {"name": "lala"}
And query:
$ http post localhost:8080/query name=lala
HTTP/1.1 200 OK
Content-Length: 30
Server: undertow
query action: {"name": "lala"}
Use Transit for Requests and Responses
Jump to this commit with:
git checkout 56d8d2e615e7f499c9dbeaa1d1479a0f39dc1950
From here on I will use a tool I created called transito written in python since writing and
reading transit is not fun I created a tool to translate to and from json,
transit and edn, here I use edn since it's more readable and is what we will
use in our om.next frontend, you can install it with:
sudo pip install transito
Send an action:
$ echo '(start {:id "id2"})' | transito http post http://localhost:8080/action e2t -
Status: 200
Content-Type: application/transit+json
Content-Length: 60
Server: undertow
{:action (start {:id "id2"})}
The response is translated from transit to edn, the actual response can be seen
using something like curl:
curl -X POST http://localhost:8080/action -d '["~#list",["~$start",["^ ","~:id","id2"]]]'
["^ ","~:action",["~#list",["~$start",["^ ","~:id","id2"]]]]
You can get the body you want translated to transit like this:
echo '(start {:id "id2"})' | transito e2t -
["~#list",["~$start",["^ ","~:id","id2"]]]
Let's try the not found handler (notice we are sending to actiona instead of action):
$ echo '(start {:id "id2"})' | transito http post http://localhost:8080/actiona e2t -
Status: 404
Content-Type: application/transit+json
Content-Length: 28
Server: undertow
{:error "Not Found"}
Now let's test the query endpoint:
$ echo '(tasks {:id "id2"})' | transito http post http://localhost:8080/query e2t -
Status: 200
Content-Type: application/transit+json
Content-Length: 59
Server: undertow
{:query (tasks {:id "id2"})}
Supporting Actions and Queries
At this point we need to support the same mutations and reads as the frontend,
to do this we need to add the om.next dependency, I'm using om next alpha25 SNAPSHOT,
here is the way to install the exact version I'm using:
git clone https://github.com/omcljs/om.git
cd om
git checkout 34b9a614764f47a022ddfaf2e469d298d7605d44
lein install
Then:
Jump to this commit with:
git checkout f9ac70c18c89ecbe336c736ef266c17ee1ef8eab
Now let's test it.
Increment by 20:
$ echo '(increment {:value 20})' | transito http post http://localhost:8080/action e2t -
Status: 200
Content-Type: application/transit+json
Content-Length: 44
Server: undertow
{:value {:keys [:count]}}
Get current count:
$ echo '[:count]' | transito http post http://localhost:8080/query e2t -
Status: 200
Content-Type: application/transit+json
Content-Length: 19
Server: undertow
{:count 20}
Increment by 1:
$ echo '(increment {:value 1})' | transito http post http://localhost:8080/action e2t -
Status: 200
Content-Type: application/transit+json
Content-Length: 44
Server: undertow
{:value {:keys [:count]}}
Get current count:
$ echo '[:count]' | transito http post http://localhost:8080/query e2t -
Status: 200
Content-Type: application/transit+json
Content-Length: 19
Server: undertow
{:count 21}
Try getting something else to try the :default handler:
$ echo '[:otherthing]' | transito http post http://localhost:8080/query e2t -
Status: 200
Content-Type: application/transit+json
Content-Length: 6
Server: undertow
{}
Try an inexistent action to try the :default handler:
$ echo '(somethingelse {:value 1})' | transito http post http://localhost:8080/action e2t -
Status: 404
Content-Type: application/transit+json
Content-Length: 84
Server: undertow
{:params {:value 1}, :key somethingelse, :error "Not Found"}