+htc,doc #18657,#18665 FormData javadsl and FormField docs

This commit is contained in:
Konrad Malawski 2015-10-08 10:25:47 +02:00
parent a17604500f
commit 4e7999cf0a
8 changed files with 93 additions and 45 deletions

View file

@ -5,6 +5,7 @@
package docs.http.javadsl.server;
import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.model.FormData;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.headers.RawHeader;
import akka.http.javadsl.server.Marshallers;
@ -14,7 +15,9 @@ import akka.http.javadsl.server.values.FormField;
import akka.http.javadsl.server.values.FormFields;
import akka.http.javadsl.server.values.Headers;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.japi.Pair;
import docs.http.scaladsl.server.directives.Person;
import org.junit.Ignore;
import org.junit.Test;
public class FormFieldRequestValsExampleTest extends JUnitRouteTest {
@ -33,11 +36,14 @@ public class FormFieldRequestValsExampleTest extends JUnitRouteTest {
);
// tests:
final FormData formData = FormData.create(
Pair.create("name", "Blippy"),
Pair.create("age", "42"));
final HttpRequest request =
HttpRequest
.POST("/");
// .withFormData(); // FIXME awaits resolution of https://github.com/akka/akka/issues/18665
testRoute(route).run(request).assertEntity("Name: ..., age: ...");
.POST("/")
.withEntity(formData.toEntity());
testRoute(route).run(request).assertEntity("Name: Blippy, age: 42");
//#simple
}
@ -45,21 +51,22 @@ public class FormFieldRequestValsExampleTest extends JUnitRouteTest {
@Test
public void testFormFieldValsUnmarshaling() {
//#custom-unmarshal
FormField<SampleId> sampleId = FormFields.fromString("id", s -> new SampleId(Integer.valueOf(s)), SampleId.class);
FormField<SampleId> sampleId = FormFields.fromString("id", SampleId.class, s -> new SampleId(Integer.valueOf(s)));
final Route route =
route(
handleWith1(sampleId, (ctx, id) ->
ctx.complete(String.format("SampleId: %s", id))
handleWith1(sampleId, (ctx, sid) ->
ctx.complete(String.format("SampleId: %s", sid.id))
)
);
// tests:
final FormData formData = FormData.create(Pair.create("id", "1337"));
final HttpRequest request =
HttpRequest
.POST("/");
// .withFormData(); // FIXME awaits resolution of https://github.com/akka/akka/issues/18665
testRoute(route).run(request).assertEntity("Name: ..., age: ...");
.POST("/")
.withEntity(formData.toEntity());
testRoute(route).run(request).assertEntity("SampleId: 1337");
//#custom-unmarshal
}
@ -72,4 +79,5 @@ public class FormFieldRequestValsExampleTest extends JUnitRouteTest {
}
}
}

View file

@ -7,27 +7,19 @@ A collection of pre-defined :ref:`request-vals-java` that can be used to extract
Description
-----------
Header request values allow extracting ``HttpHeader`` values or concrete instances from HTTP requests.
``FormField`` request values allow extracting fields submitted as ``application/x-www-form-urlencoded`` values or concrete instances from HTTP requests.
The ``RequestVal`` builder is made up of 2 steps, initially you need to pick which Header to extract (``byName`` or
``byClass``) and then you need to pick if the header is optionally available or required (i.e. the route should not
match if the header is not present in the request). This is done using one of the below depicted methods::
RequestVal<T> instance()
RequestVal<<Option<T>> optionalInstance()
RequestVal<String> value()
RequestVal<Option<String>> optionalValue()
Examples
--------
``Headers.byClass(Class[HttpHeader])``
Extracting form fields of a certain primitive type from a request:
.. includecode:: ../../../code/docs/http/javadsl/server/HeaderRequestValsExampleTest.java
:include: by-class
.. includecode:: ../../../code/docs/http/javadsl/server/FormFieldRequestValsExampleTest.java#simple
``Headers.byName(String)``
Extracting values of custom type from a request by providing a conversion function:
.. includecode:: ../../../code/docs/http/javadsl/server/HeaderRequestValsExampleTest.java
:include: by-name
.. includecode:: ../../../code/docs/http/javadsl/server/FormFieldRequestValsExampleTest.java#custom-unmarshal

View file

@ -22,12 +22,12 @@ match if the header is not present in the request). This is done using one of th
Examples
--------
``Headers.byClass(Class[HttpHeader])``
Extracting a header by using a specific ``Header`` class (which are pre-defined in ``akka.http.javadsl.model.headers.*``):
.. includecode:: ../../../code/docs/http/javadsl/server/HeaderRequestValsExampleTest.java
:include: by-class
``Headers.byName(String)``
Extracting arbitrary headers by their name, for example custom headers (usually starting with ``X-...``):
.. includecode:: ../../../code/docs/http/javadsl/server/HeaderRequestValsExampleTest.java
:include: by-name

View file

@ -0,0 +1,37 @@
/**
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.javadsl.model;
import akka.http.impl.model.parser.CharacterClasses;
import akka.http.impl.util.JavaMapping;
import akka.http.impl.util.StringRendering;
import akka.http.scaladsl.model.Uri.Query;
import akka.http.scaladsl.model.UriRendering;
import akka.japi.Pair;
/**
* Simple model for `application/x-www-form-urlencoded` form data.
*/
public abstract class FormData {
public abstract Query fields();
public RequestEntity toEntity() {
return toEntity(HttpCharsets.UTF_8);
}
public RequestEntity toEntity(HttpCharset charset) {
// TODO this logic is duplicated in scaladsl.model.FormData, spent hours trying to DRY it but compiler freaked out in a number of ways... -- ktoso
final akka.http.scaladsl.model.HttpCharset c = (akka.http.scaladsl.model.HttpCharset) charset;
final StringRendering render = (StringRendering) UriRendering.renderQuery(new StringRendering(), this.fields(), c.nioCharset(), CharacterClasses.unreserved());
return HttpEntities.create(ContentType.create(MediaTypes.APPLICATION_X_WWW_FORM_URLENCODED, charset), render.get());
}
@SafeVarargs
public static FormData create(Pair<String, String>... fields) {
return akka.http.scaladsl.model.FormData.create(fields);
}
}

View file

@ -4,10 +4,25 @@
package akka.http.scaladsl.model
import akka.http.impl.model.parser.CharacterClasses
import akka.http.impl.util.StringRendering
import akka.http.javadsl.{ model jm }
import akka.http.scaladsl.model.HttpCharsets._
import akka.http.scaladsl.model.MediaTypes._
/**
* Simple model for `application/x-www-form-urlencoded` form data.
*/
final case class FormData(fields: Uri.Query)
final case class FormData(fields: Uri.Query) extends jm.FormData {
override def toEntity: akka.http.scaladsl.model.RequestEntity =
toEntity(HttpCharsets.`UTF-8`)
def toEntity(charset: HttpCharset): akka.http.scaladsl.model.RequestEntity = {
// TODO this logic is duplicated in javadsl.model.FormData, spent hours trying to DRY it but compiler freaked out in a number of ways... -- ktoso
val render: StringRendering = UriRendering.renderQuery(new StringRendering, this.fields, charset.nioCharset, CharacterClasses.unreserved)
HttpEntity(ContentType(`application/x-www-form-urlencoded`, `UTF-8`), render.get)
}
}
object FormData {
val Empty = FormData(Uri.Query.Empty)
@ -17,4 +32,7 @@ object FormData {
def apply(fields: (String, String)*): FormData =
if (fields.isEmpty) Empty else FormData(Uri.Query(fields: _*))
def create(fields: Array[akka.japi.Pair[String, String]]): FormData =
if (fields.isEmpty) Empty else FormData(Uri.Query(fields.map(_.toScala): _*))
}

View file

@ -6,12 +6,12 @@ package akka.http.javadsl.server
package values
import java.{ lang jl }
import akka.http.impl.server.{ FormFieldImpl, Util }
import akka.http.scaladsl.unmarshalling._
import akka.japi.function.Function
import akka.japi.{ Option JOption }
import akka.http.impl.server.{ Util, FormFieldImpl }
import akka.http.scaladsl.unmarshalling._
import scala.reflect.ClassTag
trait FormField[T] extends RequestVal[T] {
@ -37,7 +37,7 @@ object FormFields {
def hexLongValue(name: String): FormField[jl.Long] = FormFieldImpl(name.as(Unmarshaller.HexLong))
/** Unmarshals the `name` field using the provided `convert` function. */
def fromString[T](name: String, convert: Function[String, T], clazz: Class[T]): FormField[T] = {
def fromString[T](name: String, clazz: Class[T], convert: Function[String, T]): FormField[T] = {
implicit val tTag: ClassTag[T] = ClassTag(clazz)
FormFieldImpl(name.as(Util.fromStringUnmarshallerFromFunction(convert)))
}

View file

@ -5,22 +5,17 @@
package akka.http.javadsl.server.values
import java.util.AbstractMap.SimpleEntry
import java.util.{ Collection JCollection, Map JMap }
import java.{ lang jl }
import java.util.{ Map JMap, Collection JCollection }
import akka.http.impl.server.{ ParameterImpl, StandaloneExtractionImpl, Util }
import akka.http.javadsl.server.RequestVal
import akka.http.scaladsl.server.directives.ParameterDirectives
import akka.http.scaladsl.unmarshalling.Unmarshaller
import akka.japi.function.Function
import scala.reflect.ClassTag
import akka.japi.{ Option JOption }
import akka.http.impl.server.{ Util, StandaloneExtractionImpl, ParameterImpl }
import akka.http.javadsl.server.RequestVal
import akka.http.scaladsl.server.Directive1
import akka.http.scaladsl.server.directives.ParameterDirectives.ParamMagnet
import scala.reflect.ClassTag
/**
* A RequestVal representing a query parameter of type T.
@ -65,7 +60,8 @@ object Parameters {
def asCollection: RequestVal[JCollection[JMap.Entry[String, String]]] =
StandaloneExtractionImpl(ParameterDirectives.parameterSeq.map(_.map(e new SimpleEntry(e._1, e._2): JMap.Entry[String, String]).asJavaCollection))
def fromString[T](name: String, convert: Function[String, T], clazz: Class[T]): Parameter[T] = {
/** Unmarshals the `name` field using the provided `convert` function. */
def fromString[T](name: String, clazz: Class[T], convert: Function[String, T]): Parameter[T] = {
implicit val tTag: ClassTag[T] = ClassTag(clazz)
ParameterImpl(name.as(Util.fromStringUnmarshallerFromFunction(convert)))
}

View file

@ -5,10 +5,9 @@
package akka.http.scaladsl.marshalling
import java.nio.CharBuffer
import akka.http.impl.model.parser.CharacterClasses
import akka.http.scaladsl.model.MediaTypes._
import akka.http.scaladsl.model._
import akka.http.impl.util.StringRendering
import akka.util.ByteString
trait PredefinedToEntityMarshallers extends MultipartMarshallers {
@ -53,9 +52,7 @@ trait PredefinedToEntityMarshallers extends MultipartMarshallers {
implicit val FormDataMarshaller: ToEntityMarshaller[FormData] =
Marshaller.withOpenCharset(`application/x-www-form-urlencoded`) { (formData, charset)
val query = Uri.Query(formData.fields: _*)
val string = UriRendering.renderQuery(new StringRendering, query, charset.nioCharset, CharacterClasses.unreserved).get
HttpEntity(ContentType(`application/x-www-form-urlencoded`, charset), string)
formData.toEntity(charset)
}
implicit val MessageEntityMarshaller: ToEntityMarshaller[MessageEntity] = Marshaller strict { value