---
title: Custom HTTP API Endpoints
---
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers'
import { Required } from '@site/src/components/Required'
In Wasp, the default client-server interaction mechanism is through [Operations](/docs/data-model/operations/overview). However, if you need a specific URL method/path, or a specific response, Operations may not be suitable for you. For these cases, you can use an `api`. Best of all, they should look and feel very familiar.
## How to Create an API
APIs are used to tie a JS function to a certain endpoint e.g. `POST /something/special`. They are distinct from Operations and have no client-side helpers (like `useQuery`).
To create a Wasp API, you must:
1. Declare the API in Wasp using the `api` declaration
2. Define the API's NodeJS implementation
After completing these two steps, you'll be able to call the API from the client code (via our `Axios` wrapper), or from the outside world.
### Declaring the API in Wasp
First, we need to declare the API in the Wasp file and you can easily do this with the `api` declaration:
```wasp title="main.wasp"
// ...
api fooBar { // APIs and their implementations don't need to (but can) have the same name.
fn: import { fooBar } from "@server/apis.js",
httpRoute: (GET, "/foo/bar")
}
```
```wasp title="main.wasp"
// ...
api fooBar { // APIs and their implementations don't need to (but can) have the same name.
fn: import { fooBar } from "@server/apis.js",
httpRoute: (GET, "/foo/bar")
}
```
Read more about the supported fields in the [API Reference](#api-reference).
### Defining the API's NodeJS Implementation
:::note
To make sure the Wasp compiler generates the types for APIs for use in the NodeJS implementation, you should add your `api` declarations to your `.wasp` file first _and_ keep the `wasp start` command running.
:::
After you defined the API, it should be implemented as a NodeJS function that takes three arguments:
1. `req`: Express Request object
2. `res`: Express Response object
3. `context`: An additional context object **injected into the API by Wasp**. This object contains user session information, as well as information about entities. The examples here won't use the context for simplicity purposes. You can read more about it in the [section about using entities in APIs](#using-entities-in-apis).
```ts title="src/server/apis.js"
export const fooBar = (req, res, context) => {
res.set("Access-Control-Allow-Origin", "*"); // Example of modifying headers to override Wasp default CORS middleware.
res.json({ msg: `Hello, ${context.user?.username || "stranger"}!` });
};
```
```ts title="src/server/apis.ts"
import { FooBar } from "@wasp/apis/types"; // This type is generated by Wasp based on the `api` declaration above.
export const fooBar: FooBar = (req, res, context) => {
res.set("Access-Control-Allow-Origin", "*"); // Example of modifying headers to override Wasp default CORS middleware.
res.json({ msg: `Hello, ${context.user?.username || "stranger"}!` });
};
```
#### Providing Extra Type Information
We'll see how we can provide extra type information to an API function.
Let's say you wanted to create some `GET` route that would take an email address as a param, and provide them the answer to "Life, the Universe and Everything." 😀 What would this look like in TypeScript?
Define the API in Wasp:
```wasp title="main.wasp"
api fooBar {
fn: import { fooBar } from "@server/apis.js",
entities: [Task],
httpRoute: (GET, "/foo/bar/:email")
}
```
We can use the `FooBar` type to which we'll provide the generic **params** and **response** types, which then gives us full type safety in the implementation.
```ts title="src/server/apis.ts"
import { FooBar } from "@wasp/apis/types";
export const fooBar: FooBar<
{ email: string }, // params
{ answer: number } // response
> = (req, res, _context) => {
console.log(req.params.email);
res.json({ answer: 42 });
};
```
## Using the API
### Using the API externally
To use the API externally, you simply call the endpoint using the method and path you used.
For example, if your app is running at `https://example.com` then from the above you could issue a `GET` to `https://example/com/foo/callback` (in your browser, Postman, `curl`, another web service, etc.).
### Using the API from the Client
To use the API from your client, including with auth support, you can import the Axios wrapper from `@wasp/api` and invoke a call. For example:
```jsx title="src/client/pages/SomePage.jsx"
import React, { useEffect } from "react";
import api from "@wasp/api";
async function fetchCustomRoute() {
const res = await api.get("/foo/bar");
console.log(res.data);
}
export const Foo = () => {
useEffect(() => {
fetchCustomRoute();
}, []);
return <>// ...>;
};
```
```tsx title="src/client/pages/SomePage.tsx"
import React, { useEffect } from "react";
import api from "@wasp/api";
async function fetchCustomRoute() {
const res = await api.get("/foo/bar");
console.log(res.data);
}
export const Foo = () => {
useEffect(() => {
fetchCustomRoute();
}, []);
return <>// ...>;
};
```
#### Making Sure CORS Works
APIs are designed to be as flexible as possible, hence they don't utilize the default middleware like Operations do. As a result, to use these APIs on the client side, you must ensure that CORS (Cross-Origin Resource Sharing) is enabled.
You can do this by defining custom middleware for your APIs in the Wasp file.
For example, an `apiNamespace` is a simple declaration used to apply some `middlewareConfigFn` to all APIs under some specific path:
```wasp title="main.wasp"
apiNamespace fooBar {
middlewareConfigFn: import { fooBarNamespaceMiddlewareFn } from "@server/apis.js",
path: "/foo"
}
```
And then in the implementation file:
```js title="src/server/apis.js"
export const apiMiddleware = (config) => {
return config;
};
```
For example, an `apiNamespace` is a simple declaration used to apply some `middlewareConfigFn` to all APIs under some specific path:
```wasp title="main.wasp"
apiNamespace fooBar {
middlewareConfigFn: import { fooBarNamespaceMiddlewareFn } from "@server/apis.js",
path: "/foo"
}
```
And then in the implementation file (returning the default config):
```ts title="src/server/apis.ts"
import { MiddlewareConfigFn } from "@wasp/middleware";
export const apiMiddleware: MiddlewareConfigFn = (config) => {
return config;
};
```
We are returning the default middleware which enables CORS for all APIs under the `/foo` path.
For more information about middleware configuration, please see: [Middleware Configuration](/docs/advanced/middleware-config)
## Using Entities in APIs
In many cases, resources used in APIs will be [Entities](/docs/data-model/entities.md).
To use an Entity in your API, add it to the `api` declaration in Wasp:
```wasp {3} title="main.wasp"
api fooBar {
fn: import { fooBar } from "@server/apis.js",
entities: [Task],
httpRoute: (GET, "/foo/bar")
}
```
```wasp {3} title="main.wasp"
api fooBar {
fn: import { fooBar } from "@server/apis.js",
entities: [Task],
httpRoute: (GET, "/foo/bar")
}
```
Wasp will inject the specified Entity into the APIs `context` argument, giving you access to the Entity's Prisma API:
```ts title="src/server/apis.js"
export const fooBar = (req, res, context) => {
res.json({ count: await context.entities.Task.count() });
};
```
```ts title="src/server/apis.ts"
import { FooBar } from "@wasp/apis/types";
export const fooBar: FooBar = (req, res, context) => {
res.json({ count: await context.entities.Task.count() });
};
```
The object `context.entities.Task` exposes `prisma.task` from [Prisma's CRUD API](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/crud).
## API Reference
```wasp title="main.wasp"
api fooBar {
fn: import { fooBar } from "@server/apis.js",
httpRoute: (GET, "/foo/bar"),
entities: [Task],
auth: true,
middlewareConfigFn: import { apiMiddleware } from "@server/apis.js"
}
```
```wasp title="main.wasp"
api fooBar {
fn: import { fooBar } from "@server/apis.js",
httpRoute: (GET, "/foo/bar"),
entities: [Task],
auth: true,
middlewareConfigFn: import { apiMiddleware } from "@server/apis.js"
}
```
The `api` declaration has the following fields:
- `fn: ServerImport`
The import statement of the APIs NodeJs implementation.
- `httpRoute: (HttpMethod, string)`
The HTTP (method, path) pair, where the method can be one of:
- `ALL`, `GET`, `POST`, `PUT` or `DELETE`
- and path is an Express path `string`.
- `entities: [Entity]`
A list of entities you wish to use inside your API. You can read more about it [here](#using-entities-in-apis).
- `auth: bool`
If auth is enabled, this will default to `true` and provide a `context.user` object. If you do not wish to attempt to parse the JWT in the Authorization Header, you should set this to `false`.
- `middlewareConfigFn: ServerImport`
The import statement to an Express middleware config function for this API. See more in [middleware section](/docs/advanced/middleware-config) of the docs.