https://github.com/pileworx/akka-http-hal
HAL (Hypermedia Application Language) specification support for akka-http
https://github.com/pileworx/akka-http-hal
akka-http hal hateoas hypermedia
Last synced: 3 months ago
JSON representation
HAL (Hypermedia Application Language) specification support for akka-http
- Host: GitHub
- URL: https://github.com/pileworx/akka-http-hal
- Owner: pileworx
- License: other
- Created: 2016-04-17T19:31:35.000Z (almost 10 years ago)
- Default Branch: develop
- Last Pushed: 2020-07-25T21:14:12.000Z (over 5 years ago)
- Last Synced: 2023-12-13T17:09:42.023Z (over 2 years ago)
- Topics: akka-http, hal, hateoas, hypermedia
- Language: Scala
- Homepage:
- Size: 354 KB
- Stars: 17
- Watchers: 7
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome - pileworx/akka-http-hal - HAL (Hypermedia Application Language) specification support for akka-http (<a name="Scala"></a>Scala)
README
akka-http-hal
=============
HAL Specification support library for akka-http.
Licensed under the Apache 2 license.
[](https://travis-ci.org/pileworx/akka-http-hal)
[](https://www.codacy.com/app/Pileworx/akka-http-hal?utm_source=github.com&utm_medium=referral&utm_content=pileworx/akka-http-hal&utm_campaign=Badge_Grade)
[](https://www.codacy.com/app/Pileworx/akka-http-hal?utm_source=github.com&utm_medium=referral&utm_content=pileworx/akka-http-hal&utm_campaign=Badge_Coverage)
Getting Started
---------------
Installation:
```scala
libraryDependencies += "io.pileworx" %% "akka-http-hal" % "1.2.5"
```
Support for Scala 2.11, 2.12, 2.13.
Usage
-----
Create your marshaller:
```scala
trait FooProtocol extends DefaultJsonProtocol {
implicit val fooFormat = jsonFormat3(FooDto)
}
```
You can import a collection of IANA Relations (Self, Next, etc):
```scala
import io.pileworx.akka.http.rest.hal.Relations._
```
Create a resource adapter:
```scala
trait FooAdapter extends FooProtocol {
def fooLink(rel: String, id: String) = rel -> Link(href = s"/foos/$id")
def foosLink(rel: String) = rel -> Link(href = "/foos")
def newResource(id: String): JsValue = {
ResourceBuilder(
withLinks = Some(Map(
fooLink(Self, id),
foosLink(Up)
))
).build
}
def notFoundResource: JsValue = {
ResourceBuilder(
withLinks = Some(Map(contactsLink(Up)))
).build
}
def toResources(foos: Seq[FooDto]): JsValue = {
ResourceBuilder(
withEmbedded = Some(Map(
"foos" -> foos.map(f => toResource(f))
)),
withLinks = Some(Map(foosLink(Self)))
).build
}
def toResource(foo: FooDto): JsValue = {
ResourceBuilder(
withData = Some(foo.toJson),
withLinks = Some(Map(
fooLink(Self, foo.id),
foosLink(Up)
))
).build
}
}
```
Create your routes:
```scala
trait FooRestPort extends FooAdapter {
val fooService = new FooService with FooComponent
val fooRoutes = path("foos") {
get {
complete {
fooService.getAll.map(f => toResources(f))
}
} ~
post {
entity(as[CreateFooCommand]) { newFoo =>
complete {
Created -> fooService.add(newFoo).map(id => newResource(id))
}
}
}
} ~
pathPrefix("foos" / Segment) { id =>
get {
complete {
fooService.getById(id).map {
case Some(f) => Marshal(toResource(f)).to[HttpResponse]
case _ => Marshal(NotFound -> notFoundResource).to[HttpResponse]
}
}
}
}
}
```
Curies Support
--------------
Curies are supported in two ways.
The first is per resource:
```scala
ResourceBuilder(
withCuries = Some(Seq(
Curie(name = "ts", href = "http://typesafe.com/{rel}")
))).build
```
The second, and most likely more common way, is to set them globally:
```scala
ResourceBuilder.curies(Seq(
Curie(name = "ts", href = "http://typesafe.com/{rel}"),
Curie(name = "akka", href = "http://akka.io/{rel}")
))
```
Note: If you mix global and resource based curies they will be combined. Currently we do not check for duplicate entries.
For the links pointing to a curie, just prefix the key with the curie name and colon (ex "ts:info"). If a colon is found in a key, we do not alter the href by adding X-Forwarded data or the request host/port.
Array of Links Support
----------------------
If you require an array of links:
```json
{
"_links": {
"multiple_links": [
{
"href": "http://www.test.com?foo=bar",
"name": "one"
},
{
"href": "http://www.test.com?bar=baz",
"name": "two"
}
]
}
}
```
This can be achieved by using the Links class which accepts a Sequence of Link:
```scala
Map(
"multiple_links" -> Links(Seq(
Link(href = url, name = Some("one")),
Link(href = url, name = Some("two"))
)))
```
HttpRequest Support
-------------------
By default the HAL links will not include the host or port.
If you would like host, port, or path prefix included, provide the HttpRequest.
```scala
def toResource(foo: FooDto, req: HttpRequest): JsValue = {
ResourceBuilder(
withRequest = req,
withData = Some(foo.toJson),
withLinks = Some(Map(
fooLink("self", foo.id),
foosLink("parent")
))
).build
}
```
This will produce a link with either the current host's information OR construct the links based on
the X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-Port, and X-Forwarded-Prefix headers.
HAL Browser
-----------
To expose HAL Browser from your API add the halBrowser route.
```scala
val routes = otherRoutes ~ halBrowserRoutes
```
The browser will be available at /halbrowser.
TODO
-----------
Find more contributors (hint).