---
title: HTTP Requests
description: Learn how to handle different types of HTTP requests with rest-rpc
---

```ts
const todos = await client.todos.list.fetch({ limit: 10 });
const todo = await client.todos.byId.fetch({ id: "1" });
```

## Request With JSON Body

Regular JSON request bodies are declared with a schema. 
The `body` key is flattened for client call and server handler.

```ts
export const api = router({
	todos: {
		create: {
			method: "POST",
			path: "/todos",
			body: z.object({
				title: z.string().min(1),
				labels: z.array(z.string()).optional(),
			}),
			response: todoSchema,
		},
	},
});
```

```ts
export const routes = router(api, {
	todos: {
		create({ title, labels }) {
			return createTodo({ title, labels });
		},
	},
});
```

```ts
const todo = await client.todos.create.fetch({
	title: "Write docs",
	labels: ["docs"],
});
```

## Request Without Body

Request without a body can be declared by omitting the `body` key or by using `noBody()` explicitly.

```ts
import { noBody } from "@rest-rpc/core";

export const api = router({
	todos: {
		list: {
			method: "GET",
			path: "/todos",
			query: z.object({
				limit: z.number().optional(),
			}),
			response: z.array(todoSchema),
		},
		byId: {
			method: "GET",
			path: "/todos/:id",
			body: noBody(),
			response: todoSchema,
		},
	},
});
```

```ts
export const routes = router(api, {
	todos: {
		list({ limit }) {
			return listTodos({ limit });
		},
		byId({ id }) {
			return getTodoById({ id });
		},
	},
});
```

## Request With Custom Content Type

Custom request bodies are declared with `customBody()`. 
The `body` key is not flattened for client call and server handler.

```ts
import { customBody, router } from "@rest-rpc/core";

export const api = router({
	imports: {
		csv: {
			method: "POST",
			path: "/imports.csv",
			body: customBody({
				contentType: "text/csv",
				schema: z.string(),
			}),
			response: z.object({
				imported: z.number(),
			}),
		},
	},
});
```

```ts
export const routes = router(api, {
	imports: {
		csv({ body }) {
			return importCsv(body);
		},
	},
});
```

```ts
const result = await client.imports.csv.fetch({
	body: "id,title\n1,Write docs\n",
});
```

## Request With Multiple Custom Content Types

Custom request bodies with multiple content types are declared with `customBody()` with an array of content types.
The `body` key is not flattened for client call and server handler. It contains both the `contentType` and the `payload`.

```ts
export const api = router({
	images: {
		upload: {
			method: "POST",
			path: "/images",
			body: customBody({
				contentType: ["image/png", "image/jpeg"],
				schema: z.instanceof(Uint8Array),
			}),
			response: z.object({
				id: z.string(),
			}),
		},
	},
});
```

```ts
export const routes = router(api, {
	images: {
		upload({ body }) {
			return saveImage({
				contentType: body.contentType,
				bytes: body.payload,
			});
		},
	},
});
```

```ts
const image = await client.images.upload.fetch({
	body: {
		contentType: "image/png",
		payload: bytes,
	},
});
```
