├── .github
└── FUNDING.yml
├── .gitignore
├── .openapiconfig
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── blog
├── 2019-05-28-first-blog-post.md
└── authors.yml
├── docs
├── api-first.md
├── examples
│ ├── _category_.json
│ ├── boilerplate.md
│ ├── building-apis.md
│ ├── calling-apis.md
│ ├── tanstack-query.md
│ └── testing-react-with-jest-and-openapi-mocks.md
├── intro.md
├── openapi-backend
│ ├── _category_.json
│ ├── api.md
│ ├── examples.md
│ ├── intro.md
│ ├── mocking.md
│ ├── operation-handlers.md
│ ├── request-validation.md
│ ├── response-validation.md
│ ├── security-handlers.md
│ ├── typescript.md
│ └── versioning.md
├── openapi-client-axios
│ ├── _category_.json
│ ├── api.md
│ ├── bundling.md
│ ├── intro.md
│ ├── typegen.md
│ └── usage.md
└── openapicmd
│ ├── _category_.json
│ ├── call.md
│ ├── config.md
│ ├── generating-documentation.md
│ ├── intro.md
│ ├── mock-server.md
│ └── typegen.md
├── docusaurus.config.js
├── package-lock.json
├── package.json
├── sidebars.js
├── src
├── components
│ ├── Comparisons.mdx
│ ├── HomepageFeatures
│ │ ├── GithubStarsButton.tsx
│ │ └── index.tsx
│ └── Sandbox
│ │ ├── Iframe.tsx
│ │ └── Sandbox.tsx
├── css
│ └── custom.css
└── pages
│ ├── docs
│ ├── examples.tsx
│ ├── index.tsx
│ ├── openapi-backend.tsx
│ ├── openapi-client-axios.tsx
│ └── openapicmd.tsx
│ ├── imprint.mdx
│ ├── index.module.css
│ └── index.tsx
├── static
├── CNAME
├── img
│ ├── favicon.ico
│ ├── header.png
│ ├── intellisense.gif
│ ├── openapi-stack-logo.png
│ ├── openapi-stack.drawio.png
│ ├── openapistack-social.jpg
│ ├── redoc-screenshot.png
│ ├── sponsors
│ │ └── fern_logo_tagline.png
│ ├── swagger-ui-screenshot.png
│ ├── undraw_code_inspection_bdl7.svg
│ ├── undraw_developer_activity_re_39tg.svg
│ └── undraw_secure_login_pdn4.svg
└── petstore.openapi.json
├── tailwind.config.js
└── tsconfig.json
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: anttiviljami
2 | open_collective: openapi-stack
3 | custom:
4 | - https://buymeacoff.ee/anttiviljami
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/.openapiconfig:
--------------------------------------------------------------------------------
1 | definition: https://openapistack.co/petstore.openapi.json
2 | security:
3 | api_key:
4 | header:
5 | api_key: secret123
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | support@openapistack.co.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | OpenAPI Stack is Free and Open Source Software. Issues and pull requests are more than welcome!
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2023 Viljami Kuosmanen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
12 |
13 | **openapi-stack** is a collection of open source libraries and tools for full stack software development using [OpenAPI specification](https://www.openapis.org/) with an API Design First philosophy.
14 |
15 | The goal is to unlock great developer experience and full stack type safety for software teams using REST; inspired by tools like [GraphQL](https://graphql.org/) and [tRPC](https://trpc.io).
16 |
17 | ## Benefits
18 |
19 | 1. 🚀 **No code generation.** Write your own code the way you like it. Only generate types from OpenAPI spec if you want.
20 | 1. 🤝 **Single source of truth for your API contract.** No more manually updating your OpenAPI specs to keep up with your backend code. Ensure your API docs and SDKs stay up to date by using the spec in runtime to route and validate.
21 | 1. 🧙♂️ **Type safety and validation.** Build your product faster and with a better developer experience using strongly typed Typescript and code autocomplete both in the server and client side.
22 | 1. ❤️ **Testing & Collaboration.** Leverage API mocks to make testing and development easier and iterate fast on your API design as you build your app's interface. Being blocked by the backend team is a thing of the past!
23 |
24 | ## Packages part of openapi-stack:
25 |
26 | - [openapistack/openapi-backend ](https://github.com/openapistack/openapi-backend)
27 | - [openapistack/openapi-client-axios ](https://github.com/openapistack/openapi-client-axios)
28 | - [openapistack/openapicmd ](https://github.com/openapistack/openapicmd)
29 |
30 | ## Comparisons
31 |
32 |
33 | How does openapi-stack compare to GraphQL?
34 |
35 | [*GraphQL*](https://graphql.org/) is a query language for APIs developed by Facebook. It gives API clients full control over the data they query, making it extremely flexible and efficient for client-centric use cases.
36 |
37 | Similar to [OpenAPI specification](https://www.openapis.org/), GraphQL APIs define a strongly typed schema for the data and mutations they support which makes them discoverable and intuitive to develop against.
38 |
39 | OpenAPI stack achieves the same type safety and great developer experience by using the OpenAPI specification as a single source of truth for the API contract, used to generate types for both client and server side and utilising it for routing and validation during runtime.
40 |
41 | Both GraphQL and openapi-stack encourage an [API First](https://openapistack.co/docs/api-first/) approach where the API contract is treated as a first class citizen in software design instead of treating it as merely documentation.
42 |
43 | While REST APIs don't generally provide the same level of control to clients as GraphQL, many times this could be seen as a benefit especially in scenarios where strict control over data access and operations is crucial.
44 |
45 | Many organizations choose REST over GraphQL due to more established conventions, simplicity, and the ability to leverage standard HTTP features directly. Widespread knowledge around REST contribute to its choice among organizations looking for a tried-and-tested approach to building APIs.
46 |
47 |
48 |
49 | How does openapi-stack compare to tRPC?
50 |
51 | [tRPC](https://trpc.io/) is a *Remote Procedure Call* (RPC) library for Typescript to build and consume typesafe APIs.
52 |
53 | Designed for full-stack Typescript applications, tRPC allows direct sharing of types between both the client and server, without relying on code generation.
54 |
55 | Unlike GraphQL and REST, tRPC doesn't expose a standard machine-readable API schema to be consumed by clients, instead taking a more straightforward approach of exposing endpoints or *procedures*, essentially [*"just functions"*](https://trpc.io/docs/concepts#its-just-functions) invoked by the client to the server.
56 |
57 | OpenAPI stack achieves type safety using a similar workflow to tRPC's procedures with [*OpenAPI operations*](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operation-object), also avoiding code generation by only generating types from OpenAPI spec and using the machine readable contract in the runtime for routing and validation.
58 |
59 | While the lightweight tRPC approach is optimal for teams just looking to build full stack applications, teams looking to build robust APIs are better served by the API design first approach of openapi-stack or GraphQL.
60 |
61 |
62 |
63 | ## Features
64 |
65 | - [x] Battle-tested in production. High test coverage.
66 | - [x] ️No code generation – we only generate types
67 | - [x] Built with TypeScript, types included with full autocomplete support
68 | - [x] Framework agnostic – works with your stack
69 | - [x] Lightweight - small frontend bundle + optimized for serverless cold starts
70 | - [x] OpenAPI 3.x support
71 | - [x] [Samples](https://openapistack.co/docs/examples/boilerplate) included
72 |
73 | ## Star History
74 |
75 | [](https://star-history.com/#openapistack/openapi-backend&openapistack/openapi-client-axios&openapistack/openapicmd&openapistack/docs&Date)
76 |
77 | ## Commercial support
78 |
79 | For assistance with integrating openapi-stack for your company, reach out at support@openapistack.co.
80 |
81 | ## Contributing
82 |
83 | OpenAPI Stack is Free and Open Source Software. Issues and pull requests are more than welcome!
84 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/blog/2019-05-28-first-blog-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: first-blog-post
3 | title: First Blog Post
4 | authors: [anttiviljami]
5 | tags: [openapi]
6 | ---
7 |
8 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
9 |
--------------------------------------------------------------------------------
/blog/authors.yml:
--------------------------------------------------------------------------------
1 | anttiviljami:
2 | name: Viljami Kuosmanen
3 | title: OpenAPI Stack Creator
4 | url: https://github.com/anttiviljami
5 | image_url: https://github.com/anttiviljami.png
6 |
--------------------------------------------------------------------------------
/docs/api-first.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Why API First?
3 | hide_title: true
4 | sidebar_position: 1
5 | ---
6 |
7 | # Why API First?
8 |
9 | ## Schema First
10 |
11 | The core idea of _API First_, sometimes referred to as _Schema First_, is that software teams start by defining an API contract and use it as the single source of truth for data models in their application logic.
12 |
13 | Teams using this approach define their API contracts using machine-readable specifications like [OpenAPI](https://www.openapis.org/) or [GraphQL](https://graphql.org/), and leverage techniques like [Generating Types](/docs/openapicmd/typegen) and [API Mocking](/docs/openapicmd/mock-server/) to rapidly iterate the product and API design while making sure the implementation and documentation stay up to date with the API contract.
14 |
15 | We do this to collaborate effectively on software design, making changes to the API schema when needed, using shared types and automated tests to ensure our implementation follows the API contract. **This reduces bugs and allows teams to deliver continuously.**
16 |
17 | ## Type Safety
18 |
19 | Use of typed languages like TypeScript improve developer experience and reduce bugs by providing strict type checks and code autocomplete during development. This is especially powerful when types are shared and used across the stack in both backend implementation and client-side logic.
20 |
21 | Given that the OpenAPI specification already leverages [JSON Schema](https://json-schema.org/) for defining data model types, these can be effortlessly translated into TypeScript types for coding use.
22 |
23 | :::tip
24 |
25 | OpenAPI Stack provides the [`openapi typegen`](/docs/openapicmd/typegen/) CLI command to generate types from OpenAPI schema, to keep your implementation up to date with the API contract.
26 |
27 | :::
28 |
29 | ## Design First
30 |
31 | Introducing [API Mocking](/docs/openapicmd/mock-server/) enables developers working on the application's frontend to develop the app against a mocked version of the backend which can be cheaply adjusted by fine-tuning the API schema. **This means the frontend team is never blocked waiting for backend changes.**
32 |
33 | For customer-centric agile teams, focusing on the user facing parts of the application first is a great way to rapidly prototype designs before investing into implementing backend logic.
34 |
35 | **Design First** signifies that design drives the code, not the other way around.
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/docs/examples/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Examples",
3 | "position": 6
4 | }
--------------------------------------------------------------------------------
/docs/examples/boilerplate.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Boilerplate projects
3 | sidebar_position: 10
4 | ---
5 |
6 | :::tip
7 |
8 | See [Framework Examples](/docs/openapi-backend/examples/) for how openapi-backend integrates with any Node.js server or framework.
9 |
10 | :::
11 |
12 | A list of example projects using openapi-stack with different frameworks:
13 |
14 | - **Next.js**
15 | - openapi-stack-fullstack-nextjs-starter ([GitHub](https://github.com/anttiviljami/docs-nextjs-starter), [Playground](https://stackblitz.com/fork/openapi-stack-nextjs-starter?file=public%2Fopenapi.yml&file=app%2Fpage.tsx&file=pages%2Fapi%2F%5Bopenapi%5D.ts))
16 | - **Express**
17 | - openapi-backend-express ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/express))
18 | - openapi-backend-express-typescript ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/express-typescript))
19 | - openapi-backend-express-ts-mock ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/express-ts-mock))
20 | - openapi-backend-express-apikey-auth ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/express-apikey-auth))
21 | - openapi-backend-express-jwt-auth ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/express-jwt-auth))
22 | - **SST**
23 | - openapi-stack-sst-sample ([GitHub](https://github.com/anttiviljami/openapistack-sst-sample))
24 | - openapi-backend-sst-sample ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/aws-sst))
25 | - **Hapi**
26 | - openapi-backend-hapi-typescript ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/hapi-typescript))
27 | - **Koa**
28 | - openapi-backend-koa ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/koa))
29 | - **Fastify**
30 | - openapi-backend-fastify ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/fastify))
31 | - **AWS SAM**
32 | - openapi-backend-aws-sam ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/aws-sam))
33 | - **AWS CDK**
34 | - openapi-backend-aws-cdk ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/aws-cdk))
35 | - **Serverless Framework**
36 | - openapi-backend-serverless-aws ([Github](https://github.com/openapistack/openapi-backend/tree/main/examples/serverless-framework))
37 | - **Azure Function**
38 | - openapi-backend-azure-function ([GitHub](https://github.com/openapistack/openapi-backend/tree/main/examples/azure-function))
39 |
--------------------------------------------------------------------------------
/docs/examples/building-apis.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Building APIs
3 | sidebar_position: 1
4 | ---
5 |
6 | :::info
7 |
8 | In this example, we will design and build a minimal Node.js REST API using [openapi-backend](/docs/openapi-backend) and the [express](https://expressjs.com) framework.
9 |
10 | :::
11 |
12 | :::tip
13 |
14 | Not using express? The `openapi-backend` package can be used with any other Node.js framework or server. See [boilerplate projects](/docs/examples/boilerplate/) for examples of using OpenAPI stack with other frameworks.
15 |
16 | :::
17 |
18 | ## Prerequisites
19 |
20 | This guide assumes you already know how to set up a Node.js project with Typescript. You can find a minimal sample project [here](https://github.com/openapistack/openapi-backend/tree/main/examples/express-typescript).
21 |
22 | Before starting, make sure to install `openapi-backend` and `express` as dependencies:
23 |
24 | ```
25 | npm i openapi-backend express
26 | ```
27 |
28 | ## Setting up express
29 |
30 | We will start by setting up a basic express server listening on port `9000`:
31 |
32 | ```ts
33 | // src/server.ts
34 | import express from 'express';
35 |
36 | const app = express();
37 |
38 | // use the json middleware
39 | app.use(express.json());
40 |
41 | // start server
42 | app.listen(9000, () => console.info('api listening at http://localhost:9000'));
43 | ```
44 |
45 | ## Setting up openapi-backend
46 |
47 | We can then import `openapi-backend` and initialize it with an openapi definition file:
48 |
49 | ```ts
50 | import { OpenAPIBackend } from 'openapi-backend';
51 |
52 | const api = new OpenAPIBackend({
53 | definition: './openapi.yml',
54 | });
55 |
56 | api.init();
57 | ```
58 |
59 | ## Writing our API spec
60 |
61 | We load our API definition from `openapi.yml`, so let's populate it with a simple API design with a `getPets` operation:
62 |
63 | ```yaml
64 | # src/openapi.yml
65 | openapi: 3.0.2
66 | info:
67 | title: "Pet API"
68 | version: 1.0.0
69 | paths:
70 | "/pets":
71 | get:
72 | operationId: getPets
73 | responses:
74 | "200":
75 | description: list of pets
76 | content:
77 | application/json:
78 | schema:
79 | type: array
80 | items:
81 | $ref: "#/components/schemas/Pet"
82 | components:
83 | schemas:
84 | Pet:
85 | type: object
86 | properties:
87 | id:
88 | type: string
89 | type:
90 | type: string
91 | enum: ["cat", "dog"]
92 | name:
93 | type: string
94 | required: ["id", "type"]
95 | ```
96 |
97 | ## Implementing Handlers
98 |
99 | Let's then implement an [operation handler](/docs/openapi-backend/operation-handlers/) for the `getPets` operation defined in our spec.
100 |
101 | ```ts
102 | api.register('getPets', async (c, req: express.Request, res: express.Response) =>
103 | res.status(200).json([{ id: '1', type: 'cat', name: 'Garfield' }])
104 | )
105 | ```
106 |
107 | To enable routing and validation, we'll add some default handlers in our code for common exceptions:
108 |
109 | ```ts
110 | // return 400 when request validation fails
111 | api.register('validationFail', (c, req: express.Request, res: express.Response) =>
112 | res.status(400).json({ err: c.validation.errors }),
113 | )
114 | // return 404 when route doesn't match any operation in openapi.yml
115 | api.register('notFound', (c, req: express.Request, res: express.Response) =>
116 | res.status(404).json({ err: 'not found' }),
117 | )
118 | ```
119 |
120 |
121 | ## Use as express middleware
122 |
123 | Finally we wire up openapi-backend to route, validate and handle API requests with express:
124 |
125 | ```ts
126 | app.use((req, res) => api.handleRequest(req, req, res));
127 | ```
128 |
129 | ## Full Example
130 |
131 | Putting everything together, here is our complete example server code:
132 |
133 | ```ts
134 | // src/server.ts
135 | import { OpenAPIBackend, Request } from 'openapi-backend';
136 | import express from 'express';
137 |
138 | const api = new OpenAPIBackend({
139 | definition: './openapi.yml',
140 | });
141 |
142 | api.init();
143 |
144 | // handler for getPets operation in openapi.yml
145 | api.register('getPets', async (c, req: express.Request, res: express.Response) =>
146 | res.status(200).json([{ id: '1', type: 'cat', name: 'Garfield' }])
147 | )
148 | // return 400 when request validation fails
149 | api.register('validationFail', (c, req: express.Request, res: express.Response) =>
150 | res.status(400).json({ err: c.validation.errors }),
151 | )
152 | // return 404 when route doesn't match any operation in openapi.yml
153 | api.register('notFound', (c, req: express.Request, res: express.Response) =>
154 | res.status(404).json({ err: 'not found' }),
155 | )
156 |
157 | const app = express();
158 |
159 | // use the json middleware
160 | app.use(express.json());
161 |
162 | // use openapi-backend to handle requests
163 | app.use((req, res) => api.handleRequest(req as Request, req, res));
164 |
165 | // start server
166 | app.listen(9000, () => console.info('api listening at http://localhost:9000'));
167 | ```
168 |
169 | ## Optional: Mocking Responses
170 |
171 | Instead of implementing a handler for `getPets`, you can register a `notImplemented` handler to mock the response based
172 | on the OpenAPI schema:
173 |
174 | ```ts
175 | // mock responses for operations with no registered handlers
176 | api.register('notImplemented', (c, req: express.Request, res: express.Response) => {
177 | const { status, mock } = c.api.mockResponseForOperation(c.operation.operationId);
178 | return res.status(status).json(mock);
179 | });
180 | ```
--------------------------------------------------------------------------------
/docs/examples/calling-apis.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Invoking APIs
3 | sidebar_position: 2
4 | ---
5 |
6 | :::info
7 |
8 | In this example we will write code to interact with a public mock API available on [example.openapistack.co/openapi.json](https://example.openapistack.co/openapi.json)
9 |
10 | :::
11 |
12 | :::tip
13 |
14 | If you're looking to invoke APIs via CLI, see [`openapicmd call`](/docs/openapicmd/call/)
15 |
16 | :::
17 |
18 | ## Prerequisites
19 |
20 | Before starting, make sure to install `openapi-client-axios` and `axios` as dependencies in your project:
21 |
22 | ```
23 | npm i openapi-client-axios axios
24 | ```
25 |
26 | ## Creating a client instace
27 |
28 | To call our API, we import `openapi-client-axios` and configure it by passing the OpenAPI definition URL:
29 |
30 | ```ts
31 | import { OpenAPIClientAxios } from 'openapi-client-axios';
32 |
33 | const api = new OpenAPIClientAxios({
34 | definition: 'https://example.openapistack.co/openapi.json',
35 | });
36 | ```
37 |
38 | :::note
39 | For optimal performance, it's recommended to pass the definition as a JS object instead or fetching it from a URL in runtime.
40 | :::
41 |
42 | To initialise our client instance, we call `api.init()`:
43 |
44 | ```ts
45 | const client = await api.init();
46 | ```
47 |
48 | ## Adding Types
49 |
50 | For type-safety and code autocompletion we use the CLI command `openapicmd typegen` to generate types.
51 |
52 | This command will create a file named `openapi.d.ts` in the src directory:
53 |
54 | ```sh
55 | npx openapicmd typegen https://example.openapistack.co/openapi.json > src/openapi.d.ts
56 | ```
57 |
58 | We can now import the types and use them to create our fully typed API client by passing the `Client` type to our `init` call.
59 |
60 | ```ts
61 | import type { Client } from './openapi.d.ts';
62 |
63 | const client = await api.init();
64 | ```
65 |
66 | ## Invoking the API
67 |
68 | Finally, we are ready to call our API using [operation methods](/docs/openapi-client-axios/usage/#operation-methods) based on our `openapi.yml` spec:
69 |
70 | ```ts
71 | const petsResponse = await client.getPets();
72 |
73 | const pets = petsResponse.data; // Pet[] inferred as type as defined in the API
74 | ```
75 |
76 | ## Full Example
77 |
78 | Putting everything together, here is our full code example combining all the steps:
79 |
80 | ```ts
81 | // src/example.ts
82 | import { OpenAPIClientAxios } from 'openapi-client-axios';
83 | import type { Client } from './openapi.d.ts';
84 |
85 | const api = new OpenAPIClientAxios({
86 | definition: 'https://example.openapistack.co/openapi.json'
87 | });
88 |
89 | async function main() {
90 | const client = await api.init();
91 |
92 | const petsResponse = await client.getPets();
93 | const pets = petsResponse.data; // Pet[] inferred as type
94 | console.log('getPets response', petsResponse.status, pets);
95 | }
96 | main();
97 | ```
98 |
--------------------------------------------------------------------------------
/docs/examples/tanstack-query.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 3
3 | title: Use with React Query
4 | ---
5 |
6 | To use `openapi-client-axios` in a declarative way in the frontend, we recommend using [TanStack Query](https://tanstack.com/query/latest) (previously known as React Query) together with type safe clients created with openapi-stack.
7 |
8 | ## Example with React Query
9 |
10 | First, let's set up our type safe API client:
11 |
12 | :::tip
13 | Use the [`openapicmd typegen`](/docs/openapicmd/typegen/) command to generate the `openapi.d.ts` type file for your API.
14 | :::
15 |
16 | :::note
17 | For optimal performance, it's recommended to pass the definition as a JS object instead or fetching it from a URL in runtime.
18 | :::
19 |
20 | ```ts
21 | // api.ts
22 | import { OpenAPIClientAxios } from 'openapi-client-axios';
23 | import type { Client } from './openapi.d.ts';
24 |
25 | const api = new OpenAPIClientAxios({
26 | definition: 'https://example.openapistack.co/openapi.json',
27 | });
28 |
29 | export const getApiClient = async () => {
30 | const client = await api.getClient();
31 |
32 | // add auth token
33 | client.default.headers['authorization'] = `Bearer ${API_TOKEN}`;
34 |
35 | return client;
36 | }
37 | ```
38 |
39 | Now we are ready to use our type safe client with React Query:
40 |
41 | ```tsx
42 | // PetView.tsx
43 | import { useQuery } from 'react-query';
44 | import { getApiClient } from './api';
45 | import Loader from './Loader';
46 |
47 | export const PetView = (props: { petId: string }) => {
48 | const petQuery = useQuery(
49 | ['getPetById', props.petId],
50 | () => getApiClient()
51 | .then(client => client.getPetById(props.petId))
52 | .then(res => res.data),
53 | { enabled: !!props.petId },
54 | );
55 |
56 | const pet = petQuery.data; // type Pet is inferred from openapi.d.ts
57 |
58 | return (
59 |
60 | {petQuery.fetching && }
61 |
62 | {petQuery.data && (/* TODO: show pet information */)}
63 |
64 | )
65 | }
66 | ```
--------------------------------------------------------------------------------
/docs/examples/testing-react-with-jest-and-openapi-mocks.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 4
3 | ---
4 |
5 | # Testing with msw + openapi-backend mocks
6 |
7 | :::info
8 |
9 | [MSW](https://mswjs.io/) (Mock Service Worker) is a popular library built to intercept and mock network requests commonly used in testing.
10 |
11 | :::
12 |
13 | ### Setting up msw
14 |
15 | Here is the basic setup for a rest api mock using msw:
16 |
17 | ```javascript
18 | import { rest } from "msw";
19 | import { setupServer } from "msw/node";
20 |
21 | const server = setupServer(
22 | rest.get("/api/pets", (req, res, ctx) => {
23 | const pets = [{ id: 1, name: "Garfield", type: "cat" }];
24 | return res(ctx.json({ pets }));
25 | })
26 | );
27 |
28 | beforeAll(() => server.listen());
29 | afterAll(() => server.close());
30 | ```
31 |
32 | One of the reasons this is extremely cool is because it avoids the pain of having to start up a real local mock backend, such as an express server that needs to be bound to a specific port on the host running the test.
33 |
34 | This helps keep your tests fast and simple to run, as they should be.
35 |
36 | ### Even better with OpenAPI
37 |
38 | It turns out `msw` together with `openapi-backend` is the perfect combination for mocking REST apis.
39 |
40 | To provide a full mock for an API, all we need is to create a mock backend with openapi-backend using the API definition and tell msw to use it:
41 |
42 | ```javascript
43 | import { rest } from "msw";
44 | import { setupServer } from "msw/node";
45 | import OpenAPIBackend from "openapi-backend";
46 | import definition from "./path/to/definition.json";
47 |
48 | // create our mock backend with openapi-backend
49 | const api = new OpenAPIBackend({ definition });
50 | api.register("notFound", (c, res, ctx) => res(ctx.status(404)));
51 | api.register("notImplemented", async (c, res, ctx) => {
52 | const { status, mock } = api.mockResponseForOperation(
53 | c.operation.operationId
54 | );
55 | ctx.status(status);
56 | return res(ctx.json(mock));
57 | });
58 |
59 | // tell msw to intercept all requests to api/* with our mock
60 | const server = setupServer(
61 | rest.all("/api/*", async (req, res, ctx) =>
62 | api.handleRequest(
63 | {
64 | path: req.url.pathname,
65 | query: req.url.search,
66 | method: req.method,
67 | body: req._bodyUsed ? await req.json() : null,
68 | headers: { ...req.headers.raw },
69 | },
70 | res,
71 | ctx
72 | )
73 | )
74 | );
75 |
76 | beforeAll(() => server.listen());
77 | afterAll(() => server.close());
78 | ```
79 |
80 | Now instead of having to write your own mock handlers for each operation, they're generated from the response schemas and examples defined in the OpenAPI document.
81 |
82 | What's more: any time the API definition changes, all your mocks will be automatically updated giving you further confidence your app is compatible with the new API version.
83 |
84 | ### Enabling Request Validation
85 |
86 | When testing, it's often very useful to make sure your application is actually sending the correct requests to the API.
87 |
88 | Working with OpenAPI definitions has the benefit that API operations are well defined and requests can be automatically validated using JSON schema.
89 |
90 | To enable request validation during tests, you can simply register the [validationFail handler](https://openapistack.co/docs/openapi-backend/api#validationfail-handler) for openapi-backend:
91 |
92 | ```javascript
93 | api.register("validationFail", (c, res, ctx) =>
94 | res(ctx.status(400), ctx.json({ error: c.validation.errors }))
95 | );
96 | ```
97 |
98 | When running tests, a malformed call to an API endpoint will now result in a 400 Bad Request error from the mock backend, alongside a useful error message telling you what's wrong with the request.
99 |
100 | ### Custom Handlers
101 |
102 | In some tests it might make sense to provide a different mock than the default one as provided by openapi-backend.
103 |
104 | Registering your own mock for an API operation in a test is as simple as calling `api.register()` with the operationId and a mock handler:
105 |
106 | ```javascript
107 | it("should call getPets operation", () => {
108 | // given
109 | const mockResponse = [{ id: 2, name: "Odie" }];
110 | const mockHandler = jest.fn((c, res, ctx) => res(ctx.json(mockResponse)));
111 | api.register("getPets", mockHandler);
112 |
113 | // when
114 | // render()...
115 |
116 | // then
117 | expect(mockHandler).toBeCalled();
118 | });
119 | ```
120 |
--------------------------------------------------------------------------------
/docs/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | hide_title: true
4 | sidebar_position: 0
5 | ---
6 |
7 |
22 |
23 | **openapi-stack** is a collection of open source libraries and tools for full stack software development using [OpenAPI specification](https://www.openapis.org/).
24 |
25 | The goal is to unlock great developer experience and full stack type safety for software teams using REST; inspired by tools like [GraphQL](https://graphql.org/) and [tRPC](https://trpc.io).
26 |
27 |
28 |
29 | How does openapi-stack compare to GraphQL?
30 |
31 | [*GraphQL*](https://graphql.org/) is a query language for APIs developed by Facebook. It gives API clients full control over the data they query, making it extremely flexible and efficient for client-centric use cases.
32 |
33 | Similar to [OpenAPI specification](https://www.openapis.org/), GraphQL APIs define a strongly typed schema for the data and mutations they support which makes them discoverable and intuitive to develop against.
34 |
35 | OpenAPI stack achieves the same type safety and great developer experience by using the OpenAPI specification as a single source of truth for the API contract, used to generate types for both client and server side and utilising it for routing and validation during runtime.
36 |
37 | Both GraphQL and openapi-stack encourage an [API First](/docs/api-first/) approach where the API contract is treated as a first class citizen in software design instead of treating it as merely documentation.
38 |
39 | While REST APIs don't generally provide the same level of control to clients as GraphQL, many times this could be seen as a benefit especially in scenarios where strict control over data access and operations is crucial.
40 |
41 | Many organizations choose REST over GraphQL due to more established conventions, simplicity, and the ability to leverage standard HTTP features directly. Widespread knowledge around REST contribute to its choice among organizations looking for a tried-and-tested approach to building APIs.
42 |
43 |
44 |
45 | How does openapi-stack compare to tRPC?
46 |
47 | [tRPC](https://trpc.io/) is a *Remote Procedure Call* (RPC) library for Typescript to build and consume typesafe APIs.
48 |
49 | Designed for full-stack Typescript applications, tRPC allows direct sharing of types between both the client and server, without relying on code generation.
50 |
51 | Unlike GraphQL and REST, tRPC doesn't expose a standard machine-readable API schema to be consumed by clients, instead taking a more straightforward approach of exposing endpoints or *procedures*, essentially [*"just functions"*](https://trpc.io/docs/concepts#its-just-functions) invoked by the client to the server.
52 |
53 | OpenAPI stack achieves type safety using a similar workflow to tRPC's procedures with [*OpenAPI operations*](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operation-object), also avoiding code generation by only generating types from OpenAPI spec and using the machine readable contract in the runtime for routing and validation.
54 |
55 | While the lightweight tRPC approach is optimal for teams just looking to build full stack applications, teams looking to build robust APIs are better served by the API design first approach of openapi-stack or GraphQL.
56 |
57 |
58 |
59 | ## Benefits
60 |
61 | 1. 🚀 **No code generation.** Write your own code the way you like it. Only generate types from OpenAPI spec if you want.
62 | 1. 🤝 **Single source of truth for your API contract.** No more manually updating your OpenAPI specs to keep up with your backend code. Ensure your API docs and SDKs stay up to date by using the spec in runtime to route and validate.
63 | 1. 🧙♂️ **Type safety and validation.** Build your product faster and with a better developer experience using strongly typed Typescript and code autocomplete both in the server and client side.
64 | 1. ❤️ **Testing & Collaboration.** Leverage API mocks to make testing and development easier and iterate fast on your API design as you build your app's interface. Being blocked by the backend team is a thing of the past!
65 |
66 | ## Backend
67 |
68 | Build, Validate, Route, Authenticate, and Mock your backend using the [openapi-backend](https://github.com/openapistack/openapi-backend) library.
69 |
70 | [Quickstart](/docs/openapi-backend/intro) - [NPM](https://www.npmjs.com/package/openapi-backend)
71 |
72 | ## Client
73 |
74 | Easily consume your API using the typesafe [openapi-client-axios](https://github.com/openapistack/openapi-client-axios) library.
75 |
76 | [Quickstart](/docs/openapi-client-axios/intro) - [NPM](https://www.npmjs.com/package/openapi-client-axios)
77 |
78 | ## CLI
79 |
80 | Generate types, design and test your API using the [openapicmd](https://github.com/openapistack/openapicmd) command line tool.
81 |
82 | [Quickstart](/docs/openapicmd/intro) - [NPM](https://www.npmjs.com/package/openapicmd)
83 |
84 | ## Features
85 |
86 | - [x] Battle-tested in production. High test coverage.
87 | - [x] ️No code generation – we only generate types
88 | - [x] Built with TypeScript, types included with full autocomplete support
89 | - [x] Framework agnostic – works with your stack
90 | - [x] Lightweight - small frontend bundle + optimized for serverless cold starts
91 | - [x] OpenAPI 3.x support
92 | - [x] [Samples](/docs/examples/boilerplate/) included
93 |
94 | ## Star History
95 |
96 | [](https://star-history.com/#openapistack/openapi-backend&openapistack/openapi-client-axios&openapistack/openapicmd&openapistack/docs&Date)
97 |
--------------------------------------------------------------------------------
/docs/openapi-backend/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Backend",
3 | "position": 3
4 | }
5 |
--------------------------------------------------------------------------------
/docs/openapi-backend/examples.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # Framework Examples
6 |
7 | OpenAPI backend is framework agnostic, which means you can use it with pretty much any javascript backend framework and hosting you're familiar with.
8 |
9 | Full, tested examples can be found the openapi-backend GitHub repository: [https://github.com/openapistack/openapi-backend/tree/main/examples/](https://github.com/openapistack/openapi-backend/tree/main/examples/)
10 |
11 | ### Express
12 |
13 | ```javascript
14 | import express from "express";
15 |
16 | const app = express();
17 | app.use(express.json());
18 | app.use((req, res) => api.handleRequest(req, req, res));
19 | app.listen(9000);
20 | ```
21 |
22 | [See full Express example](https://github.com/openapistack/openapi-backend/tree/main/examples/express)
23 |
24 | [See full Express TypeScript example](https://github.com/openapistack/openapi-backend/tree/main/examples/express-typescript)
25 |
26 | ### AWS Serverless (Lambda)
27 |
28 | ```javascript
29 | // API Gateway Proxy handler
30 | module.exports.handler = (event, context) =>
31 | api.handleRequest(
32 | {
33 | method: event.httpMethod,
34 | path: event.path,
35 | query: event.queryStringParameters,
36 | body: event.body,
37 | headers: event.headers,
38 | },
39 | event,
40 | context
41 | );
42 | ```
43 |
44 | [See full AWS SAM example](https://github.com/openapistack/openapi-backend/tree/main/examples/aws-sam)
45 |
46 | [See full AWS CDK example](https://github.com/openapistack/openapi-backend/tree/main/examples/aws-cdk)
47 |
48 | [See full SST example](https://github.com/openapistack/openapi-backend/tree/main/examples/aws-sst)
49 |
50 | [See full Serverless Framework example](https://github.com/openapistack/openapi-backend/tree/main/examples/serverless-framework)
51 |
52 | ### Azure Function
53 |
54 | ```javascript
55 | module.exports = (context, req) =>
56 | api.handleRequest(
57 | {
58 | method: req.method,
59 | path: req.params.path,
60 | query: req.query,
61 | body: req.body,
62 | headers: req.headers,
63 | },
64 | context,
65 | req
66 | );
67 | ```
68 |
69 | [See full Azure Function example](https://github.com/openapistack/openapi-backend/tree/main/examples/azure-function)
70 |
71 | ### Fastify
72 |
73 | ```ts
74 | import fastify from "fastify";
75 |
76 | fastify.route({
77 | method: ["GET", "POST", "PUT", "PATCH", "DELETE"],
78 | url: "/*",
79 | handler: async (request, reply) =>
80 | api.handleRequest(
81 | {
82 | method: request.method,
83 | path: request.url,
84 | body: request.body,
85 | query: request.query,
86 | headers: request.headers,
87 | },
88 | request,
89 | reply
90 | ),
91 | });
92 | fastify.listen();
93 | ```
94 |
95 | [See full Fastify example](https://github.com/openapistack/openapi-backend/tree/main/examples/fastify)
96 |
97 |
98 | ### Koa
99 |
100 | ```javascript
101 | import Koa from "koa";
102 | import bodyparser from "koa-bodyparser";
103 |
104 | const app = new Koa();
105 |
106 | app.use(bodyparser());
107 | app.use((ctx) => api.handleRequest(ctx.request, ctx));
108 | app.listen(9000);
109 | ```
110 |
111 | [See full Koa example](https://github.com/openapistack/openapi-backend/tree/main/examples/koa)
112 |
113 | ### Hapi
114 |
115 | ```javascript
116 | import Hapi from "@hapi/hapi";
117 |
118 | const server = new Hapi.Server({ host: "0.0.0.0", port: 9000 });
119 | server.route({
120 | method: ["GET", "POST", "PUT", "PATCH", "DELETE"],
121 | path: "/{path*}",
122 | handler: (req, h) =>
123 | api.handleRequest(
124 | {
125 | method: req.method,
126 | path: req.path,
127 | body: req.payload,
128 | query: req.query,
129 | headers: req.headers,
130 | },
131 | req,
132 | h
133 | ),
134 | });
135 | server.start();
136 | ```
137 |
138 | [See full Hapi example](https://github.com/openapistack/openapi-backend/tree/main/examples/hapi-typescript)
139 |
140 | ## More Examples
141 |
142 | A full list of openapi-stack boilerplate projects available here: [openapistack.co/docs/examples/boilerplate/](/docs/examples/boilerplate/)
143 |
--------------------------------------------------------------------------------
/docs/openapi-backend/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Quick Start: Backend"
3 | hide_title: true
4 | sidebar_position: 1
5 | ---
6 |
7 |