The javadoc:Value[Value] is an unified and type-safe API across all parameter types:
For learning purpose we are going to show all the javadoc:Value[Value] features using query parameters, but keep in mind these features apply to all the parameter types.
Single value is available via value() or [type]Value() functions:
{
get("/", ctx -> {
String name = ctx.query("name").value(); // (1)
float score = ctx.query("score").floatValue(); // (2)
boolean enabled = ctx.query("enabled").booleanValue(); // (3)
BigDecimal decimal = ctx.query("decimal").value(BigDecimal::new); // (4)
...
});
}{
get("/") {
val name = ctx.query("name").value() // (1)
val score = ctx.query("score").floatValue() // (2)
val enabled = ctx.query("enabled").booleanValue() // (3)
val decimal = ctx.query("decimal").value(::BigDecimal) // (4)
...
});
}The value() family methods always retrieve a value. If there is no value, a
BadRequest(400) response is generated. So single value parameters are required:
-
Access to query parameter
qand convert toString:-
/?name=foo⇒foo -
/⇒Bad Request(400): Missing value: "q"
-
-
Access to query parameter
scoreand convert tofloat:-
/?score=1⇒1.0 -
/?score=string⇒Bad Request(400)(Type mismatch: cannot convert to number) -
/⇒Bad Request(400)(Required parameterscoreis not present)
-
-
Access to query parameter
enabledand convert toboolean:-
/?enabled=true⇒true -
/?enabled=string⇒Bad Request(400)(Type mismatch: cannot convert to boolean) -
/⇒Bad Request(400): Missing value: "enabled"
-
-
Access to query parameter
decimaland convert toBigDecimal:-
/?decimal=2.3⇒2.3 -
/?decimal=string⇒Bad Request(400)(Type mismatch: cannot convert to BigDecimal) -
/⇒Bad Request(400): Missing value: "decimal"
-
Default and optional value are available in two different ways:
-
Providing a default value
-
Requesting an
java.util.Optionalobject
{
get("/search", ctx -> {
String q = ctx.query("q").value("*:*"); // (1)
return q;
});
get("/search", ctx -> {
Optional<String> q = ctx.query("q").toOptional(); // (2)
return q;
});
}{
get("/search") {
val q = ctx.query("q").value("*:*") // (1)
q
});
get("/search") {
val q = ctx.query("q").toOptional(); // (2)
q
});
}-
Access to query variable
qand convert toStringwith a default value of:.-
/search?q=foo⇒foo -
/search⇒:
-
-
Access to query variable
qand convert toOptional<String>:-
/search?q=foo⇒Optional[foo] -
/search⇒Optional.empty
-
Multiple values are available via functions:
-
javadoc:Value[toList]: Returns a
java.util.Listof values -
javadoc:Value[toSet]: Returns a
java.util.Setof values
{
get("/", ctx -> {
List<String> q = ctx.query("q").toList(); // (1)
List<Integer> n = ctx.query("n").toList(Integer.class); // (2)
List<BigDecimal> decimals = ctx.query("d").toList(BigDecimal::new); // (3)
...
});
}{
get("/") {
val q = ctx.query("q").toList() // (1)
val n = ctx.query("n").toList(Integer.class) // (2)
val decimals = ctx.query("d").toList(::BigDecimal) // (3)
...
});
}-
Multi-value query parameter
qasList<String>:-
/⇒[](empty list) -
/?q=foo⇒[foo] -
/?q=foo&q=bar⇒[foo, bar]
-
-
Multi-value query parameter as
List<Integer>-
/⇒[](empty list) -
/?n=1⇒[1] -
/?n=1&n=2⇒[1, 2]
-
-
Multi-value query parameter as
List<BigDecimal>-
/⇒[](empty list) -
/?d=1⇒[1] -
/?d=1&n=2⇒[1, 2]
-
The javadoc:Value[Value API] provides a way to traverse and parse structured data:
/?user.name=root&user.pass=pass
{
get("/", ctx -> {
Value user = ctx.query("user"); // (1)
String name = user.get("name").value(); // (2)
String pass = user.get("pass").value(); // (3)
String email = user.get("email").value("none"); // (4)
...
}}
}{
get("/") {
val user = ctx.query("user") // (1)
val name = user["name"].value() // (2)
val pass = user["pass"].value() // (3)
val email = user["email"].value("none") // (4)
...
}}
}-
Get the
usernode -
Get the
namevalue fromusernode -
Get the
passvalue fromusernode -
Get the
emailvalue fromusernode. This is an optional value.
The javadoc:Value[get, java.lang.String] takes a path and returns another value. The returning
value may or may not exists.
Structured data decoder supports dot and bracket notation:
?member.firstname=Pedro&member.lastname=Picapiedra
?member[firstname]=Pedro&member[lastname]=Picapiedra
?members[0]firstname=Pedro&members[0]lastname=Picapiedra
Structured data decoder is able to reconstruct a POJO (Plain Old Java Object) from:
We are going to use a Group and Member objects to demonstrate how the decoder works:
class Member {
public final String firstname;
public final String lastName;
public Member(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
}
class Group {
public final String id;
public final List<Member> members;
public Member(String id, List<Member> members) {
this.id = id;
this.members = members;
}
}class Member (val firstname: String, lastName: String)
class Group (val id: String, val members: List<Member>)/?firstname=Pedro&lastName=Picapiedra
{
get("/", ctx -> {
Member member = ctx.query(Member.class);
...
});
}{
get("/") {
val member = ctx.query<Member>()
...
}
}/?member.firstname=Pedro&member.lastName=Picapiedra
{
get("/", ctx -> {
Member member = ctx.query("member").to(Member.class);
...
});
}{
get("/") {
val member = ctx.query("member").to<Member>()
...
});
}Tabular data uses the bracket array notation:
/?[0]firstname=Pedro&[0]lastName=Picapiedra&[1]firstname=Pablo&[2]lastname=Marmol
{
get("/", ctx -> {
List<Member> members = ctx.query().toList(Member.class);
...
});
}{
get("/") {
val members = ctx.query<List<Member>>()
...
});
}/?id=flintstones&members[0]firstname=Pedro&members[0]lastName=Picapiedra
{
get("/", ctx -> {
Group group = ctx.query(Group.class);
...
});
}{
get("/") {
val group = ctx.query<Group>()
...
});
}The target POJO must follow one of these rules:
-
Has a zero argguments/default constructor, or
-
Has only one constructor
-
Has multiple constructors, but only one is annotated with Inject
The decoder matches HTTP parameters in the following order:
-
As constructor arguments
-
As setter method
HTTP parameter name which are not a valid Java identifier must be annotated with Named:
class Member {
public final String firstname;
public final String lastname;
public Member(@Named("first-name") String firstname, @Named("last-name") String lastname) {
....
}
}class Member (@Named("first-name") val firstname: String, @Named("last-name") val lastName: String){love}{love}