API Routes
API routes provide a solution to build a public API with Brisa.
Any file inside the folder src/api
is mapped to /api/*
and will be treated as an API endpoint. They are server-side only bundles and won't increase your client-side bundle size.
You can export any uppercase request method: GET
, POST
, PATCH
, PUT
, DELETE
, etc.
For example, the following API GET
endpoint returns a JSON response with a status code of 200
:
import { type RequestContext } from "brisa";
export function GET(request: RequestContext) {
const responseData = JSON.stringify({
message: "Hello world from Brisa!",
});
const responseOptions = {
headers: { "content-type": "application/json" },
};
return new Response(responseData, responseOptions);
}
Query and parameters
If we want for example to use a dynamic route for users and know which username it is:
/api/user/aralroca?id=3
โsrc/api/user/[username].ts
We have access to the route through the RequestContext
and we can access both the parameters and the query.
import { type RequestContext } from "brisa";
export function GET({ route: { query, params } }: RequestContext) {
const { id } = params;
return new Response(`Hello world ${query.username} with id=${id}!`);
}
Request params
The request that arrives is an extension of the native Request, where apart from having everything that the request has, it has extra information of the request, such as the i18n
, the route
and more. If you want to know more take a look at request context
.
Request Body
You can read the Request
body using the standard Web API methods:
//src/api/items/route.ts
export async function POST(request: RequestContext) {
const res = await request.json();
return new Response(JSON.stringify({ res }));
}
//src/api/items/route.js
export async function POST(request) {
const res = await request.json();
return new Response(JSON.stringify({ res }));
}
Request Body FormData
You can read the FormData
using the standard Web API methods:
//src/api/items/route.ts
export async function POST(request: RequestContext) {
const formData = await request.formData();
const name = formData.get("name");
const email = formData.get("email");
return new Response(JSON.stringify({ name, email }));
}
//src/api/items/route.js
export async function POST(request) {
const formData = await request.formData();
const name = formData.get("name");
const email = formData.get("email");
return new Response(JSON.stringify({ name, email }));
}
Since formData
data are all strings, you may want to use zod-form-data
to validate the request and retrieve data in the format you prefer (e.g. number
).
Response
The Response is the native one, so you can find out here how it works.
Consume i18n translations in your API
Like pages, through the request context you can consume translations depending on the locale.
Example:
/es/api/user/aralroca?id=3
โsrc/api/user/[username].ts
import { type RequestContext } from "brisa";
export function GET({ i18n, route: { query, params } }: RequestContext) {
const { id } = params;
return new Response(i18n.t("hello", { name: params.username, id }));
}
And this inside src/i18n/index.ts
or src/i18n.ts
file:
export default {
locales: ["en", "es"],
defaultLocale: "en",
messages: {
en: {
hello: "Hello {{name}} with id={{id}}!",
},
es: {
hello: "ยกHola {{name}} con id={{id}}!",
},
},
};
Dynamic routes, catch all and optional catch all routes
API Routes support dynamic routes, and follow the same file naming rules used for pages/
.
/api/post/a?id=3
โsrc/api/user/[slug].ts
It can be extended to catch all paths by adding three dots (...
) inside the brackets. For example:
/api/post/a
โpages/api/post/[...slug].js
/api/post/a/b
โpages/api/post/[...slug].js
/api/post/a/b/c
and so on. โpages/api/post/[...slug].js
Catch all routes can be made optional by including the parameter in double brackets ([[...slug]]
).
/api/post
โpages/api/post/[[...slug]].js
/api/post/a
โpages/api/post/[[...slug]].js
/api/post/a/b
, and so on. โpages/api/post/[[...slug]].js
Good to know: You can use names other than
slug
, such as:[[...param]]
CORS
You can set CORS headers on a Response
using the standard Web API methods:
import { type RequestContext } from "brisa";
export async function GET(request: RequestContext) {
return new Response("Hello, Brisa!", {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
});
}
Redirects to a specified path or URL
Taking a form as an example, you may want to redirect your client to a specified path or URL once they have submitted the form.
The following example redirects the client to the /
path if the form is successfully submitted:
import { type RequestContext } from "brisa";
export async function POST(req: RequestContext) {
const { name, message } = await req.json()
try {
await handleFormInputAsync({ name, message })
return new Response("", {
status: 307,
headers: {
Location: "/",
},
})
} catch (err) {
return new Response("Failed to fetch data", { status: 500 })
}
Cache-Control
You can add the Cache-Control
headers to the response. By default is not using any cache.
export async function GET() {
const data = await getSomeData();
const res = new Response(JSON.stringify(data));
res.headers.set("Cache-Control", "max-age=86400");
return res;
}
Headers and Cookies
You can read headers and cookies from the Request
and write headers and cookies to the Response
using Web APIs.
Example reading/writing cookies:
import { type RequestContext } from "brisa";
export async function GET(request: RequestContext) {
const cookies = request.headers.get("cookie");
const res = new Response("Hello, Brisa!");
if (cookies) {
res.headers.set("set-cookie", cookies);
}
return res;
}
Streaming
You can use the Web APIs to create a stream and then return it inside the Response
:
export async function GET() {
const stream = new ReadableStream({
start(controller) {
controller.enqueue("Hello");
controller.enqueue(" ");
controller.enqueue("Brisa!");
controller.close();
},
});
return new Response(stream); // Hello Brisa!
}
Webhooks
Webhooks are useful for receiving real-time notifications or events from external services or systems. These notifications are typically triggered by specific events and are sent as HTTP POST
requests to a predefined URL endpoint in your Brisa application.
import { type RequestContext } from "brisa";
export async function POST(req: RequestContext) {
const { event, eventData } = await req.json()
try {
// Perform actions based on the event and data received
return new Response("Webhook received and processed successfully", { status: 200 });
} catch (err) {
return new Response("Error processing webhook", { status: 500 });
}
Security Considerations
When implementing webhook endpoints, it's essential to consider security measures to prevent unauthorized access or tampering with the webhook requests. Some best practices include:
- Authentication: Verify the authenticity of incoming webhook requests using authentication mechanisms such as API keys, tokens, or signatures.
- Validation: Validate the incoming webhook payload to ensure that it meets expected format and data integrity requirements.
- Rate Limiting: Implement rate limiting to prevent abuse or excessive usage of webhook endpoints.
By implementing these security measures, you can ensure the reliability and integrity of your webhook-based integrations in Brisa.