# Data Validation in the Tanstack Start Supabase Turbo kit

> Learn how to validate data in the Tanstack Start Supabase Turbo kit.

*Canonical: https://makerkit.dev/docs/tanstack-supabase/security/data-validation*

---

Data Validation is a crucial aspect of building secure applications. In this section, we will look at how to validate data in the Tanstack Start Supabase Turbo kit.

{% sequence title="Steps to validate data" description="Learn how to validate data in the Tanstack Start Supabase Turbo kit." %}

[What are we validating?](#what-are-we-validating)

[Using Zod to validate data](#using-zod-to-validate-data)

[Validating payload data to Server Side API](#validating-payload-data-to-server-side-api)

[Validating Cookies](#validating-cookies)

[Validating URL parameters](#validating-url-parameters)

{% /sequence %}

## What are we validating?

A general rule, is that all client-side provided data should be validated/sanitized. This includes:

- URL parameters
- Search params
- Form data
- Cookies
- Any data provided by the user

## Using Zod to validate data

The Tanstack Start Supabase Turbo kit uses [Zod](https://zod.dev/) to validate data. You can use the `z` object to validate data in your application.

```ts
import * as z from "zod";

const userSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.email(),
});

// Validate the data
const validatedData = userSchema.parse(data);
```

## Validating payload data to Server Side API

We generally use two ways for sending data from a client to a server:

1. Server functions
2. API server routes

Let's look at how we can validate data for both of these cases.

### Server functions: Using createServerFn

Server functions created with `createServerFn` accept a `.validator()` that runs a Zod schema over the input, so the `data` argument in the handler is already validated. Composing `authFunctionMiddleware` adds the authenticated user to `context`.

```ts
import { createServerFn } from "@tanstack/react-start";
import { authFunctionMiddleware } from "@kit/function-middleware/functions";
import * as z from "zod";

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.email(),
});

export const createUserFunction = createServerFn({ method: "POST" })
  .middleware(authFunctionMiddleware)
  .validator(UserSchema)
  .handler(async ({ data, context: { user } }) => {
    // data is now validated against the UserSchema

    // do something with the validated data
  });
```

When you define a server function with a `.validator(UserSchema)`, the `data` argument is validated against the schema automatically. The `context.user` provides the authenticated user.

### API server routes: validating the request body

TanStack Start API routes are defined with `createFileRoute` under `apps/web/src/routes/api/...`. Validate the request body with your Zod schema inside the handler.

```ts
import { createFileRoute } from "@tanstack/react-router";
import * as z from "zod";

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.email(),
});

export const Route = createFileRoute("/api/users")({
  server: {
    handlers: {
      POST: async ({ request }) => {
        const body = UserSchema.parse(await request.json());

        // body is now validated against the UserSchema
        // do something with the validated data

        return new Response(null, { status: 201 });
      },
    },
  },
});
```

Just like the `.validator()` on a server function, parsing the request body with your schema guarantees the data is validated before you use it. Use `getSupabaseServerClient()` inside the handler if you need the authenticated user.

## Validating Cookies

Whenever you use a cookie in your application, you should validate the cookie data.

Let's assume you receive a cookie with the name `my-cookie`, and you expect it to be a number. You can validate the cookie data as follows:

```ts
import * as z from "zod";
import { getCookie } from "@tanstack/react-start/server";

const cookie = z.coerce.number()
    .safeParse(getCookie("my-cookie"));

if (!cookie.success) {
  // handle the error or provide a default value
}
```

## Validating URL parameters

Whenever you receive a URL parameter, you should validate the parameter data. Let's assume you receive a URL parameter with the name `my-param`, and you expect it to be a number. You can validate the parameter data as follows:

```ts
import { createFileRoute } from "@tanstack/react-router";
import * as z from "zod";

const SearchSchema = z.object({
    myParam: z.coerce.number(),
});

export const Route = createFileRoute("/my-page")({
    // validateSearch parses and coerces the raw search params, rejecting
    // invalid input before the component or loader runs.
    validateSearch: SearchSchema,
    component: Page,
});

function Page() {
    // Fully typed and validated search params.
    const { myParam } = Route.useSearch();

    // render the page with the validated data
}
```

Going forward, remember to validate all data that you receive from the client, and never trust anything the client provides you with. Always have a default value ready to handle invalid data, which can prevent potential security issues or bugs in your application.
