-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update getting started to match latest edge #247
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,102 +15,110 @@ First let's clone the project and change into its working directory. | |
|
||
.... | ||
git clone https://github.com/juxt/edge | ||
cd edge/app | ||
cd edge/ | ||
.... | ||
|
||
=== Create our own app | ||
|
||
.... | ||
./bin/app yada.manual/app | ||
cd yada.manual.app | ||
.... | ||
|
||
=== Build & Run | ||
|
||
Next we build and run it, in _development_ mode. | ||
|
||
.... | ||
clojure -A:dev:build:dev/rebel | ||
../bin/rebel -A:dev | ||
.... | ||
|
||
This can take up to a couple of minutes to build and run from scratch so don't worry if you have to wait a bit before you see anything. | ||
|
||
.... | ||
[Edge] Starting nREPL server | ||
[Edge] nREPL client can be connected to port 5600 | ||
[Edge] Starting development environment, please wait… | ||
WARNING: boolean? already refers to: #'clojure.core/boolean? in namespace: fipp.visit, being replaced by: #'fipp.visit/boolean? | ||
[Rebel readline] Type :repl/help for online help info | ||
[Edge] Loading Clojure code, please wait... | ||
Figwheel: Starting server at http://0.0.0.0:3449 | ||
Figwheel: Watching build - main | ||
Compiling "target/public/edge.js" from ("/home/username/Projects/clj/edge/app/dev" "/home/username/Projects/clj/edge/app/test" "/home/username/Projects/clj/edge/app/aliases/rebel" "/home/username/Projects/clj/edge/app/src" "/home/username/Projects/clj/edge/app/sass" "/home/username/Projects/clj/edge/app/resources" "/home/username/Projects/clj/edge/app/assets" "/home/username/.gitlibs/libs/io.dominic/krei.alpha/02d0675365d76e81cd2392e7f397e6f278e2a118/src")... | ||
Successfully compiled "target/public/edge.js" in 3.472 seconds. | ||
Figwheel: Starting CSS Watcher for paths ["target"] | ||
[Edge] Now enter (go) to start the dev system | ||
dev=> | ||
user=> | ||
.... | ||
|
||
=== Start the Server | ||
At the 'dev=>' prompt enter '(go)' to start a server listening by default on port 3000. | ||
At the 'user=>' prompt enter '(dev)', then '(go)' to start a server listening by default on port 3000. | ||
|
||
.... | ||
user=> (dev) | ||
[Edge] Loading Clojure code, please wait... | ||
[Edge] Enter (go) to start the dev system | ||
#object[clojure.lang.Namespace 0x7b598d05 "dev"] | ||
dev=> (go) | ||
[Edge] Website can be browsed at http://localhost:3000/ | ||
[Edge] Website listening on: http://localhost:3000 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The generated app defaulted to http://localhost:7272 |
||
[Edge] Now make code changes, then enter (reset) here | ||
:started | ||
:initiated | ||
.... | ||
|
||
=== Browse | ||
|
||
Fire up a browser and browse to http://localhost:3000/hello. You should see a simple `Hello World` message. | ||
Fire up a browser and browse to http://localhost:3000/. You should see a simple `Hello, app!` message. | ||
|
||
=== Working with the REPL | ||
|
||
We're going to start changing some of Edge's source code soon, and when we do that we'll type `(reset)` on our REPL. So let's try that now. | ||
|
||
.... | ||
dev=> (reset) | ||
:reloading (io.dominic.krei.alpha.impl.util io.dominic.krei.alpha.core edge.phonebook.db edge.lacinia edge.phonebook-app edge.selmer edge.test.system edge.phonebook edge.sources edge.hello edge.examples edge.web-server edge.system edge.examples-test edge.system-test edge.main dev user io.dominic.krei.alpha.main edge.rebel.main edge.api-test) | ||
:reloading (edge.bidi.ig yada.manual.app.foo edge.system edge.system.meta edge.yada.ig dev-extras dev user) | ||
:resumed | ||
dev=> | ||
dev=> | ||
.... | ||
|
||
=== Test the service | ||
|
||
Let's send an HTTP request to the system to check it is working. We can use a browser to visit http://localhost:3000/hello or use `curl` if you have it installed on your system: | ||
Let's send an HTTP request to the system to check it is working. We can use a browser to visit http://localhost:3000/ or use `curl` if you have it installed on your system: | ||
|
||
.... | ||
curl http://localhost:3000/hello | ||
curl http://localhost:3000/ | ||
.... | ||
|
||
The result should be the same: | ||
|
||
.... | ||
Hello World! | ||
Hello, app! | ||
.... | ||
|
||
=== Locate the source code | ||
|
||
Fire up an editor and load up the file `src/edge/hello.clj`. | ||
Fire up an editor and load up the file `src/yada/manual/app/foo.clj`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My app had the file src/yada/manual/app/core.clj generated |
||
|
||
Locate the function called `hello-routes`. This returns a simple route structure that matches on the URI paths of incoming HTTP requests. | ||
Locate the function called `string-resource`. | ||
This returns a simple yada resource which serves a string. | ||
|
||
[source,clojure] | ||
---- | ||
(defn hello-routes [_] | ||
["/hello" (yada/handler "Hello World!\n")]) | ||
(defn string-resource | ||
[x] | ||
(yada/as-resource x)) | ||
---- | ||
|
||
Make a change to string `"Hello World!"`, for example, change it to `"Hello Wonderful World!"`. | ||
|
||
It receives the string to serve from config. | ||
Open the file `src/config.edn`, and find the key `:yada.manual.app.foo/string`. | ||
Change `"Hello, app!"` to a message of your choice. | ||
For example, change it to `"Hello Wonderful World!"`. | ||
|
||
=== Reset the system | ||
|
||
Now we've made a change to Edge's source code, we must tell the system to reset. The system will then detect all the code changes and necessary dependencies to reload. | ||
|
||
.... | ||
dev=> (reset) | ||
:reloading (io.dominic.krei.alpha.impl.util io.dominic.krei.alpha.core edge.phonebook.db edge.lacinia edge.phonebook-app edge.selmer edge.test.system edge.phonebook edge.sources edge.hello edge.examples edge.web-server edge.system edge.examples-test edge.system-test edge.main dev user io.dominic.krei.alpha.main edge.rebel.main edge.api-test) | ||
:reloading () | ||
:resumed | ||
dev=> | ||
dev=> | ||
.... | ||
|
||
Let's test the service again: | ||
|
||
.... | ||
$ curl http://localhost:3000/hello | ||
$ curl http://localhost:3000/ | ||
.... | ||
|
||
You should now see that the change has been made: | ||
|
@@ -120,5 +128,3 @@ Hello Wonderful World! | |
.... | ||
|
||
Congratulations. You're all up and running with a project built with [yada]#yada#. This will make a great lab to try out your own [yada]#yada# experiments and see what is possible. | ||
|
||
Browse to http://localhost:3000 and have fun! |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,22 +3,16 @@ | |
|
||
In this chapter we examine the "Hello World!" resource in depth. If you have followed the <<getting-started,Getting Started>> chapter, you'll be up and running and ready to try the examples yourself, but it's up to you. | ||
|
||
Let's look at the route definition in the file `src/edge/hello.clj` (the same one we saw in the Getting Started chapter). This function returns a *route structure*. The simplest route structure is a pair of elements contained in a vector. | ||
Let's look at the route definition in the file `src/yada/manual/app/foo.clj` (the same one we saw in the Getting Started chapter). This function returns a *yada resource*. | ||
|
||
[source,clojure] | ||
---- | ||
(defn hello-routes [deps] | ||
["/hello" <1> | ||
(yada/handler "Hello World!\n") <2> | ||
]) | ||
(defn string-resource | ||
[x] | ||
(yada/as-resource x)) | ||
---- | ||
|
||
<1> The first element is a path (or pattern) which matches on the URI's path when handling HTTP requests. | ||
<2> The second element is often a handler function (but can be another route structure, recursively). | ||
|
||
In this route structure, any incoming request with a path of `/hello` gets sent to the [yada]#yada# handler defined by `(yada/handler "Hello World!\n")`. | ||
|
||
Let's focus on this handler. We could have used a standard Ring function `(fn [req] {…})` here but instead we created one with `yada/handler`, which takes a *resource* and turns it into a handler function. | ||
Any incoming request which is directed to this *resource* gets sent to the [yada]#yada# handler defined by `(yada/start-server)` when it encounters a *resource*. | ||
|
||
A *resource* is a Clojure map (or more accurately, a Clojure record) that completely describes the methods, properties, representations, security and other miscellaneous properties of a web resource, as data. The reason we can use a string (`"Hello World"`) here is because [yada]#yada# contains logic to _coerce_ a string into a resource. | ||
|
||
|
@@ -29,7 +23,7 @@ NOTE: There are a number of built-in coercions from various Clojure types and of | |
Let's send a request which gets routed to our handler, which creates the response. Let's examine this response in more detail, via *curl*. | ||
|
||
.... | ||
$ curl -i http://localhost:3000/hello | ||
$ curl -i http://localhost:3000/ | ||
.... | ||
|
||
TIP: The `-i` option to *curl* shows us the HTTP status and response headers as well as the body, which is very useful for debugging. If you ever need to see the request headers too, add `-v`. | ||
|
@@ -66,10 +60,10 @@ Last-Modified: Sun, 09 Aug 2015 07:25:10 GMT | |
ETag: fa863bd7ff53786d286e4bb3c0134416 | ||
.... | ||
|
||
The `Last-Modified` header shows when the string `Hello World!` was created, which happens to be the last time the system was started (or reset). Java strings are immutable, so [yada]#yada# is able to deduce that the | ||
The `Last-Modified` header shows when the string `Hello Wonderful World!` was created, which happens to be the last time the system was started (or reset). Java strings are immutable, so [yada]#yada# is able to deduce that the | ||
string's creation date is also the last time it could have been modified. | ||
|
||
The entity tag is computed from the value of the `Hello World!` itself. Unlike the `Last-Modified` value, it can survive a reset. | ||
The entity tag is computed from the value of the `Hello Wonderful World!` itself. Unlike the `Last-Modified` value, it can survive a reset. | ||
|
||
Both `Last-Modified` and `ETag` are used to support HTTP conditional requests and conflict detection when uploading new versions of a resource. | ||
|
||
|
@@ -99,7 +93,7 @@ This value is in bytes, regardless of the charset. It includes the newline. | |
Finally we see our response body. | ||
|
||
.... | ||
Hello World! | ||
Hello Wonderful World! | ||
.... | ||
|
||
[[a-conditional-request]] | ||
|
@@ -114,7 +108,7 @@ We can test this by setting the *If-Modified-Since* header in the request. | |
Here's how we might do this using the *curl* command. | ||
|
||
.... | ||
$ curl -i http://localhost:3000/hello -H "If-Modified-Since: Mon, 1 Jan 2525 00:00:00 GMT" | ||
$ curl -i http://localhost:3000/ -H "If-Modified-Since: Mon, 1 Jan 2525 00:00:00 GMT" | ||
.... | ||
|
||
Of course, nobody will have modified the resource _since_ the year 2525, so we should get a 304 response, telling us we can use our cached copy: | ||
|
@@ -142,7 +136,7 @@ The responses we have received back from our service all contain this curious he | |
Let's try getting the string in UTF16 by telling the server that's the only charset we'll accept: | ||
|
||
.... | ||
curl -i http://localhost:3000/hello -H "Accept-Charset: UTF-16" | ||
curl -i http://localhost:3000/ -H "Accept-Charset: UTF-16" | ||
.... | ||
|
||
This returns the following: | ||
|
@@ -169,7 +163,7 @@ The "Hello World!" message is prepended with 2 bytes called the *Byte Order Mark | |
A BOM indicates the order that the 2 bytes are transmitted in. In 'big endian' form the most-significant byte is transmitted first. We can tell the service that we only want the big endian form with the following: | ||
|
||
.... | ||
curl -i http://localhost:3000/hello -H "Accept-Charset: UTF-16BE" | ||
curl -i http://localhost:3000/ -H "Accept-Charset: UTF-16BE" | ||
.... | ||
|
||
This will now produce the message without the BOM, because it is unnecessary. This means our `Content-Length` will be exactly 13 * 2 = 26. | ||
|
@@ -205,23 +199,52 @@ This calls for a different implementation: | |
[source,clojure] | ||
---- | ||
(defn hello-language [] | ||
["/hello-language" | ||
(yada/resource <1> | ||
(yada/resource ; <1> | ||
{:methods | ||
{:get <2> | ||
{:get ; <2> | ||
{:produces | ||
{:media-type "text/plain" | ||
:language #{"en" "zh-ch;q=0.9"}} <3> | ||
:language #{"en" "zh-ch;q=0.9"}} ; <3> | ||
:response | ||
#(case (yada/language %) <4> | ||
#(case (yada/language %) ; <4> | ||
"zh-ch" "你好世界\n" | ||
"en" "Hello World!\n")}}})]) | ||
"en" "Hello World!\n")}}})) | ||
|
||
; <5> | ||
(defmethod ig/init-key ::hello-language | ||
[_ _] | ||
(hello-language)) | ||
---- | ||
|
||
<1> Using the `yada/resource` function to create a custom resource | ||
<2> The resource has a single method, GET | ||
<3> English is preferred, but Simplified Chinese is available too | ||
<4> This is a function that is given a *context* as the first argument. The `yada/language` convenience function pulls out the negotiated language from this context | ||
<5> Integrate this yada resource with integrant, our system manager. | ||
|
||
We also need to update our config.edn to serve this new path. | ||
|
||
[source,clojure] | ||
---- | ||
:yada.manual.app.foo/hello-language nil ; <1> | ||
:edge.bidi.ig/vhost [["http://localhost:3000" | ||
["" | ||
[["/" #ig/ref :yada.manual.app.foo/string] | ||
; <2> | ||
["/hello-language" #ig/ref :yada.manual.app.foo/hello-language]]]]] | ||
---- | ||
|
||
<1> Initialise our hello-language component | ||
<2> Refer to our new resource under the `"/hello-language"` route. Our route is a pair in a vector of `[<path>, <resource>]`. | ||
|
||
This is the last time we'll bother you with this, but you need to tell Clojure to reload your code changes. | ||
Open your REPL and enter `(reset)`. | ||
|
||
.... | ||
dev=> (reset) | ||
:reloading (yada.manual.app.foo) | ||
:resumed | ||
.... | ||
|
||
Let's test this by providing a request header which indicates a preference for simplified Chinese: | ||
|
||
|
@@ -256,7 +279,7 @@ There's a lot more to content negotiation than this simple example can show. It | |
Let's try to overwrite the string by using a `PUT`. | ||
|
||
.... | ||
$ curl -i http://localhost:3000/hello -X PUT -d "Hello Wonderful World!%0a" | ||
$ curl -i http://localhost:3000/ -X PUT -d "Hello Wonderful World!%0a" | ||
.... | ||
|
||
The response is as follows: | ||
|
@@ -274,7 +297,7 @@ Date: Mon, 27 Jun 2016 08:56:58 GMT | |
The response status is `405 Method Not Allowed`, telling us that our request was unacceptable. There is also an *Allow* header, telling us which methods are allowed. One of these methods is OPTIONS, which we could have used to check whether PUT was available without actually attempting it. | ||
|
||
.... | ||
$ curl -i http://localhost:3000/hello -X OPTIONS | ||
$ curl -i http://localhost:3000/ -X OPTIONS | ||
.... | ||
|
||
The response should be: | ||
|
@@ -384,7 +407,7 @@ There was one more method indicated by the *Allow* header of our `OPTIONS` reque | |
TIP: Use the option --head to *curl* to tell it to issue a HEAD request (and not to expect a request body). | ||
|
||
.... | ||
$ curl -i --head http://localhost:3000/hello | ||
$ curl -i --head http://localhost:3000/ | ||
.... | ||
|
||
|
||
|
@@ -453,9 +476,15 @@ Great! | |
|
||
As well as query parameters, yada supports path parameters, request headers, form data, cookies and request bodies. You can have optional parameters, in fact, anything that can be expressed in Plumatic Schema, and [yada]#yada# will even coerce parameters to a range of types. For more details, see the <<parameters-chapter,parameters chapter>>. | ||
|
||
//// | ||
[[hello-swagger]] | ||
=== Hello Swagger! | ||
|
||
[WARNING] | ||
==== | ||
Swagger is not set up this easily in edge any more, this section is out of date. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bummer. This was the part I was interested in |
||
==== | ||
|
||
Now we have seen how to build a single web resource, let's see how to build a ((Swagger)) description from a collection of web resources. | ||
|
||
In your editor, switch to `src/edge/web_server.clj`. This file defines the overall route structure which includes our routes for "Hello World!". This has been included twice, both at the root and under the `/api` path. | ||
|
@@ -544,6 +573,7 @@ It's these little details that [yada]#yada# takes care of for you. There is no t | |
By the way, if you want to see the Swagger UI, browse to http://localhost:3000/swagger/?url=http://localhost:3000/api/swagger.json | ||
|
||
image:hello-swagger.png[Swagger] | ||
//// | ||
|
||
[[summary]] | ||
=== Summary | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,10 +22,8 @@ want to set up a quick development environment. | |
[[the-easy-way-clone-edge]] | ||
=== The Easy Way: Clone edge | ||
|
||
The quickest and perhaps easiest way to get started is to clone the [yada]#yada# | ||
branch of JUXT's *edge* repository. This is a continuously improving | ||
development environment representing our firm's best advice for building | ||
Clojure projects. | ||
The quickest and perhaps easiest way to get started is to clone JUXT's *edge* repository. | ||
This is a continuously improving development environment representing our firm's best advice for building Clojure projects. | ||
|
||
.... | ||
$ git clone [email protected]/juxt/edge | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This didn't exist for my version. I got
Syntax error compiling at (REPL:1:1)