Skip to main content

APIs

Add a REST, GraphQL, or WebSocket APIs to your SST app.


Overview

While most modern frontends (like Next.js, or Remix) allow you to add API routes, it makes sense to add a dedicated API to your app as it grows larger. It allows you to support multiple clients and possibly have an API that's used directly by your users.

SST makes it easy to create serverless APIs. You can add a standard REST API, GraphQL API, or WebSocket API.

Let's look at them in detail.


Get started

Start by creating a new SST + Next.js app by running the following command in your terminal. We are using Next.js for this example but you can use your favorite frontend.

npx create-sst@latest --template standard/nextjs

Add an API

To add a REST API, add the following to your stacks.

stacks/Default.ts
const api = new Api(stack, "api", {
routes: {
"GET /": "packages/functions/src/time.handler",
},
});

This creates an API with a single GET endpoint and points it to a function.

Let's print out the API URL in our app output.

stacks/Default.ts
stack.addOutputs({
+ ApiUrl: api.url,
SiteUrl: site.url,
});

And make sure to import the Api construct.

stacks/Default.ts
- import { StackContext, NextjsSite } from "sst/constructs";
+ import { Api, StackContext, NextjsSite } from "sst/constructs";

Bind the API

After adding the API, bind your Next.js app to it.

stacks/Default.ts
const site = new NextjsSite(stack, "site", {
path: "packages/web",
+ bind: [api],
});

This allows us to access the API in our Next.js app.


Add the handler

Let's add the function that'll handle the new endpoint.

packages/functions/src/time.ts
import { ApiHandler } from "sst/node/api";

export const handler = ApiHandler(async (evt) => {
return {
statusCode: 200,
body: evt.requestContext.time,
};
});

Now once your app is updated it'll print out the new API URL in the terminal. And if you go to that URL in your browser, you'll notice it prints out the time!


Call the API

Let's make a request to the API in our Next.js app.

functions/web/pages/index.ts
import { Api } from "sst/node/api";

export async function getServerSideProps() {
const results = await fetch(Api.api.url);
console.log(await results.text());

return { props: { loaded: true } };
}

Now if you refresh your Next.js app locally, it'll print the time in the Next.js terminal!

Tutorial

Check out a tutorial on how to build a CRUD API with SST.


Custom domains

After you deploy your API, you'll get an auto-generated AWS endpoint. SST makes it easy to configure a custom domain for your API.

stacks/Default.ts
new Api(stack, "api", {
customDomain: "api.domain.com",
routes: {
"GET /": "packages/functions/src/hello.handler",
},
});

You'll just need to ensure that the domain is in Amazon Route 53.


Authentication

You can use the Auth construct to attach a JWT powered authentication route to your API.

stacks/Default.ts
import { Auth } from "sst/constructs";

const auth = new Auth(stack, "auth", {
authenticator: {
handler: "packages/functions/src/auth.handler",
},
});

auth.attach(stack, { api });

Read more about this over on our guide on authentication.


Customize your API

SST allows you to customize your API further by adding things like:


CORS

CORS allows web apps hosted on different domains (compared to the API) to make requests.

CORS is enabled by default for the Api construct to allow all HTTP methods with all HTTP headers from any origin. You can override this default behavior.

stacks/Default.ts
new Api(stack, "api", {
cors: {
allowMethods: ["ANY"],
allowHeaders: ["Authorization"],
allowOrigins: ["https://www.example.com"],
},
routes: {
"GET /": "packages/functions/src/hello.handler",
},
});

Access logs

Access logs are enabled by default for all SST APIs. The default log format is a JSON string. This can be customized.

stacks/Default.ts
new Api(stack, "api", {
// Write access log in CSV format
accessLog:
"$context.identity.sourceIp,$context.requestTime,$context.httpMethod,$context.routeKey,$context.protocol,$context.status,$context.responseLength,$context.requestId",
routes: {
"GET /": "packages/functions/src/hello.handler",
},
});

Catch-all routes

You can also add a catch-all route to catch requests that don't match any other routes.

stacks/Default.ts
new Api(stack, "api", {
routes: {
"GET /": "packages/functions/src/hello.handler",
$default: "packages/functions/src/default.handler",
},
});

Other options

Aside from REST APIs, you can also add GraphQL and WebSocket APIs to your app.


GraphQL

There are two main ways to add a GraphQL API in SST.


Pothos

You can use Pothos, which is a code-first schema approach. Add a new route to your API, say POST /graphql.

stacks/Default.ts
new Api(stack, "api", {
routes: {
"POST /graphql": {
type: "graphql",
function: "packages/functions/src/graphql.handler",
pothos: {
schema: "backend/functions/graphql/schema.ts",
output: "graphql/schema.graphql",
commands: ["./genql graphql/graphql.schema graphql/"],
},
},
},
});

AppSync

The second involves using AppSync with the AppSyncApi construct.

stacks/Default.ts
import { AppSyncApi } from "sst/constructs";

new AppSyncApi(stack, "graphql", {
schema: "graphql/schema.graphql",
dataSources: {
notesDS: "packages/functions/src/notes.handler",
},
resolvers: {
"Query listNotes": "notesDS",
"Query getNoteById": "notesDS",
"Mutation createNote": "notesDS",
"Mutation updateNote": "notesDS",
"Mutation deleteNote": "notesDS",
},
});
Tutorial

WebSocket

To add a WebSocket API to your app use the WebSocketApi construct. It uses Amazon API Gateway WebSocket API behind the scenes.

stacks/Default.ts
import { WebSocketApi } from "sst/constructs";

new WebSocketApi(stack, "ws", {
routes: {
$connect: "packages/functions/src/connect.handler",
$default: "packages/functions/src/default.handler",
$disconnect: "packages/functions/src/disconnect.handler",
sendMessage: "packages/functions/src/sendMessage.handler",
},
});
Tutorial

And that's it! You now know how to add a dedicated API to your app. Learn more about the concepts we've covered here.