@Post

Annotate methods with @Post for HTTP POST web routes.

Post JSON

A method with @Post is by default expecting a JSON body.

In the example below customer is populated via body content expected to be JSON (ctx.bodyAsClass().

@Post
void save(Customer customer) {
  ...
}

The generated code for the above is:

ApiBuilder.post("/customers", ctx -> {
  ctx.status(201);
  Customer customer = ctx.bodyAsClass(Customer.class);
  controller.save(customer);
});

@Form (Simple form)

If the method additionally has @Form then the method parameters default to be form parameters.

In the following example name, email and url all default to be form parameters.

@Form @Post("register")
void register(String name, String email, String url) {
  ...
}

@FormParam

For the example above we could alternatively use @FormParam on each of the form parameters rather than @Form. We then get:

@Post("register")
void register(@FormParam String name, @FormParam String email, @FormParam String url) {
  ...
}

The expectation is that we most often would use @Form because it reduces "annotation noise" and that we will very rarely use @FormParam. Potentially we only use @FormParam if the parameter name is snake case or similar that doesn't match a valid Java/Kotlin identifier.

The generated code for both cases above is the same:

ApiBuilder.post("/customers/register", ctx -> {
  ctx.status(201);
  String name = ctx.formParam("name");
  String email = ctx.formParam("email");
  String url = ctx.formParam("url");
  controller.register(name, email, url);
});

@Form with "Form Beans" (Large forms)

In the case where we are posting a form with a lot of parameters we can define a bean with properties for each of the form parameters (rather than have a method with lots of arguments).

"Form beans" currently must have a default no-arg constructor and bean properties (accessible setters or fields).

Using a form bean can make the code nicer (method signature) and gives us a nicer option to use validation annotations on the "form bean" properties.

public class MyForm {

  @Size(min=2, max=100)
  public String name;
  public String email;
  public String url;
}
@Form @Post("register")
void register(MyForm myForm) {
  ...
}
The generated code for the above is.
ApiBuilder.post("/contacts/register", ctx -> {
  ctx.status(201);
  MyForm myForm =  new MyForm();
  myForm.name = ctx.formParam("name");
  myForm.email = ctx.formParam("email");
  myForm.url = ctx.formParam("url");

  controller.register(myForm);
});

"Form beans" are nice with forms with lots of properties because they declutter our code and the generated code takes care of putting the values into our bean properties so that we don't have to write that code.

This use of @Form is very similar to JAX-RS @BeanParam except that the bean properties default be being form parameters. With JAX-RS we would put a @FormParam on every property that is a form parameter (which becomes noise on a large form).

Form beans with @QueryParam, @Header, @Cookie properties

The properties on a "form bean" default to being form parameters. We put @QueryParam, @Header or @Cookie on properties that are instead query params, headers or cookies.

public class MyForm {

  @Size(min=2, max=100)
  public String name;
  public String email;
  public String url;

  @QueryParam
  public Boolean overrideFlag;

  @Header
  public String ifModifiedSince;

  @Cookie
  public String myState;
}

The generated code populates from query params, headers and cookies. The generated code is:

ApiBuilder.post("/contacts/register", ctx -> {
  ctx.status(201);
  MyForm myForm =  new MyForm();
  myForm.name = ctx.formParam("name");
  myForm.email = ctx.formParam("email");
  myForm.url = ctx.formParam("url");
  myForm.overrideFlag = toBoolean(ctx.queryParam("overrideFlag"));     // queryParam !!
  myForm.ifModifiedSince = ctx.header("If-Modified-Since");            // header !!
  myForm.myState = ctx.cookie("myState");                              // cookie !!

  controller.register(myForm);
});

Kotlin "Form beans"

Right now we are limited to using a default constructor which means for Kotlin we need to use a normal class with properties (it would be nice to use data classes).

The matching Kotlin form is:

class MyForm {
  var name: String? = null
  var email: String? = null
  var email: url? = null
}