HTTP Requests
Introduction
The kernel wraps Bun’s request in Request from @bunyad/http and passes it to your action. Route parameters, the query string, and the body are available from that object.
Interacting with the request
Accessing the request
Accept Request as the first argument of a closure or a controller method.
import type { Request } from "@bunyad/http";
Route.get("/users", (request: Request) => {
return request.string("q", "");
});request.raw is the underlying Fetch request when you need a header or a body the wrapper does not already expose.
Request path, host, and method
request.method;
request.path();
request.url;
request.isMethod("post");path() has no leading slash, except for /, which stays /. isMethod ignores case. request.host() is the host header. request.scheme() is http or https.
Request headers
header reads one header. Names are case-insensitive.
request.header("accept");
request.header("x-request-id", "none");bearerToken() returns the token from Authorization: Bearer ..., without the Bearer prefix.
Request IP address
request.ip() is the client address. By default, X-Forwarded-For is ignored, so a caller cannot pick their own IP by setting that header. Call setTrustedProxies at boot when the application sits behind a proxy you control:
import { setTrustedProxies } from "@bunyad/http";
setTrustedProxies(["10.0.0.1"]);Pass "*" only when every connecting address is a proxy you trust. After that, ip() uses the forwarded value.
Content negotiation
wantsJson() is true when the preferred Accept type is JSON. expectsJson() is true in that case, and also when the call is an AJAX request that accepts any type. Error pages use expectsJson() to choose JSON or HTML. See error handling.
request.ajax();
request.pjax();
request.expectsJson();ajax() checks X-Requested-With: XMLHttpRequest.
Input
Retrieving input
input reads one value. Route parameters win over the body, and the body wins over the query string. The second argument is the default when the key is missing.
const name = request.input("name");
const nameOrGuest = request.string("name", "Guest");
const page = request.integer("page", 1);
const price = request.float("price", 0);
const remember = request.boolean("remember");Dot keys walk nested data: request.input("user.name").
| Method | Returns |
|---|---|
input(key, default?) |
The raw value |
string(key, default?) |
A string |
integer(key, default?) |
An integer, or the default when the value is empty or not a number |
float(key, default?) |
A float, or the default |
boolean(key, default?) |
true for true, 1, "1", "true", "on", and "yes" |
all() |
Query, body, and route parameters merged |
only(keys) |
Those keys from all() |
except(keys) |
all() without those keys |
collect(key?) |
A collection of the value, or of every value when the key is omitted |
boolean treats a missing key as the default, which is false when you omit it.
Input presence
request.has("name");
request.has("name", "email");
request.hasAny("name", "email");
request.filled("name");
request.missing("name");has is true when every key is present, including a key whose value is an empty string. filled is false for null and "". missing is the opposite of has for one key.
whenFilled and whenHas run a callback only in that case:
request.whenFilled("name", (name) => {
console.log(name);
});Merging additional input
merge writes keys into the input bag. Later input calls see them. mergeIfMissing writes a key only when it is not already present.
request.merge({ page: 1 });
request.mergeIfMissing({ currency: "PKR" });Old input
flash stores the current input in the session under _old_input, for the next request. flashOnly and flashExcept limit which keys are stored. Validation failures do this for you and drop password before the redirect. Read it back from the session in the form:
request.flash();
request.flashOnly("email");
request.flashExcept("password");After a failed validation redirect, the old input is in the session under _old. Views read it with old('email') without the controller passing anything; Inertia pages keep their own form state.
Cookies
request.cookie("theme");
request.cookie("theme", "light");The second argument is the default when the cookie is absent. Setting a cookie is a method on the response, not the request.
Files
Retrieving uploaded files
file returns the uploaded file for a key, or an array when the field was submitted more than once.
const avatar = request.file("avatar");
if (avatar && !Array.isArray(avatar)) {
avatar.getClientOriginalName();
}hasFile reports whether a file was uploaded for that key.
Storing uploaded files
Call store on the file with a directory and a disk name when you want the file written through the filesystem manager. The method returns the stored path.
const avatar = request.file("avatar");
if (avatar && !Array.isArray(avatar)) {
await avatar.store("avatars", { disk: "public" });
}Confirm the disk in your filesystem configuration before you rely on "public".