parent
29029be31d
commit
9e6dab4ee1
1 changed files with 177 additions and 3 deletions
|
|
@ -1,11 +1,185 @@
|
|||
Migration Guide from spray
|
||||
Migration Guide from Spray
|
||||
==========================
|
||||
|
||||
**TODO - will be written shortly.**
|
||||
General notes
|
||||
-------------
|
||||
|
||||
Features which are not ported to the akka-http:
|
||||
|
||||
- ``respondWithStatus`` also known as ``overrideStatusCode`` has not been forward ported to Akka HTTP,
|
||||
as it has been seen mostly as an anti-pattern. More information here: https://github.com/akka/akka/issues/18626
|
||||
- ``respondWithMediaType`` was considered an anti-pattern in spray and is not ported to Akka HTTP.
|
||||
Instead users should rely on content type negotiation as Akka HTTP implements it.
|
||||
More information here: https://github.com/akka/akka/issues/18625
|
||||
- :ref:`registeringCustomMediaTypes` changed from Spray in order not to rely on global state.
|
||||
- :ref:`registeringCustomMediaTypes` changed from Spray in order not to rely on global state.
|
||||
|
||||
Removed HttpService
|
||||
-------------------
|
||||
|
||||
Spray’s ``HttpService`` was removed. This means that scala code like this::
|
||||
|
||||
val service = system.actorOf(Props(new HttpServiceActor(routes)))
|
||||
IO(Http)(system) ! Http.Bind(service, "0.0.0.0", port = 8080)
|
||||
|
||||
needs to be changed into::
|
||||
|
||||
Http().bindAndHandle(routes, "0.0.0.0", port = 8080)
|
||||
|
||||
Changes in Marshalling
|
||||
----------------------
|
||||
|
||||
Marshaller.of can be replaced with ``Marshaller.withFixedContentType``.
|
||||
|
||||
Was::
|
||||
|
||||
Marshaller.of[JsonApiObject](`application/json`) { (value, contentType, ctx) =>
|
||||
ctx.marshalTo(HttpEntity(contentType, value.toJson.toString))
|
||||
}
|
||||
|
||||
Replace with::
|
||||
|
||||
Marshaller.withFixedContentType(`application/json`) { obj =>
|
||||
HttpEntity(`application/json`, obj.toJson.compactPrint)
|
||||
}
|
||||
|
||||
Akka HTTP marshallers support content negotiation, now it's not necessary to specify content type
|
||||
when creating one “super” marshaller from other marshallers:
|
||||
|
||||
Before::
|
||||
|
||||
ToResponseMarshaller.oneOf(
|
||||
`application/vnd.api+json`,
|
||||
`application/json`
|
||||
)(
|
||||
jsonApiMarshaller,
|
||||
jsonMarshaller
|
||||
}
|
||||
|
||||
After::
|
||||
|
||||
Marshaller.oneOf(
|
||||
jsonApiMarshaller,
|
||||
jsonMarshaller
|
||||
)
|
||||
|
||||
Changes in Unmarshalling
|
||||
------------------------
|
||||
|
||||
Akka Http contains a set of predefined unmarshallers. This means that scala code like this::
|
||||
|
||||
Unmarshaller[Entity](`application/json`) {
|
||||
case HttpEntity.NonEmpty(contentType, data) =>
|
||||
data.asString.parseJson.convertTo[Entity]
|
||||
}
|
||||
|
||||
needs to be changed into::
|
||||
|
||||
Unmarshaller
|
||||
.stringUnmarshaller
|
||||
.forContentTypes(`application/json`)
|
||||
.map(_.parseJson.convertTo[Entity])
|
||||
|
||||
Changes in MediaTypes
|
||||
---------------------
|
||||
|
||||
``MediaType.custom`` can be replaced with specific methods in ``MediaType`` object.
|
||||
|
||||
Was::
|
||||
|
||||
MediaType.custom("application/vnd.acme+json")
|
||||
|
||||
Replace with::
|
||||
|
||||
MediaType.applicationWithFixedCharset("application/vnd.acme+json", HttpCharsets.`UTF-8`)
|
||||
|
||||
Changes in Rejection Handling
|
||||
-----------------------------
|
||||
|
||||
``RejectionHandler`` now uses a builder pattern – see the example:
|
||||
|
||||
Before::
|
||||
|
||||
def rootRejectionHandler = RejectionHandler {
|
||||
case Nil =>
|
||||
requestUri { uri =>
|
||||
logger.error("Route: {} does not exist.", uri)
|
||||
complete((NotFound, mapErrorToRootObject(notFoundError)))
|
||||
}
|
||||
case AuthenticationFailedRejection(cause, challengeHeaders) :: _ => {
|
||||
logger.error(s"Request is rejected with cause: $cause")
|
||||
complete((Unauthorized, mapErrorToRootObject(unauthenticatedError)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
After::
|
||||
|
||||
RejectionHandler
|
||||
.newBuilder()
|
||||
.handle {
|
||||
case AuthenticationFailedRejection(cause, challengeHeaders) =>
|
||||
logger.error(s"Request is rejected with cause: $cause")
|
||||
complete((Unauthorized, mapErrorToRootObject(unauthenticatedError)))
|
||||
.handleNotFound { ctx =>
|
||||
logger.error("Route: {} does not exist.", ctx.request.uri.toString())
|
||||
ctx.complete((NotFound, mapErrorToRootObject(notFoundError)))
|
||||
}
|
||||
.result()
|
||||
.withFallback(RejectionHandler.default)
|
||||
|
||||
Changes in HTTP Client
|
||||
----------------------
|
||||
|
||||
The Spray-client pipeline was removed. Http’s ``singleRequest`` should be used instead of ``sendReceive``::
|
||||
|
||||
//this will not longer work
|
||||
val token = Authorization(OAuth2BearerToken(accessToken))
|
||||
val pipeline: HttpRequest => Future[HttpResponse] = (addHeader(token) ~> sendReceive)
|
||||
val patch: HttpRequest = Patch(uri, object))
|
||||
|
||||
pipeline(patch).map { response ⇒
|
||||
…
|
||||
}
|
||||
|
||||
needs to be changed into::
|
||||
|
||||
val request = HttpRequest(
|
||||
method = PATCH,
|
||||
uri = Uri(uri),
|
||||
headers = List(Authorization(OAuth2BearerToken(accessToken))),
|
||||
entity = HttpEntity(MediaTypes.`application/json`, object)
|
||||
)
|
||||
|
||||
http.singleRequest(request).map {
|
||||
case … => …
|
||||
}
|
||||
|
||||
Changes in Headers
|
||||
------------------
|
||||
|
||||
All HTTP headers have been moved to the ``akka.http.scaladsl.model.headers._`` package.
|
||||
|
||||
|
||||
Changes in form fields and file upload directives
|
||||
-------------------------------------------------
|
||||
|
||||
With the streaming nature of http entity, it’s important to have a strict http entity before accessing
|
||||
multiple form fields or use file upload directives.
|
||||
One solution might be using next directive before working with form fields::
|
||||
|
||||
val toStrict: Directive0 = extractRequest flatMap { request =>
|
||||
onComplete(request.entity.toStrict(5.seconds)) flatMap {
|
||||
case Success(strict) =>
|
||||
mapRequest( req => req.copy(entity = strict))
|
||||
case _ => reject
|
||||
}
|
||||
}
|
||||
|
||||
And one can use it like this::
|
||||
|
||||
toStrict {
|
||||
formFields("name".as[String]) { name =>
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue