pekko/akka-docs/rst/scala/http/routing-dsl/case-class-extraction.rst
Johan Andrén 29029be31d !htp #18919 #19519 New JavaDSL for Akka HTTP (#20518)
* !htt #18919 #19519 Align Java HTTP server DSL with Scala

This commits replaces the Java HTTP server DSL with a Java-8 centric one
which exposes all scala DSL concepts to be usable from Java, including
custom directives, (un)marshallers, rejections, headers, and type safety
for path and query parameters.

* Add RequestContext and RouteResult to Java DSL
fix websockets
WIP bring java docs up to date.
This applies some updates to the root-level documentation

* [htp] Fix java documentation to correctly mention timeouts

Timeouts are configured the same in Java and Scala. Hence, linking to the
scala docs for timeouts from Java.

* =htc fix optionalHeaderValueByType in Java

* =htt #20200 fix java testkit always using NoLogging instead logger

* +htt actually run new javadsl tests, allow overriding config

* =htt improve javadsl test infra with more details when fails

* =htt fix bug in wrong path matcher exposed

* +htp add missing remaining path matcher

* =htp Java DSL cookie tests fixed

* =htt Java DSL ParameterDirectivesTest fixed

Protect the tweets from scalariform

Incorrect response expectations in cache condition directives spec fixed

* =htt Path directives for Java DSL

* +!htt PathMatchers rewritten, made uniform and tests passing

* Bugfix in java reject and a little test-boyscouting

* Revert "Incorrect response expectations in cache condition directives spec fixed"

This reverts commit cd50e89d45db010309f8249b090ea654ebb11c7a.

* +htc HttpAPIsTest is compile time only, not for running
Also, moved from the client package since not strictly a client test.

SecurityDirectives passing

Two faulty tests and two actual bugs.

Fix for cache condition spec not working

* Not sending in Unit instad of the implicit magnet in the test
* HeaderMagnet now works as expected
* Java API added for - and + on DateTime

PetStore example and test fixed

* Annotations to make marshalling work without default constructor
* Made model class immutable

Incorrect tests fixed

Some scaladoc boyscouting as bonus

* =htt RequestValTest sprinkled out across multiple directive tests

Client ip extraction test with incorrect header name fixed.

* =htt Incorrect CodingDirectivesTest fixed.

* =htt Bugfix for Java Unmarshaller.firstOf and fixes to JavaRouteTest

* =htt MarshallerTest fixed

* Missing seal signature added to JavaDSL
* More consistent (with Scala) test kit setup for Java
* missing Javadocs added
* Thread.sleep in default exception handler removed

* =htt copy directive docs, prepare for finishing it up

* +htt SecurityDirectives.authorize variants and test coverage added

* +htt Custom headers in Java DSL

* =htt WIP on java docs

* +htp add missing parameterOrDefault directive
Fixed a lot of doc warnings

* =htc intense progress on javadsl docs

* =htc #20470 Link to issue about docs and fix compile error
compile, migration guide
don't mima check http-experimental

* =htt Java DSL doc warnings fixed.
Only `Could not lex literal_block` ones left now

* =htc fix mima settings

* =doc fix MethodDirectives doc test with custom method

* =htc fix coding directives spec after bad merge

* =htc fix concat being corresponding to route() in javadsl

* =htt Disable consistency check for route/concat as it fails only on ci server

* !htt Minor fixes to PathMatchers
2016-05-16 10:38:40 +02:00

68 lines
No EOL
4.1 KiB
ReStructuredText

.. _Case Class Extraction:
Case Class Extraction
=====================
The value extraction performed by :ref:`Directives` is a nice way of providing your route logic with interesting request
properties, all with proper type-safety and error handling. However, in some case you might want even more.
Consider this example:
.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala
:snippet: example-1
Here the :ref:`-parameters-scala-` directives is employed to extract three ``Int`` values, which are then used to construct an
instance of the ``Color`` case class. So far so good. However, if the model classes we'd like to work with have more
than just a few parameters the overhead introduced by capturing the arguments as extractions only to feed them into the
model class constructor directly afterwards can somewhat clutter up your route definitions.
If your model classes are case classes, as in our example, Akka HTTP supports an even shorter and more concise
syntax. You can also write the example above like this:
.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala
:snippet: example-2
You can postfix any directive with extractions with an ``as(...)`` call. By simply passing the companion object of your
model case class to the ``as`` modifier method the underlying directive is transformed into an equivalent one, which
extracts only one value of the type of your model class. Note that there is no reflection involved and your case class
does not have to implement any special interfaces. The only requirement is that the directive you attach the ``as``
call to produces the right number of extractions, with the right types and in the right order.
If you'd like to construct a case class instance from extractions produced by *several* directives you can first join
the directives with the ``&`` operator before using the ``as`` call:
.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala
:snippet: example-3
Here the ``Color`` class has gotten another member, ``name``, which is supplied not as a parameter but as a path
element. By joining the ``path`` and ``parameters`` directives with ``&`` you create a directive extracting 4 values,
which directly fit the member list of the ``Color`` case class. Therefore you can use the ``as`` modifier to convert
the directive into one extracting only a single ``Color`` instance.
Generally, when you have routes that work with, say, more than 3 extractions it's a good idea to introduce a case class
for these and resort to case class extraction. Especially since it supports another nice feature: validation.
.. caution:: There is one quirk to look out for when using case class extraction: If you create an explicit companion
object for your case class, no matter whether you actually add any members to it or not, the syntax presented above
will not (quite) work anymore. Instead of ``as(Color)`` you will then have to say ``as(Color.apply)``. This behavior
appears as if it's not really intended, so this might be improved in future Scala versions.
Case Class Validation
---------------------
In many cases your web service needs to verify input parameters according to some logic before actually working with
them. E.g. in the example above the restriction might be that all color component values must be between 0 and 255.
You could get this done with a few :ref:`-validate-` directives but this would quickly become cumbersome and hard to
read.
If you use case class extraction you can put the verification logic into the constructor of your case class, where it
should be:
.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala
:snippet: example-4
If you write your validations like this Akka HTTP's case class extraction logic will properly pick up all error
messages and generate a ``ValidationRejection`` if something goes wrong. By default, ``ValidationRejections`` are
converted into ``400 Bad Request`` error response by the default :ref:`RejectionHandler <The RejectionHandler>`, if no
subsequent route successfully handles the request.