API Route handlers are added using the convention route.ts
and exporting one or many HTTP methods (e.g., GET
, POST
, PUT
, DELETE
).
While you won't be writing too many API route handlers (prefer Server Actions for mutations) - you can use the enhanceRouteHandler
utility to help you with the following:
- checks the user state (if the user is authenticated)
- given a Zod schema, it validates the request body
- given a captcha site key, it validates the captcha token
- report an uncaught exception to the monitoring provider (if configured)
Fantastic, let's see how we can use it.
import { z } from 'zod';
import { enhanceRouteHandler } from '@kit/next/routes';
import { NextResponse } from 'next/server';
const ZodSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
});
export const POST = enhanceRouteHandler(
async function({ body, user, request }) {
// 1. "body" has been validated against the Zod schema, and it's safe to use
// 2. "user" is the authenticated user
// 3. "request" is the request object that contains the headers, query, etc.
// ... your code here
return NextResponse.json({
success: true,
});
},
{
schema: ZodSchema,
},
);
Using a Captcha token protection
If you want to protect your API route handlers with a captcha token, you can do so by passing the captcha site token to the enhanceRouteHandler
function and setting the captcha
flag to true
.
import { enhanceRouteHandler } from '@kit/next/routes';
export const POST = enhanceRouteHandler(
async function({ body, user, request }) {
// ... your code here
return NextResponse.json({
success: true,
});
},
{
captcha: true,
schema: ZodSchema,
},
);
When calling the API route handler, we must supply the captcha token in the request body.
The captcha token can be retrieved from the useCaptchaToken
hook in the package @kit/auth/captcha/client
.
import { useCaptchaToken } from '@kit/auth/captcha/client';
function Component() {
const captchaToken = useCaptchaToken();
// ... your code here
}
Now, when calling the API route handler, we can pass the captcha and the CSRF token.
NB: The CSRF token must be added for all API routes making mutations in routes that are outside /api/*
. Routes inside /api/*
are not protected by default as they're meant to be used externally.
import { useCaptchaToken } from '@kit/auth/captcha/client';
import { useCsrfToken } from '@kit/shared/hooks';
function Component() {
const captchaToken = useCaptchaToken();
const csrfToken = useCsrfToken();
const onSubmit = async (params: {
email: string;
password: string;
}) => {
const response = await fetch('/my-api-route', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-csrf-token': csrfToken,
'x-captcha-token': captchaToken,
},
body: JSON.stringify(params),
});
// ... your code here
};
// ... your code here
}
You can improve the above using React Query:
import { useMutation } from '@tanstack/react-query';
import { useCaptchaToken } from '@kit/auth/captcha/client';
function Component() {
const captchaToken = useCaptchaToken();
const mutation = useMutateData();
const onSubmit = async (params: {
email: string;
password: string;
}) => {
await mutation.mutateAsync(params);
};
// ... your code here
}
function useMutateData() {
return useMutation({
mutationKey: 'my-mutation',
mutationFn: async (params: { email: string; password: string }) => {
const response = await fetch('/my-api-route', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-captcha-token': captchaToken,
},
body: JSON.stringify(params),
});
if (!response.ok) {
throw new Error('An error occurred');
}
return response.json();
},
});
}
NB: to use Captcha protection, you need to set the captcha token in the environment variables.
CAPTCHA_SECRET_TOKEN=
NEXT_PUBLIC_CAPTCHA_SITE_KEY=
As a secret environment variable, please do not add it to the .env
file. Instead, add it to the environment variables of your CI/CD system.
The only captcha provider supported is Cloudflare Turnstile.
Capturing Exceptions
This function automatically reports uncaught exceptions if you configured a monitoring provider. The monitoring provider is set in the environment variable MONITORING_PROVIDER
.
To disable it, pass captureException: false
to the enhanceAction
function.
import { enhanceRouteHandler } from '@kit/next/routes';
export const POST = enhanceRouteHandler(
async function({ body, user, request }) {
// ... your code here
return NextResponse.json({
success: true,
});
},
{
captcha: true,
captureException: false,
schema: ZodSchema,
},
);