juxt.pro - yada









Search Preview

The yada manual

juxt.pro
A manual explaining yada, an HTTP library for Clojure from JUXT.
.pro > juxt.pro

SEO audit: Content analysis

Language Error! No language localisation is found.
Title The yada manual
Text / HTML ratio 59 %
Frame Excellent! The website does not use iFrame solutions.
Flash Excellent! The website does not have any flash contents.
Keywords cloud resource yada request response HTTP function resources parameters methods method coming web Swagger handler data entry user return Clojure
Keywords consistency
Keyword Content Title Description Headings
resource 149
yada 142
request 92
response 90
HTTP 70
function 60
Headings
H1 H2 H3 H4 H5 H6
4 31 88 58 0 0
Images We found 3 images on this web page.

SEO Keywords (Single)

Keyword Occurrence Density
resource 149 7.45 %
yada 142 7.10 %
request 92 4.60 %
response 90 4.50 %
HTTP 70 3.50 %
function 60 3.00 %
53 2.65 %
resources 49 2.45 %
parameters 48 2.40 %
methods 46 2.30 %
method 45 2.25 %
coming 45 2.25 %
web 43 2.15 %
Swagger 38 1.90 %
handler 35 1.75 %
data 33 1.65 %
entry 32 1.60 %
user 30 1.50 %
return 29 1.45 %
Clojure 29 1.45 %

SEO Keywords (Two Word)

Keyword Occurrence Density
of the 78 3.90 %
in the 75 3.75 %
can be 61 3.05 %
coming soon 45 2.25 %
the resource 43 2.15 %
a resource 42 2.10 %
to the 41 2.05 %
is a 37 1.85 %
of a 30 1.50 %
the request 28 1.40 %
with a 27 1.35 %
it is 24 1.20 %
on the 24 1.20 %
Hello World 24 1.20 %
with the 23 1.15 %
the response 23 1.15 %
will be 23 1.15 %
you can 22 1.10 %
such as 21 1.05 %
in a 21 1.05 %

SEO Keywords (Three Word)

Keyword Occurrence Density Possible Spam
Connection KeepAlive Date 14 0.70 % No
HTTP11 200 OK 12 0.60 % No
Server Aleph041 Connection 12 0.60 % No
of the resource 12 0.60 % No
Aleph041 Connection KeepAlive 12 0.60 % No
a number of 12 0.60 % No
in the request 11 0.55 % No
that can be 11 0.55 % No
1 mode=block XContentTypeOptions 10 0.50 % No
mode=block XContentTypeOptions nosniff 10 0.50 % No
XFrameOptions SAMEORIGIN XXSSProtection 10 0.50 % No
SAMEORIGIN XXSSProtection 1 10 0.50 % No
XXSSProtection 1 mode=block 10 0.50 % No
the request context 9 0.45 % No
can be used 8 0.40 % No
XContentTypeOptions nosniff ContentLength 7 0.35 % No
the resource is 7 0.35 % No
you want to 7 0.35 % No
part of the 7 0.35 % No
that will be 7 0.35 % No

SEO Keywords (Four Word)

Keyword Occurrence Density Possible Spam
Server Aleph041 Connection KeepAlive 12 0.60 % No
Aleph041 Connection KeepAlive Date 12 0.60 % No
SAMEORIGIN XXSSProtection 1 mode=block 10 0.50 % No
XXSSProtection 1 mode=block XContentTypeOptions 10 0.50 % No
1 mode=block XContentTypeOptions nosniff 10 0.50 % No
XFrameOptions SAMEORIGIN XXSSProtection 1 10 0.50 % No
mode=block XContentTypeOptions nosniff ContentLength 7 0.35 % No
OK XFrameOptions SAMEORIGIN XXSSProtection 6 0.30 % No
200 OK XFrameOptions SAMEORIGIN 6 0.30 % No
HTTP11 200 OK XFrameOptions 6 0.30 % No
Tue 05 Jul 2016 5 0.25 % No
Connection KeepAlive Date Mon 5 0.25 % No
that will be called 5 0.25 % No
KeepAlive Date Mon 27 5 0.25 % No
Wed 22 Jun 2016 5 0.25 % No
can be found in 4 0.20 % No
you might want to 4 0.20 % No
methods get response fn 4 0.20 % No
an example of a 4 0.20 % No
Date Tue 05 Jul 4 0.20 % No

Internal links in - juxt.pro

Home
JUXT: Delivering Innovation
Delivery
JUXT: How We Deliver
Training
JUXT: JUXT Training Courses
Compliance
JUXT: Compliance
Blog
JUXT: The JUXT Blog
Why JUXT?
JUXT: Why JUXT?
Why Clojure?
JUXT: Why Clojure?
Clojure In
JUXT: Clojure In - Reference Clojure case studies from across Europe
Tech Radar
JUXT: Radar
Library
JUXT: Delivering Innovation
edge
The Edge Manual
tick
tick
yada
The yada manual
About Us
JUXT: About Us
Clients
JUXT: Clients
Team
JUXT: JUXTers
Careers
JUXT: Join JUXT
Community
JUXT: Community
Contact
JUXT: Contact
OnTheMarket.com and JUXT
JUXT: Blog: OnTheMarket.com and JUXT
Trading Dashboards for Tier-One Banking
JUXT: Blog: Trading Dashboards for Tier-One Banking
Building a Bitemporal Data-Store
JUXT: Blog: Building a Bitemporal Data-Store
Deploying libraries with deps.edn
JUXT: Blog: Deploying libraries with deps.edn
Testable Clojurescript apps
JUXT: Blog: Testable Clojurescript apps
Just a techie?
JUXT: Blog: Just a techie?
Login
JUXT:

Juxt.pro Spined HTML


The yada transmission ☰ Services HomeWordageTraining Compliance Resources Blog Why JUXT? Why Clojure? Clojure In Tech Radar Library Tech crux whet tick yadaWell-nighAbout Us Clients Team Careers Community Contact The yada transmission Malcolm Sparks malcolm@juxt.pro version 1.2.0, January 2017 Table of Contents Preface Basics 1. Introduction 1.1.Diamondgoals 1.2. Say Hello! to yada 1.3. Resources 1.4. Serving requests 1.5. Conclusion 2. Getting Started 2.1. Clone 2.2. Build & Run 2.3. Start the Server 2.4.Scan2.5. Working with the REPL 2.6. Test the service 2.7. Locate the source lawmaking 2.8. Reset the system 3. Hello World! 3.1. Examining the response 3.2. A provisionary request 3.3. Content negotiation 3.4. Mutation 3.5. A HEAD request 3.6. Parameters 3.7. Hello Swagger! 3.8. Summary 4. Installation 4.1. Setting up a minutiae environment 4.2. The Easy Way: Clone whet 4.3. The Simple Way: Construct your own 4.4. REPL and Testing 5. Resources 5.1. Resource models 5.2. Resources as Ring handlers 5.3. Resource types 6. Parameters 6.1. Capturing multi-value parameters 6.2. Capturing large request persons 7. Properties 8. Methods 8.1. Method semantics, by method 8.2. GET 8.3. PUT 8.4. POST 8.5. DELETE 8.6. HEAD 8.7. OPTIONS 8.8. TRACE 8.9. PATCH 8.10. Handling all methods 8.11. Custom methods 8.12. BREW 9. Representations 9.1. Producing content 9.2. Proactive negotiation 9.3. Reactive negotiation 9.4. The Vary response header 9.5.Soulurgency 9.6. Consuming content 10. Responses 10.1. Explicit responses 10.2.Supposedresponses 10.3. Status responses 11. Security 11.1. Security is part of the resource, not the route 11.2. The :access-control entry 11.3.Hallmark11.4.Passport11.5. Realms 11.6. Cross-Origin Resource Sharing (CORS) 11.7. HTTP Strict Transport Security (HSTS) 11.8. Content Security Policy 11.9. Clickjacking prevention 11.10. Cross-site Scripting (XSS) protection 11.11. Media-type sniffing protection 12. Routing 12.1. Declaring your website or API as a bidi/yada tree 12.2. Declaring policies wideness multiple resources 13. Example 2: Phonebook 13.1. Phonebook requirements 13.2. The database 13.3. Creating new phonebook entries 14. Swagger 14.1. Creating the specification: the easy way 14.2. The Swagger UI 14.3. Resource options 14.4. Swagger and REST 14.5. Data descriptions of APIs 14.6. ReferencesWidetopics 15. Async 15.1. Deferred values 16. Example 3: Search engine 17. Server Sent Events 17.1. Introduction 17.2. SSE with yada 18. Example 4: Chat server 19. Handling request persons 20. Example 5: Selfie uploader 21. Handlers 22. The Request Context 22.1. path-for 23. Interceptors 23.1.Cadreinterceptors 23.2. Modifying interceptor villenage 24. Sub-resources 24.1. Declaring sub-resources 24.2. Path info 25. Example 6: File server 26. Testing Reference Glossary Appendix A: Reference A.1. Resource model schema A.2. Handler schema A.3. Request context schema A.4. Protocols A.5.Seatedtypes Bibliography Colophon HTML PDF Preface State is everywhere. The world is moving and we need to alimony up. We need our computers to help us stay up-to-date with the latest information, chats, trends, stock-prices, news and weather updates, and other important stuff. The web is primarily a ways to move state around. You have some state here, and you want it over there. Or it’s over there, but you want it over here. For two decades or more, the pre-dominant model for web programming has ignored state, instead requiring developers to work at the level of the HTTP protocol itself. For example, in Java: public void handleRequest(HttpServletRequest request, HttpServletResponse response) { response.setStatus(200); } or in Clojure (fn [request] {:status 200}) This programming model puts the HTTP request and response at centre stage. The concept of state is missing entirely - the resource is seen merely as an operation (or set of operations) misogynist for remote invocation. For years, the same RPC-centered tideway has been copied by web frameworks in many languages, old and new (Python, Ruby, Go, Clojure, Rust…​). It has survived considering it’s so flexible, as many low-level programming models are. But there are significant downsides to this model too. HTTP is a big specification, and it’s unreasonable to expect developers to have the time to implement all the relevant pieces of it. What’s more, many developers tend to implement much the same lawmaking over and over again, for each and every operation they write. A notable throw-away from this programming model can be found in Erlang’s WebMachine and Clojure’s Liberator. To a degree, these libraries ease the undersong on the developer by orchestrating the steps required to build a response to a web request. However, developers are still required to understand the state transition diagram underlying this orchestration if they are to successfully exploit these libraries to the maximum extent. Fundamentally, the programming model is the same: the developer is still writing lawmaking with a view to forming a response at the protocol level. While this model has served us well in the past, there are increasingly important reasons why we need an upgrade. Rather than mere playthings, HTTP-based APIs are rhadamanthine hair-trigger components in virtually every organisation. With supporting infrastructure such as proxies, API gateways and monitoring, there has never been a greater need to modernize compatibility through largest conformance with HTTP standards. Yet many APIs today at weightier ignore, and at worst violate many parts of the HTTP standard. For unnoticeable prototypes, this unstudied tideway to HTTP is acceptable. Yet HTTP is designed for long-lived systems with lifetimes measured in decades, that must navigate departmental and organisational boundaries, while adapting to ongoing changes in technology. It’s time for a fresh approach. We need our libraries to do increasingly work for us. For this to happen, we need to move from the de-facto operational view of web services to a strong data-oriented approach, focussing on what a web resource is really about: state. Basics 1. Introduction yada is a web library for Clojure that lets you pinpoint websites and web APIs using data. Despite some differences, virtually all web libraries do a similar thing: undeniability your lawmaking with some request data and ask you to return a response, leaving the zillion of the responsibililty for implementing the HTTP standards in your hands: responding with the correct status codes, response headers and ensuring semantics have been followed properly. yada is different. Rather than leaving all the implementation details to you, it helps you out in doing the right thing (according to HTTP standards), thereby creating a largest web [1]. It achieves this by providing you with a highly-configurable handler that is unstipulated unbearable to use in the vast majority of cases. Rather than coding the handler, the developer only has to configure one. This declarative tideway provides greater telescopic for accuracy, consistency and re-use. yada represents a unravel from the traditional yet stale method of towers web backends, an tideway that can trace its roots all the way when to the days ofWorldwideGateway Interface. While yada's data-oriented tideway takes full wholesomeness of the data-oriented philosophy of Clojure, there’s no reason why this methodology cannot be implemented by new web libraries in other languages. Using yada for your web project will indulge you to finally exploit and goody from the many features typified in the outstanding diamond of HTTP, for scale, flexibility, security, longevity and interoperability. 1.1.Diamondgoals yada is designed to meet the pursuit goals: Be easy to use for intermediate Clojure developers Comprehensive compliance with HTTP standards over pragmatism and performance Increase productivity through re-use Handle large workloads with reasonable performance Support multiple architectural styles, including Hypermedia APIs (REST) yada is not an experiment. It is designed for, and has been tested in, production environments. yada is sufficiently quick-and-easy for quick prototype work but scales up when you need it to, to feature-rich secure services that can handle the most taxing workloads, while remaining true-blue to the HTTP standards. Some familiarity with HTTP will help you understand yada concepts quicker, but isn’t veritably necessary. As you learn how to wield yada you will moreover discover and learn increasingly well-nigh the HTTP standards as you go. 1.2. Say Hello! to yada It’s quick to get started with yada without knowing how it works - it’s easy to get started plane if you only have a vital knowledge of Clojure. Let’s uncork with a few examples. The obligatory Hello World! example is (yada/handler "Hello World!"), which responds with a message. Perhaps you might want to serve a file? That’s (yada/handler (new java.io.File "index.html")). Now you know how to serve a file, you know how to serve a directory. But perhaps you’ve got some resources on the classpath? (yada/handler (clojure.java.io/resource "talks/")). What well-nigh (yada/handler nil)? Without knowing, can you guess what that might do? (That’s right, it produces a 404 Not Found response). What well-nigh a quick dice generator? (yada/handler #(inc (rand-int 6))). Notice we use a function here, rather than a unvarying value, to vary numbers between rolls. How well-nigh streaming those dice rolls as Server Sent Events? Put those dice rolls on a core.async channel, and return it with yada. All these examples demonstrate the use of Clojure types that are converted on-the-fly into yada resources, and you can create your own types too. Let’s delve a little deeper… 1.3. Resources In yada, resources are specified by a plain-old Clojure map. This has many benefits. While functions are opaque, data is unshut to inspection. Data structures are easy to generate, transform and query - chores that Clojure makes light work of. Here’s an example of a resource: (yada/resource {:properties {…} :methods {:get {:response (fn [ctx] "Hello World!")} :put {…} :brew {…}} … }) There’s a lot of things you can do with a resource data model but perhaps the most obvious is to create a request handler from it to create responses from HTTP requests. That’s the role of a handler. With yada, we transform a resource into a handler using the handler function. (require '[yada.yada :as yada]) (yada/handler (yada/resource {…})) A handler can be tabbed as a function, with a single treatise representing an HTTP request. It returns a value representing the respective HTTP response. A yada handler is an instance of the yada.handler/Handler record. Since this record satisfies clojure.lang.IFn, yada handlers behave just like normal Ring handlers and can be used wherever you might use a Ring handler. 1.4. Serving requests To use yada to create real responses to real HTTP requests, you need to add yada to a web-server. The web server takes superintendency of the networking and messages of HTTP (RFC 7230), while yada focuses on the semantics and content ([RFC7231] and upwards). Currently, the only web server you can use is ztellman/aleph. This is considering yada is built on an asynchronous wresting provided by ztellman/manifold. However, there is no technical reason why, in future, other web servers can’t be wrapped by manifold. In the meantime, Aleph (which wraps a much worthier library, Netty) provides a very capable and performant server. To write real applications you moreover need a router that understands URIs, and yada has some features that are enabled when used with juxt/bidi, although there is nothing to stop you using yada with other routing libraries. 1.5. Conclusion That’s yada in a nutshell, but the quickest way to to learn it is to set up an environment and play. That’s what we’ll do in the next chapter. 2. Getting Started In this quick tutorial we’re going to run a real Clojure project, diving into the lawmaking to show how yada is used. Our project is tabbed Edge, a sample project from JUXT to show some of our libraries in action. It lives on GitHub. We’ll clone it first, then build it, then run it, then scan the examples and plane make modifications. So let’s get going! 2.1. Clone First let’s clone the project and transpiration into its working directory. git clone https://github.com/juxt/edge cd edge/app 2.2. Build & Run Next we build and run it, in minutiae mode. clojure -A:dev:build:dev/rebel 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 surpassing you see anything. [Edge] Starting nREPL server [Edge] nREPL vendee can be unfluctuating to port 5600 [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=> 2.3. Start the Server At the dev⇒ prompt enter (go) to start a server listening by default on port 3000. dev=> (go) [Edge] Website can be browsed at http://localhost:3000/ [Edge] Now make lawmaking changes, then enter (reset) here :started 2.4.ScanFire up a browser and scan to http://localhost:3000/hello. You should see a simple Hello World message. 2.5. Working with the REPL We’re going to start waffly some of Edge’s source lawmaking 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) :resumed dev=> 2.6. Test the service Let’s send an HTTP request to the system to trammels it is working. We can use a browser to visit http://localhost:3000/hello or use flourish if you have it installed on your system: flourish http://localhost:3000/hello The result should be the same: Hello World! 2.7. Locate the source lawmaking Fire up an editor and load up the file src/edge/hello.clj. Locate the function tabbed hello-routes. This returns a simple route structure that matches on the URI paths of incoming HTTP requests. (defn hello-routes [_] ["/hello" (yada/handler "Hello World!\n")]) Make a transpiration to string "Hello World!", for example, transpiration it to "Hello Wonderful World!". 2.8. Reset the system Now we’ve made a transpiration to Edge’s source code, we must tell the system to reset. The system will then snift all the lawmaking 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) :resumed dev=> Let’s test the service again: $ flourish http://localhost:3000/hello You should now see that the transpiration has been made: Hello Wonderful World! Congratulations. You’re all up and running with a project built with yada. This will make a unconfined lab to try out your own yada experiments and see what is possible.Scanto http://localhost:3000 and have fun! 3. Hello World! In this installment we examine the "Hello World!" resource in depth. If you have followed the Getting Started chapter, you’ll be up and running and ready to try the examples yourself, but it’s up to you. Let’s squint 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. (defn hello-routes [deps] ["/hello" (1) (yada/handler "Hello World!\n") (2) ]) 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 flipside route structure, recursively). In this route structure, any incoming request with a path of /hello gets sent to the yada handler specified 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. A resource is a Clojure map (or increasingly 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 considering yada contains logic to coerce a string into a resource. There are a number of seated coercions from various Clojure types and of undertow you can provide your own. 3.1. Examining the response Let’s send a request which gets routed to our handler, which creates the response. Let’s examine this response in increasingly detail, via curl. $ flourish -i http://localhost:3000/hello The -i option to flourish shows us the HTTP status and response headers as well as the body, which is very useful for debugging. If you overly need to see the request headers too, add -v. The response should be something like pursuit (note that headers may towards in a variegated order): HTTP/1.1 200 OK Server: Aleph/0.4.1 Connection: Keep-Alive Date: Fri, 17 Jun 2016 16:44:23 GMT Last-Modified: Fri, 17 Jun 2016 16:43:02 GMT ETag: fa863bd7ff53786d286e4bb3c0134416 Content-Type: text/plain;charset=utf-8 Vary: accept-charset Content-Length: 23 X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff The first three response headers are widow by our webserver, Aleph. Server: Aleph/0.4.0 Connection: Keep-Alive Date: Fri, 17 Jun 2016 16:44:23 GMT Next we have flipside stage and a string known as the entity tag: 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 is worldly-wise to deduce that the string’s megacosm stage is moreover 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. Both Last-Modified and ETag are used to support HTTP provisionary requests and mismatch detection when uploading new versions of a resource. Next we have a header telling us the media-type of the string’s representation. Content-Type: text/plain;charset=utf-8 yada is worldly-wise to determine that the media-type is text, but without increasingly information it must default to text/plain. It can moreover tell us the charset, which defaults to the default charset of the JVM (almost unchangingly utf-8) Vary: accept-charset Since the Java platform can encode a string to a number of charsets, yada adds a Vary header to signal to the user-agent (and proxy caches in between) that the soul can transpiration if a request contained a variegated Accept-Charset header. Java installations support many variegated charsets, so yada does too. Next we are given the length of the body. Content-Length: 13 This value is in bytes, regardless of the charset. It includes the newline. Finally we see our response body. Hello World! 3.2. A provisionary request In HTTP, a provisionary request is one where a user-agent (like a browser) can ask a server for the state of the resource but only if a particular condition holds. A worldwide condition is whether the resource has been modified since a particular date, usually considering the user-agent once has a reprinting of the resource’s state which it can use if possible. If the resource hasn’t been modified since this date, the server can tell the user-agent that there is no new version of the state. We can test this by setting the If-Modified-Since header in the request. Here’s how we might do this using the flourish command. $ flourish -i http://localhost:3000/hello -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: HTTP/1.1 304 Not Modified X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Length: 0 Vary: accept-charset ETag: fa863bd7ff53786d286e4bb3c0134416 Server: Aleph/0.4.1 Connection: Keep-Alive Date: Wed, 22 Jun 2016 16:57:46 GMT Notice we moreover get the same Vary and ETag headers. These help any proxies between the user-agent and the service properly enshroud content, and if they would have been produced in a 200 response, then they must moreover be produced in a 304. (This is the kind of thing that yada takes superintendency of for you, unlike most libraries). 3.3. Content negotiation The responses we have received when from our service all contain this curious header tabbed Vary set to accept-charset. The server is telling us (and any proxies between us) that the representation might vary depending on the charset negotiated. Let’s see if we can get our "Hello World!" message returned in other charsets. Let’s try getting the string in UTF16 by telling the server that’s the only charset we’ll accept: flourish -i http://localhost:3000/hello -H "Accept-Charset: UTF-16" This returns the following: HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Length: 28 Content-Type: text/plain;charset=utf-16 Last-Modified: Sun, 26 Jun 2016 11:11:31 GMT Vary: accept-charset ETag: 43b1f79e8efe0fa97c32901fbd5746d6 Server: Aleph/0.4.1 Connection: Keep-Alive Date: Mon, 27 Jun 2016 07:45:07 GMT ��Hello World! The "Hello World!" message is prepended with 2 bytes tabbed the Byte Order Mark (BOM). The length of the string (including the newline) is 13 characters. Since each weft here is 2 bytes, that makes 26. The spare of the BOM makes it 28, which is what our Content-Length header reports. 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: flourish -i http://localhost:3000/hello -H "Accept-Charset: UTF-16BE" This will now produce the message without the BOM, considering it is unnecessary. This ways our Content-Length will be exactly 13 * 2 = 26. HTTP/1.1 200 OK … Content-Length: 26 Hello World! If we were to use UTF-32, which defaults to big-endian, we’ll get a Content-Length of 13 * 4 = 52. HTTP/1.1 200 OK … Content-Length: 52 Hello World! Note moreover that variegated representations generate variegated ETag values. The entity tag is a way of managing a enshroud of representations, not a enshroud of resources. Think of the ETag value as the key you could use in a key/value store that stored a enshroud of representations. The negotiation of charsets may be considered by some to be unnecessary given the dominance of UTF-8. That is certainly true for today’s modern browsers. However, there are many other types of devices that are stuff unfluctuating to the internet (under the imprint Internet of Things). Many of these devices have very tight constraints on processing and memory which prevent them from supporting UTF-8. If we are towers a web service, we may want to connect these devices to it in the future. 3.3.1. Languages Of undertow it is not just charsets that can be negotiated.Flipsideexample is languages. Our "Hello World!" string is in English. Let’s provide support for simplified Chinese. This calls for a variegated implementation: (defn hello-language [] ["/hello-language" (yada/resource (1) {:methods {:get (2) {:produces {:media-type "text/plain" :language #{"en" "zh-ch;q=0.9"}} (3) :response #(case (yada/language %) (4) "zh-ch" "你好世界\n" "en" "Hello World!\n")}}})]) 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 misogynist 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 Let’s test this by providing a request header which indicates a preference for simplified Chinese: $ flourish -i http://localhost:3000/hello-language -H "Accept-Language: zh-CH" We should get the pursuit response: HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Length: 13 Content-Type: text/plain Content-Language: zh-ch Vary: accept-language Server: Aleph/0.4.1 Connection: Keep-Alive Date: Mon, 27 Jun 2016 08:20:59 GMT 你好世界 There’s a lot increasingly to content negotiation than this simple example can show. It is covered in depth in subsequent chapters. 3.4. Mutation Let’s try to overwrite the string by using a PUT. $ flourish -i http://localhost:3000/hello -X PUT -d "Hello Wonderful World!%0a" The response is as follows: HTTP/1.1 405 Method NotUnliableAllow: GET, HEAD, OPTIONS Content-Length: 284 Content-Type: application/json Server: Aleph/0.4.1 Connection: Keep-Alive 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 moreover anIndulgeheader, telling us which methods are allowed. One of these methods is OPTIONS, which we could have used to trammels whether PUT was misogynist without unquestionably attempting it. $ flourish -i http://localhost:3000/hello -X OPTIONS The response should be: HTTP/1.1 200 OK Allow: GET, HEAD, OPTIONS Content-Length: 0 X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Server: Aleph/0.4.1 Connection: Keep-Alive Date: Mon, 27 Jun 2016 09:00:27 GMT Both the PUT and the OPTIONS response contain anIndulgeheader which tells us that PUT isn’t possible. This makes sense, considering we can’t mutate a Java string. We could, however, wrap the Java string in a Clojure whit which could reference variegated Java strings at variegated times. To demonstrate this, try the pursuit with the identifier http://localhost:3000/hello-atom. (yada/as-resource (atom "Hello World!\n")) Let’s try a normal GET. $ flourish -i http://localhost:3000/hello-atom We can now make flipside OPTIONS request to see whether PUT is available, surpassing trying it. $ flourish -i http://localhost:3000/hello-atom -X OPTIONS HTTP/1.1 200 OK Allow: GET, DELETE, HEAD, OPTIONS, PUT Content-Length: 0 X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Server: Aleph/0.4.1 Connection: Keep-Alive Date: Tue, 05 Jul 2016 15:41:36 GMT It is! So let’s try it. $ flourish -i http://localhost:3000/hello-atom -X PUT -d "value=Hello Wonderful World!%0a" And now let’s see if we’ve managed to transpiration the state of the resource. $ flourish -i http://localhost:3000/hello-atom HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Length: 23 Content-Type: text/plain;charset=utf-8 Last-Modified: Tue, 05 Jul 2016 16:08:22 GMT Vary: accept-charset ETag: 3c3e0684be182b7185f6ad10b63f246a Server: Aleph/0.4.1 Connection: Keep-Alive Date: Tue, 05 Jul 2016 16:08:35 GMT Hello Wonderful World! As long as someone else hasn’t sneaked in a variegated state between your PUT and subsequent GET, you should see the new state of the resource is "Hello Wonderful World!". Great! But what if someone did manage to PUT their transpiration superiority of yours? Their version would now be overwritten. That might not be what you wanted. To ensure we don’t override someone’s change, we could have set the If-Match header using the ETag value. Let’s test this now, using the ETag value we got surpassing we sent our PUT request. $ flourish -i http://localhost:3000/hello-atom -X PUT -H "If-Match: fa863bd7ff53786d286e4bb3c0134416" -d "value=Hello Wonderful World!%0a" HTTP/1.1 412 Precondition Failed Content-Length: 196 Content-Type: application/json Server: Aleph/0.4.1 Connection: Keep-Alive Date: Tue, 05 Jul 2016 16:10:53 GMT We get a 412, which ways a pre-condition failed. The pre-condition in question relates to our If-Match header value not matching the current value of the atom. This is a very useful result, considering it ways we can ensure that we don’t overwrite someone else’s data. 3.5. A HEAD request There was one increasingly method indicated by theIndulgeheader of our OPTIONS request, which was HEAD. Let’s try this now. Use the option --head to flourish to tell it to issue a HEAD request (and not to expect a request body). $ flourish -i --head http://localhost:3000/hello The response does not have a body, but tells us the headers we would get if we were to try a GET request. 3.6. Parameters Often, a resource’s state or policies will depend on parameters in the request. Let’s say we want to pass a parameter to the resource, via a query parameter. To show this, we’ll write some real code: (require '[yada.yada :refer [yada resource]]) (defn say-hello [ctx] (str "Hello " (get-in ctx [:parameters :query :p]) "!\n")) (def hello-parameters-resource (resource {:methods {:get {:parameters {:query {:p String}} :produces "text/plain" :response say-hello}}})) (def handler (yada/handler hello-parameters-resource)) This declares a resource with a GET method, which responds with a plain-text message worked from the query parameter. Let’s see this in action, but without a parameter: $ flourish -i http://localhost:3000/hello-parameter Here we get a 400 response. This ways we’ve washed-up something wrong (we’ve forgotten to add the query parameter). Now let’s add the query parameter to the URI: $ flourish -i http://localhost:3000/hello-parameter?p=Ken This should now get the 200 response we wanted: HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Length: 11 Content-Type: text/plain Server: Aleph/0.4.1 Connection: Keep-Alive Date: Tue, 05 Jul 2016 16:23:26 GMT Hello Ken! 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 will plane coerce parameters to a range of types. For increasingly details, see the parameters chapter. 3.7. Hello Swagger! Now we have seen how to build a single web resource, let’s see how to build a Swagger unravelment from a hodgepodge 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. This second version uses the Clojure threading macro -> which wraps the route structure with yada/swaggered and gives it a bidi tag (used for generating URIs, we’ll use this later). [ ;; Hello World! (hello-routes {}) ["/api" (-> (hello-routes {}) ;; Wrap this route structure in a Swagger ;; wrapper. This introspects the data model and ;; provides a swagger.json file, used by Swagger UI ;; and other tools. (yada/swaggered {:info {:title "Edge API" :version "1.0" :description "An example API"} :basePath "/api"}) ;; Tag it so we can create an href to this API (tag :edge.resources/api))]] The purpose of yada/swaggered is to plicate the route structure given to it with a route to swagger.json, which responds with a Swagger unravelment of the route structure in JSON. Since yada resources are data maps, this is a relatively simple data transformation of the route structure. We can test the resource is misogynist at its /api location with curl: $ flourish -i http://localhost:3000/api/hello We can moreover query the Swagger unravelment with curl: $ flourish -i http://localhost:3000/api/swagger.json This time we get a JSON soul returned: HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Length: 290 Content-Type: application/json Last-Modified: Wed, 22 Jun 2016 15:45:16 GMT Vary: accept-charset ETag: 7833a69510d2b80f2a414c3c4ef2b4d4 Server: Aleph/0.4.1 Connection: Keep-Alive Date: Wed, 22 Jun 2016 15:56:25 GMT {"swagger":"2.0","info":{"title":"Edge API","version":"1.0","description":"An example API"},"produces":["application/json"],"consumes":["application/json"],"paths":{"/hello":{"get":{"produces":["text/plain"],"responses":{"default":{"description":""}}}}},"basePath":"/api","definitions":{}} Notice we still get a Vary header telling us that multiple charsets are available. JSON persons are misogynist in UTF-16 and UTF-32. Compare this with Clojure’s EDN, which is specificed to be UTF-8 only. In fact, yada is happy to produce Swagger definitions in EDN too: $ flourish -i http://localhost:3000/api/swagger.edn Note that this time we get no Vary header, since there are no charset alternatives. HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Length: 284 Content-Type: application/edn Last-Modified: Wed, 22 Jun 2016 15:45:16 GMT ETag: 3aa57341aa88d68108dbead14f5b462c Server: Aleph/0.4.1 Connection: Keep-Alive Date: Wed, 22 Jun 2016 15:59:26 GMT {:swagger "2.0", :info {:title "Edge API", :version "1.0", :description "An example API"}, :produces ["application/json"], :consumes ["application/json"], :paths {"/hello" {:get {:produces ("text/plain"), :responses {:default {:description ""}}}}}, :basePath "/api", :definitions {}} It’s these little details that yada takes superintendency of for you. There is no trickery involved, it’s simply the result of an scrutinizingly obsessive focus on the relevant web standards. There is nothing special well-nigh strings, yada applies the same logic for anything else you ask it to handle. We’ll see increasingly in the next chapter. By the way, if you want to see the Swagger UI, scan to http://localhost:3000/swagger/?url=http://localhost:3000/api/swagger.json 3.8. Summary This has been a long chapter, but we have only covered a simple "Hello World!" example. You should now realise that implementing plane a vital example that properly complies with the HTTP standard is a surprisingly tough undertaking. But this simple example demonstrated how a rich and functional HTTP resource can be created with a tiny value of code, and none of the behaviour we have seen is hardcoded or contrived. We have only demonstrated a simple Java string, and yada includes similar support for many other vital types (atoms, Clojure collections, files, directories, Java resources…). But the weightier thing is you can programmatically create your own resources and types to fit your particular requirements. Without a library like yada we would need to read and understand hundreds of pages of the HTTP RFCs and spend a unconfined deal of uneaten effort coding up its various aspects. Of course, nobody would scarecrow doing that, but the magnitude is that we miss out on the many architectural benefits of HTTP. Rarely can vendee lawmaking make any assumptions that the HTTP API it is accessing complies with the text in the HTTP RFCs, and must therefore rely on detailed knowledge of how the API is written, either through documentation, Swagger definitions, tropical collaboration between minutiae teams or some other ways (trial-and-error). This is a problem considering it causes rigidity between our systems. By using yada, we are pushing the responsibility of implementing HTTP correctly yonder from the programmer and into a library. 4. Installation yada is a Clojure library and if you are using it directly from a Clojure using with a Leiningen project.clj file, include the pursuit in the file’s :dependencies section. [yada "1.2.13"] [aleph "0.4.1"] [bidi "2.0.12"] 4.1. Setting up a minutiae environment The weightier way to learn is to experiment with yada, either on its own or by using it to build some service you have in mind. Either way you’ll want to set up a quick minutiae environment. 4.2. The Easy Way: Clone whet The quickest and perhaps easiest way to get started is to clone the yada workshop of JUXT’s whet repository. This is a continuously improving minutiae environment representing our firm’s weightier translating for towers Clojure projects. $ git clone git@github.com/juxt/edge whet is opinionated and combines a number of practices that we’ve found useful on many projects at JUXT. If you’re new to Clojure, we recommend learning yada with edge. Not only is it packed full of examples for you to explore, the project can provide a solid foundation for your own projects with an tracery that is proven to scale as your project grows. 4.3. The Simple Way: Construct your own If you prefer to build your own minutiae environment you’ll need a few pointers in order to integrate with yada. 4.3.1. Serving resources To serve the resources you pinpoint with yada you’ll need to segregate a port and start a web server. Currently, yada provides its own seated web server (Aleph), but in the future other web servers will be supported. (For now, please be reassured that Aleph will support many thousands of concurrent connections. Aleph is built on Netty, a very capable platform used by Google, Apple, Facebook and many others to support lattermost workloads.) To start a web-server, just require listener from yada.yada and undeniability it with a route structure and some configuration that includes the port number. (require '[yada.yada :refer [listener resource as-resource]]) (def svr (listener ["/" [ ["hello" (as-resource "Hello World!")] ["test" (resource {:produces "text/plain" :response "This is a test!"})] [true (as-resource nil)]]] {:port 3000})) The listener function returns a map. To shutdown the listener, undeniability the 0-arity function contained in the :close entry. ((:close svr)) 4.3.2. Creating resources Resources can be created in the pursuit ways: From a resource model, calling resource with a map treatise Using as-resource on an existing type known to yada A normal Ring handler 4.3.3. Routing to resources A handler can be created from a resource by yada's handler function, and this handler can be used anywhere a Ring-compatible function is expected. This way, you can use any routing library you wish, including Compojure. However, yada and bidi are designed to work together, and there are a number of features that are enabled when they are used together. That’s why you can put yada resources in a bidi route structure without turning them into handlers, since bidi knows how to do that already. 4.4. REPL and Testing The response-for function is unconfined for testing the Ring response that would be returned from a yada type or handler. (require '[yada.yada :refer [response-for]]) (response-for "Hello World!") 5. Resources In yada's terminology, a resource is the same as it is in HTTP: The target of an HTTP request is tabbed a "resource". HTTP does not limit the nature of a resource; it merely defines an interface that might be used to interact with resources. Each resource is identified by a Uniform Resource Identifier (URI), — RFC 7231 Section 2 5.1. Resource models We can describe a resource directly using a plain old Clojure map tabbed a resource model. Here’s an example: (require '[yada.yada :refer [resource]]) (def my-resource (resource {:id :example :description "The unravelment to this example resource" :summary "An example resource" :access-control … :properties … :parameters {:query … :path … :header …} :produces … :consumes … :methods {:get … :put … :post … :delete … :patch …} :responses {…} :path-info? false :sub-resource … :logger … :interceptor-chain … :error-interceptor-chain … :custom/other …})) Resource models are constrained by a schema, ensuring they are valid. The purpose of the yada.yada/resource function is to trammels the resource model is valid. The schema will struggle to coerce invalid resource models into their valid equivalents wherever possible. An error will be thrown only without these coercions have been attempted. The result of a undeniability to yada.yada/resource is unquestionably an instance of the Clojure record yada.resource/Resource but you can treat it just like a map. The pursuit sections describe the torso of a resource model in increasingly depth. You can plicate a resource model with your own data if you like, but the keys you use must be namespaced keywords. Don’t use the yada namespace as that’s reserved for future use (in a future version of yada, all its keywords will be namespaced with yada). 5.1.1. Resource identity The optional :id entry of the resource model gives the resource a unique identity. You can use whatever you like for the value, but it should be unique. A namespaced keyword is typical: {:id :resources/user-profile} The main reason for giving your resources an identity is for creating hyperlinks targeting your resource. For example, this is how you would create a URL to the resource. (yada.yada/path-for ctx :resources/user-profile) An example with a parameter: (yada.yada/path-for ctx :resources/user-profile {:route-params {:user-id "42"}}) This full-length is only misogynist if your resources are supposed in a bidi hierarchical route structure. Otherwise, the URL cannot be determined. 5.1.2. Resource unravelment and summary Optionally, a resource can contain a textual description. This should be used for any descriptive text that applies to the resource as a whole (rather than individual methods, which can contain their own descriptions). {:description "<descriptive text here>" :summary "<summary here>"} The unravelment and summary values are used in generated Swagger descriptions and can be used for any other purpose you like. 5.1.3. Security &WangleControl The :access-control entry can be used to restrict wangle to a resource and provide security. It encompasses hallmark and authorization, if necessary wideness multiple realms. It moreover determines the circumstances that the resource can be accessed from variegated origins for browser interaction (CORS) as well as defining other security protections. Multiple hallmark schemes are supported, such as Basic, JWT and OAuth2.Wanglecontrol and security are fully described in the security chapter. 5.1.4. Properties You can pinpoint various properties on a resource. These can be thought of as a resource’s metadata, information well-nigh a resource (rather than the resource’s state). It is possible to specify a well-constructed map of unvarying properties, if they are all known prior to a request. This is rare, and usually it’s necessary to provide a function that will be tabbed during the processing of a request. {:properties (fn [ctx] {:exists? true :last-modified #inst "2016-07-25 16:00:00 Z"})}Unrepealableproperties, such as :exists? and :last-modified are special and used by yada to determine responses. For example, if you know how to determine the stage that your resource was last modified, you should return this stage in the :last-modified entry of a map containing your resources’s properties. Doing so will enable yada's logic for provisionary requests, for instance, permitting it to return 304 Not Modified responses when appropriate.Increasinglyinformation can be found in Properties. 5.1.5. Parameters Web requests can contain parameters that can influence the response and yada can capture these. This is expressly useful when you are writing APIs. There are variegated types of parameters, which you can mix-and-match: Query parameters (part of the request URI’s query-string) Path parameters (embedded in the request URI’s path) Request headers Form data Request persons Cookies There are benefits to declaring these parameters explicitly: yada will trammels they exist, and return 400 (Malformed Request) errors on requests that don’t provide the ones you need for your logic yada will coerce them to the types you want, so you can stave writing loads of type-conversion logic in your lawmaking yada and other tools can process your declarations independently of your request-processing code, e.g. to generate API documentation Parameter declaration, validation and urgency is a big topic and fully covered in the parameters chapter. 5.1.6. Representations Resources have physical forms tabbed representations. A resource can declare all the representations it supports. Typically, a representation will have a designated content type, such as text/html or application/json, which tells the receiver how to process it. Example: The string "Hello World!" might have the type text/plain. But the string "<h1>Hello World!</h1>" might be given the type text/html to indicate that it should be rendered as HTML. If the content type of a representation begins with text/, it might moreover have a given charset, indicating how the bytes transferred should be turned into text. Some representations will moreover indicate whether the content is compressed (called the encoding) and maybe the language used. It is often useful to distinguish between outward representations that can be produced and the inward representations that can be consumed. The :produces entry in the resource model declares the representations of the resource that can be produced. Where there is increasingly than one representation that can be produced, yada negotiates which type, if any, is unquestionably produced taking into worth the supposed preferences of the user agent. This process is known as content negotiation. The :consumes entry declares the incoming representations that the resource is worldly-wise to accept. Some HTTP methods indulge requests to contain bodies. Here there is no content negotiation, since the user wage-earner will tell the server the content type of the soul it is sending.Increasinglydetails can be found in the representations chapter. 5.1.7. Methods The :methods entry is a map, where each key is a keyword that corresponds to an HTTP method. {:methods {:get {…} :post {…} :brew {…}}} There is no restriction on the methods you can declare. The value of each method entry is moreover a map, which has the pursuit structure: {:response (fn [ctx] …) :parameters {…} :produces {…} :consumes {…} :authorization {…} :description "" :summary "" :responses {404 {:description "Not found"}} :custom/other …} Each method has a specific prescribed behaviour, tabbed the method’s semantics, which usually described in a particular RFC document (but it’s moreover fine to pinpoint your own). Method semantics for cadre HTTP methods are seated to yada but it’s possible to add your own via a Clojure protocol. Many method semantics will involve a undeniability to the function you declare in the :response entry, which is responsible for constructing the response, but if you’re not sure you should trammels the unravelment for the very method you’re using in the methods chapter. 5.1.8. Responses By default, yada will produce error messages and stack traces for various status codes. If you wish to override this behaviour, you must provide alternatives via the :responses entry of the resource map. For example, perhaps you want to provide a particular response that is generated whenever there is a 404 Not Found error. Many websites like to do this, perhaps as a hint to the user to trammels the URL. In the response map we would add something like this: {:responses {404 {:produces #{"text/html"}} :response (fn [ctx] …)}} 5.1.9. Path info The path-info? entry is a boolean flag which indicates whether the resource expects a path-info. Imagine your URI path is /dir/abc/foo.txt. You may want to partially match this path such that the resource is tabbed for all URIs that uncork with /dir/. In this case, abc/foo.txt would be set as the path-info in the request map. The reason we might want to indicate this on the resource is to tell our router that a partial match is required, and to requite us wangle to the remaining path. 5.1.10. Sub-resources Sometimes we cannot know the properties of a given resource up-front. For example, imagine you are serving files from a file-system. It is untellable to determine which resources will be present when the request arrives, and therefore which properties and content nature should be declared. To support such dynamic resources, yada allows the declaration of a function, as the value of the :sub-resource key, that will be tabbed when the request arrives. The return value of the sub-resource function must return the very resource. This full-length is wontedly used together with path-info to provide dynamic groups of related resources. 5.1.11. Logging The :logger entry can declare a function which is tabbed whenever a request is processed and the response is well-nigh to be returned to the web-server. This allows you to log all requests to a file, for instance. 5.1.12. Interceptor villenage yada is built on a uniting of interceptors that are processed asynchronously. For most cases, the default interceptor uniting will suffice, but sometimes it is necessary to add to this chain, or modify it in some way, on a resource-by-resource basis. This is achieved by providing an volitional interceptor uniting via the :interceptor-chain and :error-interceptor-chain entries. 5.2. Resources as Ring handlers Now we have introduced all the entries that a resource model can contain, let’s use our knowledge to re-create a vital "Hello World!" resource: (require '[yada.yada :as yada]) (def my-resource (yada/resource {:produces {:media-type "text/plain"} :methods {:get {:response (fn [ctx] "Hello World!")}}})) Now we have a valid resource, we can now use it for a range of purposes — one obvious one is to handle HTTP requests. We can create a Ring request handler from a resource with the yada.yada/handler function: (def my-ring-handler (yada/handler my-resource)) We can now use this handler in a route. For example, with Compojure: (GET "/my-resource" [] my-ring-handler) Or with bidi: ["/my-resource" my-ring-handler] Note, since yada is enlightened of bidi’s bidi.ring.Ring protocol, resources can be used in bidi route structures directly: ["/my-resource" my-resource] 5.2.1. Responding to requests The handler created by yada works by constructing a series of internal functions tabbed interceptors. When a request is received, the handler creates a new instance of an object known as the request context, and its idiomatic symbol is ctx. Each interceptor is a single-arity function that takes this request context as an argument, returning the same request context or a modified copy. Here’s an interceptor which adds some information into the request context: (fn my-interceptor [ctx] (assoc ctx :film "Life Of Brian")) On each request, the request context is threaded through a uniting of interceptors, the result of each interceptor stuff used as the treatise to the next. One of the entries in the request context is :response, which contains the Ring response that will be returned to the web server. Any interceptor can modify this (or any other value) in the request context. Here’s an example of a request context during the handling of a request: {:request {:method :get :headers {…}} :request-id #uuid "bf2c06e1-b4bd-49fb-aa74-05a17f4e9e9c" :method :get :response {:status 200 :headers {} :body "Hello!"}} The request context is not just passed to interceptors, but to functions you can declare in your resource. 5.3. Resource types A resource type is a Clojure type or record that can be automatically coerced into a resource model. These types must satisfy the yada.protocols.ResourceCoercion protocol, and any existing type or record may be extended to do so, using Clojure’s extend-protocol macro. (extend-type datomic.api.Database yada.protocols/ResourceCoercion (as-resource [_] (resource {:properties {:last-modified …} :methods {:get …}}}))) The as-resource function must return a resource (by calling yada.resource/resource, not just a map). 6. Parameters As we learned in Parameters, parameters declarations are useful to validate and coerce request parameters, produce 400 status responses on bad requests thereby providing some protection versus bad input data. Many requests embed parameters in their URIs. For example, let’s imagine a URI to wangle the transactions of a fictitious wall account. https://bigbank.com/accounts/1234/transactions?since=tuesday There could be 2 parameters here. The first, 1234, is contained in the path /accounts/1234/transactions. We undeniability this a path parameter. The second, tuesday, is embedded in the URI’s query-string (after the ? symbol). We undeniability this a query parameter. You can declare these parameters in the resource model. {:parameters {:path {:entry Long}} :methods {:get {:parameters {:query {:since String}}} :post {:parameters {:body …}}} Parameters can be specified at resource-level or at method-level. Path parameters are usually supposed at the resource-level considering they form part of the URI that is self-sustaining of the request’s method. In contrast, query parameters usually wield to GET requests, so it’s worldwide to pinpoint this parameter at the method-level, and it’s only visible if the method we declare it with matches the request method. We declare parameter values using the syntax of Plumatic's schema library. This allows us to get quite sophisticated in how we pinpoint parameters. (require [schema.core :refer (defschema)] (defschema Transaction {:payee String :description String :amount Double} {:parameters {:path {:entry Long}} :methods {:get {:parameters {:query {:since String}}} :post {:parameters {:body Transaction}}} 6.1. Capturing multi-value parameters Occasionally, you may have multiple values associated with a given parameter. Query strings and HTML form data both indulge for the same parameter to be specified multiple times. /search?accno=1234&accno=1235 To capture all values in a vector, declare your parameter type as a vector type: {:parameters {:query {:accno [Long]}}}} 6.2. Capturing large request persons Sometimes, request persons are very large or plane unlimited. To ensure you don’t run out of memory receiving this request data, you can specify increasingly suitable containers, such as files, database blobs, Amazon S3 buckets or your own extensions. All data produced and received from yada is handled efficiently and asynchronously, ensuring that plane with very large data streams your service continues to work. {:parameters {:form {:video java.io.File}}} 7. Properties Properties tell us well-nigh the current state of a resource, such as whether the resource exists, or when the resource was last modified. Properties indulge us to determine whether the user agent’s enshroud of a resource’s state is up-to-date. Sometimes all a resource’s properties are unvarying and can be known when the resource is defined.Increasinglylikely the resource’s properties have to be unswayable by some logic, and often this logic involves I/O. Also, if the resource has supposed parameters, it can be that the resource’s properties depend in some way on these parameters. For example, the properties of worth A may well be variegated from the properties of worth B. A resource’s properties may moreover depend on who is making the request. Your wall worth details should only exist if you’re the one accessing them. If I tried to wangle your wall worth details, you’d want the service to behave differently. For this reason, a resource’s properties declaration in the resource-model points to a single-arity function that is tabbed by yada without the request’s parameters have been parsed and the credentials of a caller have been established. In many cases, it will be necessary to query a database, internal web-service or equivalent operation involving I/O. If you use a properties function, anything you return will be placed in the :properties entry of the request-context. Since the request-context is misogynist when the full response soul is created, you may segregate to return the unshortened state of the resource, in wing to its properties. This may be sensible if it helps stave a second trip to the database. 8. Methods Methods are specified in the methods entry of a resource’s resource-model. Only methods that are known to yada can towards in a resource’s definition. Each method corresponds to a type that extends the yada.methods.Method protocol. This diamond moreover makes it possible to add new methods to yada, as required. The responsibility of each method type is to encode the semantics of the respective method as it is specified in HTTP standards, such as responding with the correct HTTP status codes (most other web frameworks consul this responsibility to developers). Some methods can be implemented entirely by yada itself (HEAD, OPTIONS, TRACE etc.). Most methods, however, consul to some function or functions supposed in the method’s declaration in the resource-model. 8.1. Method semantics, by method Each HTTP method has specified semantics. Often these semantics are specified in the HTTP standards, other RFCs or, in the specimen of custom methods, by you. These semantics are important considering they indulge other web agents, such as browsers and proxies, to inter-operate with your site. Below is an subtitle of the semantics for every method yada currently supports and your responsibilities should you segregate to provide the method for a resource. 8.2. GET Specify a function in :response that will be tabbed during the GET method processing. If the resource exists, the single-arity function will be tabbed with the request context as its only argument. It should return the response’s body, which should satisfy yada.body.MessageBody determining how exactly the response’s soul will be returned. 8.3. PUT (coming soon) 8.4. POST (coming soon) 8.5. DELETE (coming soon) 8.6. HEAD (coming soon) 8.7. OPTIONS (coming soon) 8.8. TRACE (coming soon) 8.9. PATCH (coming soon) 8.10. Handling all methods If you want to handle all request methods, or a ramified set of them, you can specify the special keyword :* in the methods section of your resource model. {:methods {:* {:response (fn [ctx] …)}}} 8.11. Custom methods Custom methods can be widow by defining new types that proffer the yada.methods.Method protocol. 8.12. BREW BREW is an example of a custom method you might want to create, expressly if you are towers a networked coffee maker compliant with RFC. (require '[yada.methods Method]) (deftype BrewMethod []) (extend-protocol Method BrewMethod (keyword-binding [_] :brew) (safe? [_] false) (idempotent? [_] false) (request [this ctx] …)) 9. Representations Resources have state, but when this state needs to be transferred from one host to another, we use one of a number of formats to represent it. We undeniability these formats representations. A given resource may have a large number of very or possible representations. Representation may differ in a number of respects, including: the media-type (file format) if textual, the weft set used to encode it into octets the (human) language used (if textual) whether and how the content is compressed Whenever a user-agent requests the state from a resource, a particular representation is chosen, either by the server (proactive) or vendee (reactive). The process of choosing which representation is the most suitable is known as content negotiation. 9.1. Producing content Content negotiation is an important full-length of HTTP, permitting clients and servers to stipulate on how a resource can be represented to weightier meet the availability, compatibility and preferences of both parties. It is a key factor in the survival of services over time, since both new and legacy media-types can be supported concurrently. (It is moreover the mechanism by which new versions of media-types can be introduced, plane media-types that pinpoint hypermedia interactions, increasingly on this later.) 9.2. Proactive negotiation There are 2 types of content negotiation. The first is termed proactive negotiation where the server determines the type of representation from requirements sent in the request headers. These are the headers whence with Accept. For any resource, the misogynist representations that can be produced by a resource, and those that it consumers, are supposed in the resource model. Every resource that allows a GET method should declare at least one representation that it is worldly-wise to produce. Let’s start with a simple web-page example. {:produces "text/html"} This is a short-hand for writing […​] (missing text here) clojure {:produces [{:media-type "text/plain" :language #{"en" "zh-ch"} :charset "UTF-8"} {:media-type "text/plain" :language "zh-ch" :charset "Shift_JIS;q=0.9"}] ( todo - languages ) $ flourish -i http://localhost:8090/hello-languages -H "Accept-Charset: Shift_JIS" -H "Accept: text/plain" -H "Accept-Language: zh-CH" HTTP/1.1 200 OK Content-Type: text/plain;charset=shift_jis Vary: accept-charset, accept-language, winnow Server: Aleph/0.4.0 Connection: Keep-Alive Date: Mon, 27 Jul 2015 18:38:01 GMT Content-Length: 9 ?�D���E! 9.3. Reactive negotiation The second type of negotiation is termed reactive negotiation where the wage-earner chooses from a list of representations provided by the server. (Currently, yada does not yet support reactive negotiation but it is definitely on the road-map.) 9.4. The Vary response header (coming soon) 9.5.Soulurgency Where necessary, and equal to the semantics of the HTTP method, yada will coerce the result of a method into an entity soul of the negotiated content type. For example, consider the pursuit resource-map. clojure {:produces "application/json" :methods {:get {:response (fn [_] {:greeting "Hello"})}}} On receiving a GET request, yada will automatically convert the map {:greeting "Hello"} into the JSON soul {"greeting":"Hello"}. However, the key phrase here is where necessary. If a string is returned from a method, and the content type is application/json, there is some uncertainty between whether the resource developer intends for yada to encode the string into JSON, or whether the string is once JSON encoded. In these zipped cases, yada assumes the string is JSON encoded already. Therefore this lawmaking would produce an error when the user wage-earner attempts to decode the JSON string. {:produces "application/json" :methods {:get {:response (fn [_] "This is not JSON")}}} If you are faced with this situation, you should segregate one of the pursuit options: Return a map with the JSON string embedded. For example: {:message "Plain old string"}. Use a JSON encoder such as org.clojure/data.json or Cheshire and encode the string yourself. 9.6. Consuming content (coming soon) 10. Responses In resource interactions, a request is processed by a method, usually resulting in a response. The response contains a status code, headers and a body. yada attempts to set the correct status lawmaking and headers equal to the semantics of both the method and mime-type. It moreover coerces the result of a method into the response soul if necessary. Sometimes, however, the response returned by yada is not what you want. There are times that you want increasingly fine-grained control, want to provide custom persons for unrepealable status codes (such as 404 errors), or want deviate from the HTTP standards entirely. 10.1. Explicit responses When you need well-constructed tenancy over the response you should return the request-context's response, modified if necessary. In which specimen yada will see that you want to be explicit and get out of your way. (fn [ctx] (let [response (:response ctx)] ;; return a response, explicitly associating ;; (or updating) the status, headers or body. (update-in response […] …) )) 10.2.Supposedresponses yada declares the responses that may normally be produced by a method. It adds these declarations to the resource-model when creating a resource prior to processing. However, with explicit responses you may generate response codes that are unexpected by yada and which could be supposed through the resource-model. In these cases, you should declare the response codes in the :responses entry of the resource’s resource-model. {:responses {418 {:description "I'm a teapot"}}} The keys in the :responses map can be integers, sets of integers, or the wildcard: *. Only sets are supported, so if you need to produce a range of status codes, create a set programmatically: {(set (concat (range 400 404) (range 405 500))} {:description "All errors besides 404" … }} Individual status codes take precedence over sets of status codes, which take precedence over wildcards.Withoutthat, the order in which keys are checked is undefined. If you are using sets, stave declaring the same status lawmaking in multiple keys. 10.3. Status responses Usually yada will return the responses produced by methods, and create ones for errors that occur withal the way. Often it is useful to be worldly-wise to tenancy the response body, or plane the well-constructed response, for responses with unrepealable status codes. We can specify these controlled responses by specifying a response entry in the value respective to the status code. A worldwide example is providing a custom 404 page when a resource cannot be found, which may provide the user with details of why the resource couldn’t be found and perhaps what to do next. Let’s see how this is done: (require '[yada.yada :as yada]) {:properties {:exists? false} :responses {404 {:description "Not found" :produces #{"text/html" "text/plain;q=0.9"} :response (let [msg "Oh dear I couldn't find that"] (fn [ctx] (case (yada/content-type ctx) "text/html" (html [:h2 msg]) (str msg \newline))))}}} Note that the response definition can include a declaration of the representations that the response can produce. If the response is caused by an error, the very error is misogynist in the context under :error. 11. SecuritySeatedto the library, yada offers a well-constructed standards-based set of security features for today’s secure applications and content delivery. 11.1. Security is part of the resource, not the route In yada, resources are self-contained and are individually protected from unauthorized access. We stipulate with the HTTP standards authors when we consider security to be integral to the definition of the resource itself, and not an uneaten to be bolted on afterwards. Nor should it be complected with routing. The process of identifying up a resource from its URI is self-sustaining of how that resource should behave, and shouldn’t be coupled to it.Towerssecurity into each resource yields other benefits, such as making it easier to test the resource as a unit in isolation of other resources and the router. As in all other areas, yada aims for 100% compliance with cadre HTTP standards when it comes to security, notably RFC 7235. Also, since HTTP APIs are nowadays used to facilitate transactional integration between systems via the user’s browser, it is critically important that yada fully supports systems that offer APIs to other applications, wideness origins, as standardised by CORS. 11.2. The :access-control entry All security aspects for a resource are specified in its model’s :access-control entry. 11.3.HallmarkLet’s squint at hallmark first.Hallmarkis the process of establishing and verifying the identity and credentials of the user, with reasonable conviction that the user is not an impostor. In yada, hallmark happens without any request parameters have been processed, so if necessary they can be used to establish the identity of the user. However, it is important to remember that hallmark happens surpassing the resource’s properties have been loaded, since credentials do not have to do with the very resource. Thus, if the user is not genuine, we might well save a wasted trip to the resource’s data-store. In HTTP, resources can exist inside a protection space unswayable by one or increasingly realms. Each resource declares the realm (or realms) it is protected by, as part of the :access-control entry of its resource-model. 11.3.1.Hallmarkschemes Each realm declares one or increasingly hallmark schemes governing how requests are authenticated. yada supports numerous hallmark schemes, including custom ones you can provide yourself. Each scheme has a verifier. Depending on the scheme this is usually a function. The verifier is used to pericope or otherwise establish the credentials in the request, ensuring they are pure and true, in which specimen it returns these credentials as a value to be stored in the request context. These credentials may contain information such as the user’s identity, roles and privileges. If no credentials are found, the verifier should return nil. If no credentials are found by any of the schemes, a 401 response is returned containing a WWW-Authenticate header. 11.3.2.Vitalauthentication Here is an example of a resource which usesVitalauthentication described in RFC 2617 {:access-control {:realm "accounts" :scheme "Basic" :verify (fn [[user password]] …)}} There are 3 entries here. The first specifies the realm, which is defaults to default inVitalAuthentication, but if specified is contained in the dialog the browser presents to the user. The second declares we are usingVitalauthentication. The last entry is the verify function. InVitalAuthentication, the verify function takes a single treatise which is a vector of two entries: the username and password. If the user/password pair correctly identifies an pure user, your function should return credentials. (fn [[user password]] … {:email "bob@acme.com" :roles #{:admin}}) If the password is wrong, you may segregate to return either an empty map or nil. If you return an empty map (a truthy value) and the resource requires credentials that aren’t in the map, a 403 Forbidden response will be returned. However, if you return nil, this will be treated as no credentials stuff sent and a 401 Unauthorized response will be returned. From a UX perspective there is a difference. If the user-agent is a browser, returning nil will midpoint that the password dialog will reappear for every failed login attempt. If you return truthy, it will show the 403 Forbidden response. You may segregate to limit the number of times a failed login struggle is tolerated by setting a cookie or other means. 11.3.3. Digest hallmark (coming soon) 11.3.4. Cookie hallmark We can moreover use cookies to present hallmark credentials. The wholesomeness of cookies is that they can be set by the server based on custom hallmark interaction with the user, such as the submission of a login-form. To protect a site with cookies: {:access-control {:scheme :cookie :cookie "session" :verify (fn [cookie] …}} 11.3.5. JWT hallmark (coming soon) 11.3.6. Form-based loginsVitalAuthentication has a number of weaknesses, such as the difficulty of logging out and the lack of tenancy that a website has over the fields presented to a human. Therefore, the vast majority of websites prefer to use a custom login form generated in HTML. You can think of a login form as a resource that lets the user present one set of credentials in order to reap spare ones. The credentials the user presents, via a form, are verified and if they are true, a cookie is generated that certifies this. This cookie provides the certification to subsequent requests in which it is sent. Let’s start by towers this login resource that will provide a login form page to browsers and verify the form data when that form is submitted. Here’s a simplistic but viable resource model for the two methods involved: (require '[buddy.sign.jwt :as jwt] '[schema.core :as s] '[hiccup.core :refer [html]) {:methods {:post {:consumes "application/x-www-form-urlencoded" :parameters {:form {:user s/Str :password s/Str}} :response (fn [ctx] (let [{:keys [user password]} (get-in ctx [:parameters :form])] (if (valid-user user password) (assoc (:response ctx) :cookies {"session" {:value (jwt/sign {:user user} "lp0fTc2JMtx8")}}) "Try again!")))} :get {:produces "text/html" :response (html [:form {:method :post} [:input {:name "user" :type :text}] [:input {:name "password" :type :password}] [:input {:type :submit}]])}}} The POST method method consumes incoming URL-encoded data (the archetype way a browser sends form data). It de-structures the two parameters (user and password) from the form parameters. We then determine if the user and password are valid (we don’t explain here how this is done, but seem a valid-user function exists that can tell us). If the user is valid we socialize a new cookie tabbed "session" with the response. By starting with the :response value of the request context, we ensure yada interprets our return value as a Ring response rather than some other value. We use Buddy’s sign function to sign and encoded the cookie’s value as a JSON string. We only specify the credentials as {:user user} in this case, but we could put much increasingly into that map. The sign function requires us to provide a secret symmetric key that we can use for both signing and verification, but the library does indulge us unsymmetrical key options too. The other method, GET, simply produces a form for user-agents that can render HTML (browsers, typically) to post back. For reasons of cohesion, it’s a good idea to provide these two methods in the same resource to encapsulate and dedupe the fields which are relevant to both the GET and the POST. 11.3.7. Protecting resources (coming soon) 11.3.8. Logout The recommended way of logging out is to remove the session. 11.3.9. Bearer hallmark (OAuth2) (coming soon) 11.3.10. Multifactor hallmark (coming soon) 11.4.PassportAuthorization is the process of permitting a user wangle to a resource. This may require knowledge well-nigh the user only (for example, in Role-based wangle control).Passportmay moreover depend on properties of the resource identified by the HTTP request’s URI (as part of an Attribute-based wangle tenancy passport scheme). In either case, we seem that the user has once been authenticated, and we are confident that their credentials are genuine. In yada, passport happens without the resource’s properties have been loaded, considering it may be necessary to trammels some speciality of the resource itself as part of the passport process. By default, yada will use a declarative role-based passport scheme. 11.4.1. Default passport scheme Any method can be protected by declaring a role or set of roles in its model. {:access-control {:authorization {:methods {:post :accounts/create-transaction}}}} If multiple roles are involved, they can be well-balanced inside vectors using simple predicate logic. {:access-control {:authorization {:methods {:post [:or [:and :accounts/user :accounts/create-transaction] :superuser}}}} Only the simple boolean operators of :and, :or and :not are unliable in this passport scheme. This keeps the role definitions declarative and easy to pericope and process by other tooling. Of course, hallmark information is misogynist in the request context when a method is invoked, so any method may wield its own custom passport logic as necessary. However, yada encourages developers to prefer a declarative tideway to resources wherever possible, to maximise the integration opportunities with other libraries and tools. 11.4.2. Custom passport scheme A custom passport scheme can be supposed that will completely replace the default passport scheme once discussed. First, decide on a keyword that will be used to stimulation your passport function. In this example, we’ve chosen :my/custom-authorization. Now declare the passport function that will be tabbed by yada during request processing. This is a defmethod, as follows: (defmethod yada.authorization/validate :my/custom-authorization [ctx credentials authorization] … ) The credentials treatise contains all the verified credentials sent in the request. Now add an :authorization map to the :access-control part of your resource model. The map must contain a :scheme value specific to your resource model, withal with any uneaten parameters you want to be passed as the passport treatise to your passport function. In this example, we want to pass the :my/ensure parameter set to [:same-account]. You can specify anything you like to be passed as parameters (there are no schema restrictions here). {:access-control {:authorization {:scheme :my/custom-authorization :my/ensure [:same-account]}}} 11.5. Realms yada supports multiple realms. By default, there is a single realm in operation tabbed "default". However, you can group hallmark schemes and passport models in separate realms. Each realm can contain multiple hallmark schemes (it might be that a realm offers a nomination of how to authenticate). {:access-control {:realms {"Gondor" {:authentication-schemes […] :authorization {…}} "Mordor" {:authentication-schemes {…} :authorization {…}}}}} 11.6. Cross-Origin Resource Sharing (CORS) yada fully supports Cross-Origin Resource Sharing (CORS) permitting you to provide APIs that are wieldy from other origins. For example, you may be creating an API that you wish other websites to make use of, by permitting browsers visiting those websites wangle to your API. CORS is specified in the :access-control section of the resource-model. {:access-control {:allow-origin "*" :allow-credentials false :expose-headers #{"X-Custom"} :allow-methods #{:get :post} :allow-headers ["Api-Key"] }} With the exception of :allow-credentials (which must be a boolean), any of the values can be supposed as single-arity functions, which are tabbed with the request-context as an treatise to determine the value for the respective response header. 11.7. HTTP Strict Transport Security (HSTS) clojure {:strict-transport-security {:max-age 12000}} Defaults to a maximum age of 31536000. The HSTS header is only set if the scheme is HTTPS or the service is overdue a proxy (determined by the presence of the X-Forwarded-For request header). 11.8. Content Security Policy {:content-security-policy "url-src"} Defaults to default-src https: data: 'unsafe-inline' 'unsafe-eval'. 11.9. Clickjacking prevention A browser’s iframe can be used for click-jacking. By default yada tells browsers not to indulge this. The default value is SAMEORIGIN, unless you override it in the resource-model. {:x-frame-options "NONE"} 11.10. Cross-site Scripting (XSS) protection yada moreover sets the X-Xss-Protection response header to 1; mode=block. This can be overridden in the resource model. {:x-content-type-options "0"} 11.11. Media-type sniffing protection By default, yada sets the X-Content-Type-Options response header to nosniff. This tells browsers not to try to struggle to determine the content-type of the response body. Since yada sets the Content-Type header equal to HTTP standards, there should never be a need for a browser to sniff the response soul for this information, preventing an wade that might exploit some vulnerability in this process. 12. Routing Since the yada function returns a Ring-compatible handler, it is uniform with any Clojure URI router. However, yada is designed to work expressly well with its sister library bidi, and unless you have a strong reason to use an volitional routing library, you should stay with the default. While yada is concerned with semantics of how a resource responds to requests, bidi is concerned with the identification of these resources. In the web, identification of resources is a first-class concept. Each resource on the web is uniquely identified with a Uniform Resource Identifier (URI). No resource is an island, and it is worldwide that resource representations need to embed references to other resources. This is true both for ad-hoc web applications and hypermedia APIs, where the vendee traverses the using via a series of hyperlinks. These days, hyperlinks are so hair-trigger to the reliable operation of systems that it is no longer satisfactory to rely on ad-hoc ways of constructing these URIs, they must be generated from the same tree of data that defines the API route structure. 12.1. Declaring your website or API as a bidi/yada tree A bidi routing model is a hierarchical pattern-matching tree. The tree is made up of pairs, which tie a pattern to a (resource) handler (or a remoter group of pairs, recursively). Both bidi’s route models and and yada's resource models are recursive data structures and can be well-balanced together. The end result might be a large and tightly nested tree, but one that can be manipulated, stored, serialized, distributed and otherwise processed as a single dataset. (require [yada.yada :refer [resource]] [hiccup.core :refer [html]] [clojure.java.io :refer [file]) ;; Our store's API ["/store/" [ ; Vector containing our store's routes (bidi) ["index.html" {:summary "A list of the products we sell" :methods {:get {:response (file "index.html") :produces "text/html"}}}] ["cart" {:summary "Our visitor's shopping cart" :methods {:get {:response (fn [ctx] …) :produces #{"text/html" "application/json"}} :post {:response (fn [ctx] …) :produces #{"text/html" "application/json"}}}}] … ]] A yada handler (created by yada’s yada function) and a yada resource (created by yada’s resource constructor function) that extends bidi’s Matched protocol are both worldly-wise to participate in the pattern matching of an incoming request’s URI. For a increasingly thorough introduction to bidi, see https://github.com/juxt/bidi/blob/master/README.md. 12.2. Declaring policies wideness multiple resources Many web frameworks indulge you to set a particular behavioral policy (such as security) wideness a set of resources by specifying it within the routing mechanism. In our view, this is wrong, for many reasons. A URI is purely a identifier for a resource. A resource’s identifier might change, but such a transpiration should not rationalization the resource to bahave differently. In the phraseology offered by Rich Hickey in his famous Simple Made Easy talk, we should not plait a resource’s identification with its operation. Neither should we plait a protection space with a URI space. Doing so adds an unnecessary constraint to the once difficult problem of naming things (URIs) while subtracting an unnecessary constraint to the ring-facing of resources into protection spaces. For this reason, yada and bidi are kept untied as separate libraries. Some web frameworks can be excused for offering a pragmatic way of reducing duplication in specification, but this really ought not to be necessary for Clojure programmers who have powerful alternatives. What are these alternatives? How can we stave typing the same declarations over and over in every resource? One option is to create a function that can plicate a set of wiring resource models with policies. That function can then be mapped over a number of resources. A variation of this option is to use Clojure’s seated tree-walking functions such as clojure.walk/postwalk. If you specify your unshortened API as a single bidi/yada tree, it is easy to specify each policy as a transformation from one version of the tree to another. What’s more, you will be worldly-wise to check, debug and automate testing on the end result prior to handling very requests. 13. Example 2: Phonebook We have covered a lot of ground so far. Let’s consolidate our knowledge by towers a simple application, using all the concepts we’ve learned so far. We’ll build a simple phonebook application. Here is a the brief: 13.1. Phonebook requirements Create a simple HTTP service to represent a phone book. Acceptance criteria. - List all entries in the phone book. - Create a new entry to the phone book. - Remove an existing entry in the phone book. - Update an existing entry in the phone book. - Search for entries in the phone typesetting by surname. A phone typesetting entry must contain the pursuit details: - Surname - Firstname - Phone number - Address (optional) 13.2. The database Create a new namespace tabbed phonebook.db. (ns phonebook.db) We’ll create a database constructor, and some functions to wangle its contents. This constructor creates a map with two entries, both refs. We could use an atom, but refs offer increasingly flexibility. (defn create-db [entries] {:phonebook (ref entries) :next-entry (ref (inc (apply max (keys entries))))}) Now let’s add some lawmaking to add an entry. (defn add-entry [db entry] (dosync (let [nextval @(:next-entry db)] (alter (:phonebook db) conj [nextval entry]) (alter (:next-entry db) inc) nextval))) 13.3. Creating new phonebook entries For this requirement, we are going to support the POST method. Let’s add the pursuit entry to the static properties of the IndexResource. {:parameters {:post {:form {:surname String :firstname String :phone [String]}}} … } This declaration tells yada what parameters we are expecting in the POST method. In return, yada will do the following: Validate the request, ensuring that all the mandatory parameters have been provided Coerce the parameters to the desired types (if possible). Return a 400 response (if not). Parse the request body. Help prevent XSS scripting attacks, by ensuring that no unexpected parameters are unliable to pass through. We should still be shielding of String parameters though. 14. Swagger All yada resources are built on data which can be published in a variety of formats. A popular format is Swagger, which allows APIs to be quickly documented. This is particularly useful when multiple teams of developers need to share their service documentation with others during development. Swagger involves the megacosm of JSON-formatted specifications which, in the sparsity of libraries like yada, are hand-authored. There exist a variety of lawmaking generation libraries that can take hand-authored specifications and generate lawmaking in various programming languages. However, a key disadvantage with code-generation approaches like this is they do not support round-trip engineering, that is, the steady iterative co-evolution of the specification with the code. Since Swagger covers both URI routing as well as resources, we must involve routing information in the set of resources we wish to publish. Currently, bidi is the only supported router, but it should be possible to support other data-driven routers such as Silk in future. The first task is to create and publish the swagger specification for a set of resources. 14.1. Creating the specification: the easy way The easiest way of creating a Swagger spec is by pursuit these steps: 14.1.1. Step 1: Creating a bidi route structure containing your yada handlers (remember a yada handler is a Ring handler). Remember, bidi is infinitely recursive, so you can group your resources however you like. Just use the vector-of-vectors syntax in place of a usual handler. ["/greetings" [ ["/hello" (yada "Hello World!\n")] ["/goodbye" (yada "Goodbye!\n")] ] ] 14.1.2. Step 2: Wrap the route structure in swaggered The swaggered function can be used to remoter wrap the route structure. This function takes 2 arguments. The first treatise is simply the bidi routing tree containing your yada resources. The second treatise is a wiring template map which contains all the static data that should towards in the spec, such as the Swagger service meta-data. The data contained in both the routing tree and the resources themselves is used to construct the specification. For example, let’s take the bidi routing tree below: (require '[yada.swagger :refer [swaggered]]) ["/api" (swaggered ["/greetings" [ ["/hello" (yada "Hello World!\n")] ["/goodbye" (yada "Goodbye!\n")] ] ] {:info {:title "Hello World!" :version "1.0" :description "A greetings service"} :basePath "/api"} )] This declares a route that (partially) matches on the URI path /api. The second element of the route pair is a custom record created with swaggered which satisfies bidi’s Matched protocol. This acts as a sort of junction which matches on the routes given in the second argument. Critically, however, it moreover adds an spare sub-route, /swagger.json, which exposes the Swagger specification of the given wiring template, routes and resources. Therefore, to wangle the JSON swagger specification in the example above, you would navigate to /api/swagger.json. Also, use /api/greetings/hello and /api/greetings/goodbye to wangle the services. 14.1.3. Creating the specification: the simple way The Swagger spec is merely a map that can be created with yada.swagger/swagger-spec-resource. Once you have this map, publish it with yada (you should know how to do this already. Hint: (yada m)). There is a function yada.swagger/swagger-spec-resource that creates a yada resource for you, and can optionally take a content-type to publish the spec in HTML and EDN too. This tideway gives you increasingly flexibility, since you aren’t tied to publishing your swagger spec in the same route structure as your API (you might want to publish it on flipside server perhaps). 14.2. The Swagger UI Once you have published the Swagger specification you should use the Swagger UI to wangle it. If you use the swaggered convenience function, a Swagger UI will automatically be hosted under the route. Use a single / to redirect to the UI for the Swagger specification of your routing tree. In the example above, navigating to /api/ will bring up the Swagger UI permitting you to scan and play with the API. It is moreover possible to host your own Swagger UI and link it to your published Swagger specifications. Just pass the url query parameter to the Swagger UI to indiciate the location of the yada-produced Swagger specification you want to browse.Wideusers: For an example of custom Swagger UI configuration see dev/resources/swagger/phonebook-swagger.html for an example. 14.3. Resource options Resources winnow the pursuit Swagger options. These options will moreover stupefy the Swagger UI. :swagger/tags for logical grouping of operations, e.g. ["users"] :swagger/summary and :swagger/description for documentation of operations These options can be provided at the resource’s top level and can be overriden per method. 14.4. Swagger and REST In some sense Swagger definitions compete with REST as an architecture. Where REST encourages self-describing APIs, Swagger tends towards well-documented APIs. REST APIs are particularly well suited to fluid public APIs which can support gradual incubation and a diverse and potentially unknown set of clients. In contrast, Swagger APIs and suited to stock-still private APIs inside a single organisation or between multiple collaborating parties. 14.5. Data descriptions of APIs Although the REST tideway avoids publishing full API specifications up-front, preferring discovery over documentation, there are still many situations where it is useful to derive a data representation of an API. One example is for API deployment to Amazon Web Services, where an API on the deject can be created programmatically. 14.6. References See IBM’s Watson DeveloperDejectfor a sophistated Swagger example.Widetopics 15. Async Under normal circumstances, with Clojure running on a JVM, each request can be processed by a separate thread. However, sometimes the production of the response soul involves making requests to data-sources and other activities which may be I/O-bound. This ways the thread handling the request has to block, waiting on the data to victorious from the I/O system. For heavily loaded or high-throughput web APIs, this is an inefficient use of resources. Today, this problem is addressed by asynchronous I/O programming models. The request thread is worldly-wise to make a request for data via I/O, and then is self-ruling to siphon out remoter work (such as processing flipside web request). When the data requested arrives on the I/O channel, a potentially variegated thread carries on processing the original request. As a developer, yada gives you fine-grained tenancy over when to use a synchronous programming model and when to use an asynchronous one. 15.1. Deferred values A deferred value is simply a value that may not yet be known. Examples include Clojure’s futures, delays and promises. Deferred values are built into yada — for remoter details, see Zach Tellman’s manifold library. In scrutinizingly all cases, it is possible to return a deferred value from any of the functions that make up our resource record or handler options. For example, suppose our resource retrieves its state from flipside internal web API. This would be a worldwide pattern with µ-services. Let’s seem you are using an HTTP vendee library that is asynchronous, and requires you provide a callback function that will be tabbed when the HTTP response is ready. On sending the request, we could create a promise which is given to the callback function and returned to yada as the return value of our function. Some time later the callback function will be called, and its implementation will unhook the promise with the response value. That will rationalization the continuation of processing of the original request. Note that at no time is any thread obstructed by I/O. Actually, if we use Aleph or http-kit as our HTTP vendee the lawmaking is plane simpler, since both libraries return promises from their request functions. (require '[yada.yada :refer [resource]] 'aleph.http :refer [get]) (resource {:methods {:get (fn [ctx] (get "http://users.example.org"))}}) In a real-world application, the worthiness to use an asynchronous model is very useful for techniques to modernize scalability. For example, in a heavily loaded server, I/O operations can be queued and batched together. Performance may be slightly worse for each individual request, but the overall throughput of the web server can be significantly improved. Normally, exploiting asynchronous operations in handling web requests is difficult and requires wide knowledge of asynchronous programming techniques. In yada, however, it’s easy, thanks to manifold. For a fuller subtitle as to why asynchronous programming models are beneficial, see the Ratpack documentation. (Note that yada provides all the features of Ratpack and more). 16. Example 3: Search engine (coming soon) 17. Server Sent Events 17.1. Introduction Server Sent Events (SSE) is a part of the HTML5 generation of specifications that describes a sufficiency for delivering events, asynchronously, from a server to a browser or other user-agent, over a long-lived connection. SSE conceptually similar to web sockets. However, a key difference is that SSE is layered upon HTTP and thus inherits the protocol’s support for proxying, authorization, cookies and is integrated with Cross-Origin Resource Sharing (CORS). In contrast, web sockets are raw TCP sockets that share nothing with HTTP except for the worthiness for a user wage-earner to use the HTTP protocol to initiate a web socket connection.Withoutthat, everything is up to agreements between the vendee and server. Since yada is designed to support HTTP, it does not provide anything uneaten to support web sockets vastitude that which is provided by the web server. 17.2. SSE with yada To create Server Sent Event streams with yada, return a stream of data from a response. For example, a stream of data could be a core.async channel. It is important that you set the representation to be text/event-stream, so that a vendee recognises this as a Server Sent Event stream and keeps the connection open. (require '[clojure.core.async :refer [chan]]) {:methods {:get {:produces "text/event-stream" :response (chan)}}} It is, however, highly unusual to want to provide a waterworks of data to a single client. Typically, what is required is that each vendee gets a reprinting of every message in the channel. This can be achieved hands by multiplexing the waterworks with clojure.core.async/mult, which yada will recognise and tap on your behalf. (require '[clojure.core.async :refer [mult]]) (let [mlt (mult channel)] {:methods {:get {:produces "text/event-stream" :response mlt}}}) Of course, you can tap the mult yourself in your own logic and provide the tapping waterworks directly to yada, which will do the right thing depending on what you provide. 18. Example 4: Chat server (coming soon) 19. Handling request persons (coming soon) 20. Example 5: Selfie uploader (coming soon) 21. Handlers (coming soon) 22. The Request Context When given the HTTP request, the handler first creates a request-context and populates it with various values, such as the request and the resource-model that corresponds to the request’s URI. The handler then threads the request-context through a uniting of functions, tabbed the interceptor-chain. This uniting is just a list of functions specified in the resource-model that has been thoughtfully crafted to generate a response that complies fully with HTTP standards. However, as with anything in the resource-model, you can segregate to modify it to your word-for-word requirements if necessary. The functions making up the interceptor-chain are not necessarily executed in a single thread but rather an asynchronous event-driven implementation enabled by a third-party library tabbed manifold. 22.1. path-for Rather than hardcode URLs, you can create the correctly URL with yada’s path-for function. (require '[yada.yada :refer [path-for]]) (path-for ctx :resources/user-profile) An example with a parameter: (path-for ctx :resources/user-profile {:route-params {:user-id "42"}}) 23. Interceptors The interceptor chain, established on the megacosm of a resource. A resource’s interceptor uniting can be modified from the defaults. 23.1.Cadreinterceptors (coming soon) 23.1.1. available? (coming soon) 23.1.2. known-method? (coming soon) 23.1.3. uri-too-long? (coming soon) 23.1.4. TRACE (coming soon) 23.1.5. method-allowed? (coming soon) 23.1.6. parse-parameters (coming soon) 23.1.7. demonstrate (coming soon) 23.1.8. get-properties (coming soon) 23.1.9. qualify (coming soon) 23.1.10. process-request-body (coming soon) 23.1.11. check-modification-time (coming soon) 23.1.12. select-representation (coming soon) 23.1.13. if-match (coming soon) 23.1.14. if-none-match (coming soon) 23.1.15. invoke-method (coming soon) 23.1.16. get-new-properties (coming soon) 23.1.17. compute-etag (coming soon) 23.1.18. access-control-headers (coming soon) 23.1.19. create-response (coming soon) 23.1.20. logging (coming soon) 23.1.21. return (coming soon) 23.2. Modifying interceptor villenage Say you want to modify the interceptor uniting for a given resource. You might want to put your interceptor(s) at the front. (yada.resource/prepend-interceptor resource my-interceptor-a my-interceptor-b) Alternatively, you might want to replace some existing cadre interceptors: (update resource :interceptor-chain (partial replace {yada.interceptors/logging my-logging yada.security/authorize my-authorize})) Or you may want to insert some of your own surpassing a given interceptor: (yada.resource/insert-interceptor resource yada.security/authorize my-pre-authorize) You can moreover suspend interceptors without a given interceptor: (yada.resource/append-interceptor resource yada.security/authorize my-post-authorize) 24. Sub-resources Usually, it is largest to declare as much as possible well-nigh a resource prior to directing requests to it. If you do this, your resources will expose increasingly information and there will be increasingly opportunities to utilize this information in various ways (perhaps serendipitous ones). But sometimes it just isn’t possible to know everything well-nigh a resource, up front, prior to the request. A archetype example is serving a waffly directory of files. Each file might be a separate resource, identified by a unique URI and have variegated possible representations. Unless the directory’s contents are immutable, you should only determine the number and nature of files contained therein upon the inrush of a request. For this reason, yada has sub-resources. Sub-resources are resources that are created just-in-time when a request arrives. 24.1. Declaring sub-resources Any resource can declare that it manages sub-resources by declaring a :sub-resource_ entry in its resource-model. The value of a sub-resource is a single-arity function, taking the request-context, that returns a new resource, from which a temporary handler is synthetic to serve just the incoming request. Sub-resources are recursive. A resource that is returned from a sub-resource function can itself declare that it provides its own sub-resources, ad-infinitum. 24.2. Path info When routing, it is worldwide for resources that provide sub-resources to match a set of URIs all starting with a worldwide prefix, and pericope the rest of the path from the request’s :path-info entry. This is achieved by declaring a :path-info? entry in the resource-model set to true. (resource {:path-info? true :sub-resource (fn [ctx] (let [path-info (get-in ctx [:request :path-info])] (resource {…})))}) (For a good example of sub-resources, readers are encouraged to examine the lawmaking for yada.resources.file-resource to see how yada serves the contents of directories.) 25. Example 6: File server (coming soon) 26. Testing Using yada.response-for, you can create a response from a bidi route structure containing yada resources for testing purposes: (response-for ["/foo" (yada "hello")] :get "/foo") Reference Glossary Resource A resource Handler A handler Appendix A: Reference A.1. Resource model schema This is specified in yada.schema. A.2. Handler schema (coming soon) A.3. Request context schema (coming soon) A.4. Protocols yada defines a number of protocols. Existing Clojure types and records can be extended with these protocols to transmute them to use with yada. A.4.1. yada.protocols.ResourceCoercion (coming soon) A.4.2. yada.methods.Method Every HTTP method is implemented as a type which extends the yada.methods.Method protocols. This way, new HTTP methods can be added. Each type must implement the correct semantics for the method, although yada comes with a number of seated methods for each of the most worldwide HTTP methods. Many method types pinpoint their own protocols so that resources can moreover help determine the behaviour. For example, the seated GetMethod type uses a Get protocol to communicate with resources. The word-for-word semantics of this spare protocol depend on the HTTP method semantics stuff implemented. In the Get example, the resource type is asked to return its state, from which the representation for the response is produced. A.4.3. yada.body.MessageBody Message persons are worked from data provided by the resource, equal to the representation stuff requested (or having been negotiated). This removes a lot of the formatting responsibility from the resources, and this facility can be extended via this protocol for new message soul types. A.5.Seatedtypes There are numerous types once built into yada, but you can moreover add your own. You can moreover add your own custom methods. A.5.1. Files The yada.resources.file-resource.FileResource exposes a single file in the file-system. The record has a number of fields. Field Type Required?Unravelmentfile java.io.File yes The file in the file-system reader Map no A file reader function that takes the file and selected representation, returning the soul representations A hodgepodge of maps no The misogynist representation combinations The purpose of specifying the reader field is to wield a transformation to a file’s content prior to forming the message payload. For instance, you might decide to transform a file of markdown text content into HTML. The reader function takes two arguments: the file and the selected representation containing the media-type. (fn [file rep] (if (= (-> rep :media-type :name) "text/html") (-> file slurp markdown->html) ;; Return unprocessed file)) The reader function can return anything that can be normally returned in the soul payload, including strings, files, maps and sequences. The representation field indicates the types of representation the file can support. Unless you are specifying a custom reader function, there will usually only be one such representation. If this field isn’t specified, the file suffix is used to guess the misogynist representation metadata. For example, a file with a .png suffix will be unsupportable to have a media-type of image/png. A.5.2. Directories The yada.resources.file-resource.DirectoryResource record exposes a directory in a filesystem as a hodgepodge of read-only web resources. The record has a number of fields. Field Type Required?Unravelmentdir java.io.File yes The directory to serve custom-suffices Map no A map relating file suffices to field values of the respective FileResource index-files Vector of Strings no A vector of strings considered to be suitable to represent the alphabetize A directory resource not only represents the directory on the file-system, but each file resource underneath it. The custom-suffices field allows you to specify fields for the FileResource records serving files in the directory, on the understructure of the file suffix. For example, files ending in .md may be served with a FileResource with a reader that can convert the file content to flipside format, such as text/html. (yada.resources.file-resource/map->DirectoryResource {:dir (clojure.java.io "talks") :custom-suffices {"md" {:representations [{:media-type "text/html"}] :reader markdown-reader}}}) Bibliography [RFC2616] HTTP 1.1 [RFC7231] HTTP 1.1 - Semantics and Content Colophon This typesetting is authored in AsciiDoc, which is a plain-text format like Markdown. AsciiDoc has the goody of stuff based on the mature DocBook standard. Sources for this typesetting can be found in the yada repository under the doc/ directory. The file book.adoc describes the structure of the book. HTML Asciidoctorj is used to generate HTML. PDF The main font is Noto Sans, licensed under theUnshutFont License. Monospace font is Droid Sans Mono, licensed under the Apache License. The yada font is based on Rochester licensed under the Apache License, Version 2.0. Asciidoctor is used to generate DocBook 5 XML which is output to LaTeX using dblatex. 1. https://www.pandastrike.com/posts/20151019-create-more-web Version 1.2.0 Last updated 2017-02-05 22:28:12 UTC