{"id":30237925,"url":"https://github.com/stainless-api/stl-api","last_synced_at":"2025-08-15T02:58:00.603Z","repository":{"id":169898513,"uuid":"644096733","full_name":"stainless-api/stl-api","owner":"stainless-api","description":"Stainless full-stack API Framework","archived":false,"fork":false,"pushed_at":"2025-08-08T17:45:22.000Z","size":285943,"stargazers_count":130,"open_issues_count":15,"forks_count":7,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-08-10T00:36:56.434Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://stainlessapi.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stainless-api.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-05-22T20:07:58.000Z","updated_at":"2025-08-09T15:58:08.000Z","dependencies_parsed_at":"2024-02-12T20:25:56.134Z","dependency_job_id":"02610baa-223e-4eeb-b551-263eb1bdf64e","html_url":"https://github.com/stainless-api/stl-api","commit_stats":null,"previous_names":["stainless-api/stl-api"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/stainless-api/stl-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stainless-api%2Fstl-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stainless-api%2Fstl-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stainless-api%2Fstl-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stainless-api%2Fstl-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stainless-api","download_url":"https://codeload.github.com/stainless-api/stl-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stainless-api%2Fstl-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270515656,"owners_count":24598440,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-15T02:57:55.800Z","updated_at":"2025-08-15T02:58:00.587Z","avatar_url":"https://github.com/stainless-api.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stainless: a framework for robust \u0026 polished REST APIs\n\nStainless helps you ship quality, typesafe REST APIs from any TypeScript backend.\n\nYou declare the shape and behavior of your API in one place,\nand get an OpenAPI spec, docs, and typed frontend client without a build step.\n\nYou can use it as a pluggable, batteries-included web framework for APIs (managing auth, pagination, observability, etc) or sprinkle it on top of your existing API in any framework for better OpenAPI support and/or full-stack typesafety.\n\nYou can also opt into Stainless's Stripe-inspired [pristine API design conventions](#pristine) and get rich pagination, consistent errors, field inclusion \u0026 selection, and (WIP) normalized caching on the frontend for free.\n\nStainless draws inspiration with gratitude from tRPC, FastAPI, GraphQL/Relay, and (heavily) from the internal API Framework we worked on at Stripe.\n\n\u003e **Note**\n\u003e This project is currently in its **alpha stage of development**.\n\u003e Features may be changed or removed at any time without warning, and production use is not recommended.\n\u003e Hobbyists welcome!\n\nFor example:\n\n\u003c!-- TODO: this is too long / too much code… --\u003e\n\n```ts\n// server.ts\nimport { Stl } from \"stainless\";\nimport { makePrismaPlugin } from \"@stl-api/prisma\";\nimport { makeNextPlugin } from \"@stl-api/next\";\nimport { makeNextAuthPlugin } from \"@stl-api/next-auth\";\nimport { authOptions } from \"~/pages/api/auth/[...nextauth]\";\nimport prisma from \"~/libs/prisma\";\nimport { z } from \"stainless\";\n\nconst plugins = {\n  next: makeNextPlugin(),\n  nextAuth: makeNextAuthPlugin({ authOptions }),\n  prisma: makePrismaPlugin(),\n};\n\nexport const stl = new Stl({\n  plugins,\n});\n\nconst User = z.object({\n  id: z.string(),\n  name: z.string(),\n});\n\nconst update = stl.endpoint({\n  endpoint: \"POST /users/:id\",\n  description: \"Update a user. Currently only updating the name is supported.\",\n  authenticated: true,\n  response: User,\n\n  path: z.object({\n    id: z.string(),\n  }),\n  body: z.object({\n    name: z.string(),\n  }),\n\n  async handler({ id, name }) {\n    return await prisma.users.updateOne(id, { name });\n  },\n});\n\nexport const api = stl.api({\n  openapi: {\n    endpoint: \"GET /api/openapi\",\n  },\n  resources: {\n    users: stl.resource({\n      actions: {\n        update,\n      },\n      models: {\n        User,\n      },\n    }),\n  },\n});\n\n// client.ts\nimport { createClient } from \"stainless\";\nimport type { api } from \"./server\";\n\nconst client = createClient\u003ctypeof api\u003e(\"http://localhost:3000/api\");\n\n// params are fully typed:\nconst user = await client.users.update(\"id\", { name: \"my new name\" });\n// user object is fully typed.\n\n// A full OpenAPI spec is available by default at \"get /openapi\":\nconst openapi = await client.getOpenapi();\nconsole.log(openapi.paths[\"/users/:id\"].post);\nconsole.log(openapi.components.schemas.User);\n```\n\n# Getting started\n\nSee [`stainless` package docs](/packages/stainless/README.md#getting-started) to get started!\n\n# Packages\n\n- [stainless](/packages/stainless)\n- [@stl-api/express](/packages/express)\n- [@stl-api/next](/packages/next)\n- [@stl-api/next-auth](/packages/next-auth)\n- [@stl-api/prisma](/packages/prisma)\n\n# Pristine\n\nPristine is an API Standard by Stainless, providing opinions on API design so teams don't have to bikeshed, and so tools can expect consistent API shapes.\n\nFollowing the Pristine Standard helps your API offer an interface like Stripe's,\nwith best-practices baked in. Like the Relay standard for GQL, Pristine can also help tooling like frontend clients cache data, paginate requests, handle errors, and so on.\n\n\u003c!-- You can opt your API into Pristine like so:\n\n```ts\nconst stl = new Stainless({ pristine: true });\n```\n\nThis will enforce the Pristine conventions, and provide easier access to tooling which depends on it.\n\nIf you're starting with an existing API and don't want to go straight to a v2,\nyou can gradually adopt Pristine standards and tooling. In the future, we plan to offer lint rules for your OpenAPI spec and an overall \"Lighthouse score\" indicating the degree of compliance your API offers.\n --\u003e\n\n## Pristine Conventions\n\nHere is a list of Pristine API design conventions:\n\n- [Pagination](/packages/stainless/docs/pagination.md)\n- [Inclusion](/packages/stainless/docs/inclusion.md)\n- [Selection](/packages/stainless/docs/selection.md)\n\n# Using Stainless in an existing codebase\n\nIf you'd like a maintainable way of declaring your OpenAPI spec\nin TypeScript, right alongside your application code, and getting\ngreat docs, end-to-end typesafety, and backend API client libraries (SDKs),\nyou can adopt the `stainless` library gradually in minimally-invasive ways.\n\nFor example, in an Express app, you can add annotations near a handler to get an OpenAPI spec and client:\n\n```ts\n// app/routes/users.ts\n\nconst User = z.object({\n  id: z.string(),\n  name: z.string(),\n});\n\nconst create = stl.endpoint({\n  endpoint: \"POST /users\",\n  response: User,\n  body: z.object({ name: z.string() }),\n});\n\napp.post(\"/users\", async (req, rsp) =\u003e {\n  const user = await db.users.create({ name });\n  rsp.status(200).json(user);\n});\n```\n\n\u003csummary\u003eYou'll also need a small amount of server code\u003c/summary\u003e\n\n```ts\n// app/api.ts\nconst users = stl.resource({\n  models: { User },\n  actions: {\n    create,\n  },\n});\n\nconst api = stl.api({\n  resources: {\n    users,\n  },\n});\n\n// and voila, you get an OpenAPI spec!\napp.get(\"/openapi\", (req, rsp) =\u003e {\n  rsp.json(api.openapi.spec);\n});\n```\n\n\u003csummary\u003e\nFor typesafety and validation of parameters, you can also sprinkle in\nparam parsing, response generation, and more:\n\u003c/summary\u003e\n\n```ts\napp.post(\"/users\", async (req, rsp) =\u003e {\n  const { name } = create.validateParams(req);\n\n  const user = await db.users.create({ name });\n\n  rsp.send(create.makeResponse(user));\n});\n```\n\nDoing this helps TypeScript ensure that your OpenAPI spec is an accurate reflection of your runtime behavior. It can also help return consistent response shapes and validation error messages to the user.\n\nNote that `validateParams` raises `BadRequestError` if params don't match.\n\nTo handle errors like this, add middleware:\n\n```ts\napp.use((err, req, rsp, next) =\u003e {\n  if (err instanceof stl.Error) {\n    rsp.status(err.statusCode).send(stl.makeError(err));\n  }\n  // …\n});\n```\n\n`stl.makeError` is will return a JSON object with `type`, `message`, and other information. (TODO add/encourage things like request ID's…)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstainless-api%2Fstl-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstainless-api%2Fstl-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstainless-api%2Fstl-api/lists"}