=== Context

A javadoc:Context[Context] allows you to interact with the HTTP request and manipulate the HTTP response.

In most cases, you access the context object as a parameter of your route handler:

.Java
[source, java, role="primary"]
----
{
  get("/", ctx -> { /* do important stuff with the 'ctx' variable */ });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  get("/") { /* the 'it' variable (or implicit ctx) holds the context */ }
}
----

javadoc:Context[Context] also provides derived information about the current request, such as matching locales based on the `Accept-Language` header. You can use javadoc:Context[locale] or javadoc:Context[locales] to present content matching the user's language preference.

These methods use `Locale.lookup(...)` and `Locale.filter(...)` to perform language tag matching. (See their overloads if you need to plug in a custom matching strategy).

To leverage language matching, you must tell Jooby which languages your application supports. Set the `application.lang` configuration property to a value compatible with the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language[Accept-Language] header:

.application.conf
[source, properties]
----
application.lang = en, en-GB, de
----

Or configure it programmatically using javadoc:Jooby[setLocales, java.util.List]:

.Java
[source, java, role="primary"]
----
{
  setLocales(Locale.GERMAN, new Locale("hu", "HU"));
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  setLocales(Locale.GERMAN, Locale("hu", "HU"))
}
----

If you don't explicitly set the supported locales, Jooby falls back to a single locale provided by `Locale.getDefault()`.

==== Parameters

There are several parameter types: `header`, `cookie`, `path`, `query`, `form`, `multipart`, `session`, and `flash`. They all share a unified, type-safe API for accessing and manipulating their values.

This section covers how to extract raw parameters. The next section covers how to convert them into complex objects using the <<core-context-value-api, Value API>>.

===== Header

HTTP headers allow the client and server to pass additional information.

.Java
[source, java, role="primary"]
----
{
  get("/", ctx -> {
    String token = ctx.header("token").value();      // <1>
    Value headers = ctx.headers();                   // <2>
    Map<String, String> headerMap = ctx.headerMap(); // <3>
    // ...
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  get("/") { ctx ->
    val token = ctx.header("token").value() // <1>
    val headers = ctx.headers()             // <2>
    val headerMap = ctx.headerMap()         // <3>
    // ...
  }
}
----

<1> Retrieves the header `token`.
<2> Retrieves all headers as a javadoc:value.Value[].
<3> Retrieves all headers as a Map.

===== Cookie

Request cookies are sent to the server via the `Cookie` header. Jooby provides simple key/value access:

.Cookies
[source, java, role="primary"]
----
{
  get("/", ctx -> {
    String token = ctx.cookie("token").value();      // <1>
    Map<String, String> cookieMap = ctx.cookieMap(); // <2>
    // ...
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  get("/") { ctx ->
    val token = ctx.cookie("token").value() // <1>
    val cookieMap = ctx.cookieMap()         // <2>
    // ...
  }
}
----

<1> Retrieves the cookie named `token`.
<2> Retrieves all cookies as a Map.

===== Path

Path parameters are part of the URI. Use the `{identifier}` notation to define a path variable.

.Syntax:
[source,java,role="primary"]
----
{
  get("/{id}", ctx -> ctx.path("id").value());                                 // <1>
  get("/@{id}", ctx -> ctx.path("id").value());                                // <2>
  get("/file/{name}.{ext}", ctx -> ctx.path("name") + "." + ctx.path("ext"));  // <3>
  get("/file/*", ctx -> ctx.path("*"));                                        // <4>
  get("/{id:[0-9]+}", ctx -> ctx.path("id"));                                  // <5>
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  get("/{id}") { ctx -> ctx.path("id").value() }                                 // <1>
  get("/@{id}") { ctx -> ctx.path("id").value() }                                // <2>
  get("/file/{name}.{ext}") { ctx -> ctx.path("name") + "." + ctx.path("ext") }  // <3>
  get("/file/*") { ctx -> ctx.path("*") }                                        // <4>
  get("/{id:[0-9]+}") { ctx -> ctx.path("id") }                                  // <5>
}
----

<1> Standard path variable `id`.
<2> Path variable `id` prefixed with `@`.
<3> Multiple variables: `name` and `ext`.
<4> Unnamed catchall path variable.
<5> Path variable strictly matching a regular expression.

.Accessing Path Variables
[source, java, role="primary"]
----
{
  get("/{name}", ctx -> {
    String pathString = ctx.getRequestPath();     // <1>
    Value path = ctx.path();                      // <2>
    Map<String, String> pathMap = ctx.pathMap();  // <3>
    String name = ctx.path("name").value();       // <4>
    // ...    
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  get("/{name}") { ctx ->
    val pathString = ctx.getRequestPath()  // <1>
    val path = ctx.path()                 // <2>
    val pathMap = ctx.pathMap()           // <3>
    val name = ctx.path("name").value()   // <4>
    // ...    
  }
}
----

<1> Access the `raw` path string (e.g., `/a b` returns `/a%20b`).
<2> Path as a javadoc:value.Value[] object (decoded).
<3> Path as a `Map<String, String>` (decoded).
<4> Specific path variable `name` as a `String` (decoded).

===== Query

The query string is the part of the URI that starts after the `?` character.

.Java
[source, java, role="primary"]
----
{
  get("/search", ctx -> {
    String queryString = ctx.queryString();                    // <1>
    QueryString query = ctx.query();                           // <2>
    Map<String, List<String>> queryMap = ctx.queryMultimap();  // <3>
    String q = ctx.query("q").value();                         // <4>
    SearchQuery searchQuery = ctx.query(SearchQuery.class);    // <5>
    // ...
  });
}

class SearchQuery {
   public final String q;
   public SearchQuery(String q) { this.q = q; }
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  get("/search") { ctx ->
    val queryString = ctx.queryString()         // <1>
    val query = ctx.query()                     // <2>
    val queryMap = ctx.queryMultimap()          // <3>
    val q = ctx.query("q").value()              // <4>
    val searchQuery = ctx.query<SearchQuery>()  // <5>
    // ...
  }
}

data class SearchQuery(val q: String)
----

<1> Access the `raw` query string (e.g., `?q=a%20b`).
<2> Query string as a javadoc:QueryString[] object (e.g., `{q=a b}`).
<3> Query string as a multi-value map (e.g., `{q=[a b]}`).
<4> Access decoded variable `q`. Throws a `400 Bad Request` if missing.
<5> Binds the query string directly to a `SearchQuery` object.

===== Formdata

Form data is sent in the HTTP body (or as part of the URI for `GET` requests) and is encoded as `application/x-www-form-urlencoded`.

.Java
[source, java, role="primary"]
----
{
  post("/user", ctx -> {
    Formdata form = ctx.form();                             // <1>
    Map<String, List<String>> formMap = ctx.formMultimap(); // <2>
    String userId = ctx.form("id").value();                 // <3>
    String pass = ctx.form("pass").value();                 // <4>
    User user = ctx.form(User.class);                       // <5>
    // ...
  });
}

class User {
   public final String id;
   public final String pass;
   public User(String id, String pass) {
     this.id = id;
     this.pass = pass;
   }
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  post("/user") { ctx ->
    val form = ctx.form()               // <1>
    val formMap = ctx.formMultimap()    // <2>
    val userId = ctx.form("id").value() // <3>
    val pass = ctx.form("pass").value() // <4>
    val user = ctx.form<User>()         // <5>
    // ...
  }
}

data class User(val id: String, val pass: String)
----

<1> Form as javadoc:Formdata[].
<2> Form as a multi-value map.
<3> Specific form variable `id`.
<4> Specific form variable `pass`.
<5> Form automatically bound to a `User` object.

===== Multipart & File Uploads

Multipart data is sent in the HTTP body and encoded as `multipart/form-data`. It is required for file uploads.

.Java
[source, java, role="primary"]
----
{
  post("/user", ctx -> {
    Multipart multipart = ctx.multipart();                            // <1>
    Map<String, List<String>> multipartMap = ctx.multipartMultimap(); // <2>
    String userId = ctx.multipart("id").value();                      // <3>
    String pass = ctx.multipart("pass").value();                      // <4>
    FileUpload pic = ctx.file("pic");                                 // <5>
    User user = ctx.multipart(User.class);                            // <6>
    // ...
  });
}

class User {
   public final String id;
   public final String pass;
   public final FileUpload pic;
   public User(String id, String pass, FileUpload pic) {
     this.id = id;
     this.pass = pass;
     this.pic = pic;
   }
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  post("/user") { ctx ->
    val multipart = ctx.multipart()              // <1>
    val multipartMap = ctx.multipartMultimap()   // <2>
    val userId = ctx.multipart("id").value()     // <3>
    val pass = ctx.multipart("pass").value()     // <4>
    val pic = ctx.file("pic")                    // <5>
    val user = ctx.multipart<User>()             // <6>
    // ...
  }
}

data class User(val id: String, val pass: String, val pic: FileUpload)
----

<1> Form as javadoc:Multipart[].
<2> Form as a multi-value map.
<3> Specific multipart text variable `id`.
<4> Specific multipart text variable `pass`.
<5> Single file upload named `pic`.
<6> Multipart form bound to a `User` object (including the file).

[NOTE]
.File Upload
====
File uploads are **only** available for multipart requests.

.Java
[source,java,role="primary"]
----
  FileUpload pic = ctx.file("pic");         // <1>
  List<FileUpload> pics = ctx.files("pic"); // <2>
  List<FileUpload> files = ctx.files();     // <3>
----

.Kotlin
[source,kotlin,role="secondary"]
----
  val pic = ctx.file("pic")   // <1>
  val pics = ctx.files("pic") // <2>
  val files = ctx.files()     // <3>
----

<1> Single file upload named `pic`
<2> Multiple file uploads named `pic`
<3> All file uploads
====

===== Session

Session parameters are available via javadoc:Context[session] or javadoc:Context[sessionOrNull]. (See the full <<web-session, Session Chapter>> for details).

.Java
[source,java,role="primary"]
----
  Session session = ctx.session();                      // <1>
  String attribute = ctx.session("attribute").value();  // <2>
----

.Kotlin
[source,kotlin,role="secondary"]
----
  val session = ctx.session()                             // <1>
  val attribute = session.attribute("attribute").value()  // <2>
----

<1> Finds an existing Session or creates a new one.
<2> Gets a specific session attribute.

===== Flash

Flash parameters transport success/error messages between requests. They are similar to a session, but their lifecycle is shorter: **data is kept for only one request**.

.Java
[source,java,role="primary"]
----
  get("/", ctx -> {
    return ctx.flash("success").value("Welcome!"); // <3>
  });

  post("/save", ctx -> {
    ctx.flash().put("success", "Item created");    // <1>
    return ctx.sendRedirect("/");                  // <2>
  });
----

.Kotlin
[source,kotlin,role="secondary"]
----
  get("/") { ctx ->
    ctx.flash("success").value("Welcome!")         // <3>
  }
  
  post("/save") { ctx ->
    ctx.flash().put("success", "Item created")     // <1>
    ctx.sendRedirect("/")                          // <2>
  }
----

<1> Sets a flash attribute: `success`.
<2> Redirects to the home page.
<3> Displays the flash attribute `success` (if it exists) or defaults to `Welcome!`.

Flash attributes are implemented using an HTTP Cookie. To customize the cookie (the default name is `jooby.flash`), use javadoc:Router[setFlashCookie, io.jooby.Cookie].

.Java
[source,java,role="primary"]
----
{
  setFlashCookie(new Cookie("myflash").setHttpOnly(true));
  // or if you're fine with the default name
  getFlashCookie().setHttpOnly(true);
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  flashCookie = Cookie("myflash").setHttpOnly(true)
  // or if you're fine with the default name
  flashCookie.isHttpOnly = true
}
----

===== Parameter Lookup

You can search for parameters across multiple sources with an explicitly defined priority using javadoc:Context[lookup].

.Java
[source,java,role="primary"]
----
get("/{foo}", ctx -> {
  String foo = ctx.lookup("foo", ParamSource.QUERY, ParamSource.PATH).value();
  return "foo is: " + foo;
});

get("/{foo}", ctx -> {
  String foo = ctx.lookup().inQuery().inPath().get("foo").value();
  return "foo is: " + foo;
});
----

.Kotlin
[source,kotlin,role="secondary"]
----
get("/{foo}") { ctx ->
  val foo = ctx.lookup("foo", ParamSource.QUERY, ParamSource.PATH).value()
  "foo is: $foo"
}

get("/{foo}") { ctx ->
  val foo = ctx.lookup().inQuery().inPath()["foo"].value()
  "foo is: $foo"
}
----

If a request is made to `/bar?foo=baz`, the result will be `foo is: baz` because the query parameter takes precedence over the path parameter.

===== Client Certificates

If mutual TLS is enabled, you can access the client's certificates from the context. The first certificate in the list is the peer certificate, followed by the CA certificates in the chain.

.Java
[source,java,role="primary"]
----
get("/{foo}", ctx -> {
  List<Certificate> certificates = ctx.getClientCertificates(); // <1>
  Certificate peerCertificate = certificates.get(0);            // <2>
});
----

.Kotlin
[source,kotlin,role="secondary"]
----
get("/{foo}") { ctx ->
  val certificates = ctx.clientCertificates                     // <1>
  val peerCertificate = certificates.first()                    // <2>
}
----

<1> Get all certificates presented by the client during the SSL handshake.
<2> Get only the peer certificate.

include::value-api.adoc[]

include::body.adoc[]
