{ "id": "ec40cd4320aad0b03a3dca30", "source": "solid:signals", "type": "github-document", "title": "api-routes", "content": "---\ntitle: API routes\nuse_cases: \u003e-\n rest api, graphql endpoints, trpc setup, webhooks, oauth callbacks, pdf\n generation, third-party integrations\ntags:\n - api\n - rest\n - graphql\n - trpc\n - endpoints\n - server\n - http\nversion: '1.0'\ndescription: \u003e-\n Create API routes in SolidStart for REST, GraphQL, or tRPC endpoints. Handle\n HTTP methods, sessions, and external integrations.\n---\n\nWhile Server Functions can be a good way to write server-side code for data needed by your UI, sometimes you need to expose API routes.\nSome reasons for wanting API Routes include:\n- There are additional clients that want to share this logic.\n- Exposing a GraphQL or tRPC endpoint.\n- Exposing a public-facing REST API.\n- Writing webhooks or auth callback handlers for OAuth.\n- Having URLs not serving HTML, but other kinds of documents like PDFs or images.\n\nFor these use cases, SolidStart provides a way to write these routes in a way that is easy to understand and maintain.\nAPI routes are just similar to other routes and follow the same filename conventions as [UI Routes](/solid-start/building-your-application/routing).\n\nThe difference between API routes and UI routes is in what you should export from the file.\nUI routes export a default Solid component, while API Routes do not.\nRather, they export functions that are named after the HTTP method that they handle.\n\n:::note\nAPI routes are prioritized over UI route alternatives.\nIf you want to have them overlap at the same path remember to use `Accept` headers.\nReturning without a response in a `GET` route will fallback to UI route handling.\n:::\n\n## Writing an API route\n\nTo write an API route, you can create a file in a directory.\nWhile you can name this directory anything, it is common to name it `api` to indicate that the routes in this directory are for handling API requests:\n\n```tsx title=\"routes/api/test.ts\"\nexport function GET() {\n // ...\n}\n\nexport function POST() {\n // ...\n}\n\nexport function PATCH() {\n // ...\n}\n\nexport function DELETE() {\n // ...\n}\n```\n\nAPI routes get passed an `APIEvent` object as their first argument.\nThis object contains:\n- `request`: [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object representing the request sent by the client.\n- `params`: Object that contains the dynamic route parameters. For example, if the route is `/api/users/:id`, and the request is made to `/api/users/123`, then `params` will be `{ id: 123 }`.\n- `fetch`: An internal `fetch` function that can be used to make requests to other API routes without worrying about the `origin` of the URL.\n\nAn API route is expected to return JSON or a `Response` object.\nIn order to handle all methods, you can define a handler function that binds multiple methods to it:\n\n```tsx title=\"routes/api/all.ts\"\nasync function handler() {\n // ...\n}\n\nexport const GET = handler;\nexport const POST = handler;\n// ...\n```\n\nAn example of an API route that returns products from a certain category and brand is shown below:\n\n```tsx title=\"routes/api/product/[category]/[brand].ts\"\nimport type { APIEvent } from \"@solidjs/start/server\";\nimport store from \"./store\";\n\nexport async function GET({ params }: APIEvent) {\n console.log(`Category: ${params.category}, Brand: ${params.brand}`);\n const products = await store.getProducts(params.category, params.brand);\n return products;\n}\n```\n\n## Session management\n\nSince HTTP is a stateless protocol, you need to manage the state of the session on the server.\nFor example, if you want to know who the user is, the most secure way of doing this is through the use of HTTP-only cookies.\nCookies are a way to store data in the user's browser that persist in the browser between requests.\n\nThe user's request is exposed through the `Request` object.\nThrough parsing the [`Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie) header, the cookies can be accessed and any helpers from `vinxi/http` can be used to make that a bit easier.\n\n```tsx\nimport type { APIEvent } from \"@solidjs/start/server\";\nimport { getCookie } from \"vinxi/http\";\nimport store from \"./store\";\n\nexport async function GET(event: APIEvent) {\n const userId = getCookie(\"userId\");\n if (!userId) {\n return new Response(\"Not logged in\", { status: 401 });\n }\n const user = await store.getUser(event.params.userId);\n if (user.id !== userId) {\n return new Response(\"Not authorized\", { status: 403 });\n }\n return user;\n}\n```\n\nIn this example, you can see that the `userId` is read from the cookie and then used to look up the user in the store.\nFor more information on how to use cookies for secure session management, read the [session documentation](/solid-start/advanced/session).\n\n## Exposing a GraphQL API\n\nSolidStart makes it easy to [implement a GraphQL API](https://graphql.org/).\nGraphQL is a query language for APIs and a runtime for executing those queries by using a type system you define for your data.\n\nTo implement a GraphQL API, you need to define a schema and resolvers.\nThe `graphql` function takes a GraphQL schema and returns a function that can be used as an API route handler.\n\nFirst, to implement a GraphQL API, install the `graphql` library.\nFollowing that, you can implement your schema and resolvers in a file and then export a handler function that will be used as the API route:\n\n```tsx title=\"routes/graphql.ts\"\nimport { buildSchema, graphql } from \"graphql\";\nimport type { APIEvent } from \"@solidjs/start/server\";\n\n// Define GraphQL Schema\nconst schema = buildSchema(`\n type Message {\n message: String\n }\n\n type Query {\n hello(input: String): Message\n goodbye: String\n }\n`);\n\n// Define GraphQL Resolvers\nconst rootValue = {\n hello: () =\u003e {\n return {\n message: \"Hello World\"\n };\n },\n goodbye: () =\u003e {\n return \"Goodbye\";\n }\n};\n\n// request handler\nconst handler = async (event: APIEvent) =\u003e {\n // get request body\n const body = await new Response(event.request.body).json();\n\n // pass query and save results\n const result = await graphql({ rootValue, schema, source: body.query });\n\n // send query result\n return result;\n};\n\nexport const GET = handler;\n\nexport const POST = handler;\n```\n\n## Exposing a tRPC server route\n\n[tRPC](https://trpc.io/) is a modern TypeScript-first API framework that is designed to be easy to use and understand.\n\nTo expose a tRPC server route, you need to write your router.\nOnce you have written your router, you can put it in a separate file so that you can export the type for your client.\n\n```tsx title=\"lib/router.ts\"\nimport { initTRPC } from \"@trpc/server\";\nimport { wrap } from \"@decs/typeschema\";\nimport { string } from \"valibot\";\n\nconst t = initTRPC.create();\n\nexport const appRouter = t.router({\n hello: t.procedure.input(wrap(string())).query(({ input }) =\u003e {\n return `hello ${input ?? \"world\"}`;\n })\n});\n\nexport type AppRouter = typeof appRouter;\n```\n\nAn example of a simple client that you can use to fetch data from your tRPC server is shown below:\n\n```tsx title=\"lib/trpc.ts\"\nimport { createTRPCProxyClient, httpBatchLink, loggerLink } from \"@trpc/client\";\nimport type { AppRouter } from \"./router\";\n\nexport const client = createTRPCProxyClient\u003cAppRouter\u003e({\n links: [loggerLink(), httpBatchLink({ url: \"http://localhost:3000/api/trpc\" })]\n});\n```\n\nFinally, you can use the `fetch` adapter to write an API route that acts as the tRPC server.\n\n```tsx title=\"routes/api/trpc/[trpc].ts\"\nimport { type APIEvent } from \"@solidjs/start/server\";\nimport { fetchRequestHandler } from \"@trpc/server/adapters/fetch\";\nimport { appRouter } from \"~/lib/router\";\n\nconst handler = (event: APIEvent) =\u003e\n fetchRequestHandler({\n endpoint: \"/api/trpc\",\n req: event.request,\n router: appRouter,\n createContext: () =\u003e ({})\n });\n\nexport const GET = handler;\n\nexport const POST = handler;\n```\n\nTo learn more about tRPC, you can read the [tRPC documentation](https://trpc.io/docs).", "url": "https://github.com/solidjs/solid-docs/blob/HEAD/src/routes/solid-start/building-your-application/api-routes.mdx", "metadata": { "path": "src/routes/solid-start/building-your-application/api-routes.mdx", "repo": "solidjs/solid-docs", "repo_url": "https://github.com/solidjs/solid-docs.git", "size": 7896, "source_type": "github" }, "hash": "1398f942368bff8ae6946da78176e7def07868a2edb6a7c27695a3330921ee11", "timestamp": "2026-02-23T11:43:00.19376043+01:00" }