Skip to content

Commit

Permalink
feat: 🎸 add OpenAPI + Code Generation example
Browse files Browse the repository at this point in the history
  • Loading branch information
suin committed Apr 6, 2022
1 parent 8ac5fd1 commit d8d8b59
Show file tree
Hide file tree
Showing 9 changed files with 624 additions and 9 deletions.
103 changes: 101 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,107 @@ export default Pokemon;

- [Documentation](https://redux-toolkit.js.org/rtk-query/usage/code-generation)

Install @rtk-query/codegen-openapi:
Install @rtk-query/codegen-openapi and its dependencies:

```shell
yarn add -D @rtk-query/codegen-openapi
yarn add -D @rtk-query/codegen-openapi esbuild esbuild-runner
```

Create an empty api using `createApi` like:

```typescript
// store/emptyApi.ts
// Or from '@reduxjs/toolkit/query' if not using the auto-generated hooks
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

// initialize an empty api service that we'll inject endpoints into later as needed
export const emptySplitApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: "https://petstore.swagger.io/v2/" }),
endpoints: () => ({}),
});
```

Generate a config file (json, js or ts) with contents like:

```typescript
// openapi-config.ts
import type { ConfigFile } from "@rtk-query/codegen-openapi";

// https://redux-toolkit.js.org/rtk-query/usage/code-generation#simple-usage
const config: ConfigFile = {
schemaFile: "https://petstore3.swagger.io/api/v3/openapi.json",
apiFile: "./store/emptyApi.ts",
apiImport: "emptySplitApi",
outputFile: "./store/petApi.ts",
exportName: "petApi",
hooks: true,
};

export default config;
```

and then call the code generator:

```shell
npx @rtk-query/codegen-openapi openapi-config.ts
```

This generates a new api file in the `store` directory.

Wrap your application with the `Provider`:

```tsx
// pages/_app.tsx
import type { AppProps } from "next/app";
import { ApiProvider } from "@reduxjs/toolkit/query/react";
import { petApi } from "../store/petApi";
import "../styles/globals.css";

function MyApp({ Component, pageProps, router }: AppProps) {
return (
<ApiProvider api={petApi}>
<Component {...pageProps} />
</ApiProvider>
);
}

export default MyApp;
```

Use the query in a component:

```tsx
// pages/pet.ts
import { NextPage } from "next";
import { useFindPetsByStatusQuery } from "../store/petApi";

const Pet: NextPage = (props) => {
const { data, error, isLoading } = useFindPetsByStatusQuery({
status: "available",
});

return (
<div>
<h1>Petstore</h1>
<p>
<a href="https://redux-toolkit.js.org/rtk-query/usage/code-generation">
see the tutorial
</a>
</p>
<div>
{error ? (
<>Oh no, there was an error</>
) : isLoading ? (
<>Loading...</>
) : data ? (
<>
<pre>{JSON.stringify(data, null, 2)}</pre>
</>
) : null}
</div>
</div>
);
};

export default Pet;
```
13 changes: 13 additions & 0 deletions openapi-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ConfigFile } from "@rtk-query/codegen-openapi";

// https://redux-toolkit.js.org/rtk-query/usage/code-generation#simple-usage
const config: ConfigFile = {
schemaFile: "https://petstore3.swagger.io/api/v3/openapi.json",
apiFile: "./store/emptyApi.ts",
apiImport: "emptySplitApi",
outputFile: "./store/petApi.ts",
exportName: "petApi",
hooks: true,
};

export default config;
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"@types/node": "17.0.23",
"@types/react": "17.0.43",
"@types/react-dom": "17.0.14",
"esbuild": "^0.14.31",
"esbuild-runner": "^2.2.1",
"eslint": "8.12.0",
"eslint-config-next": "12.1.4",
"prettier": "^2.6.2",
Expand Down
15 changes: 12 additions & 3 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import type { AppProps } from "next/app";
import { Provider } from "react-redux";
import { store } from "../store";
import { ApiProvider } from "@reduxjs/toolkit/query/react";
import { petApi } from "../store/petApi";
import "../styles/globals.css";

function MyApp({ Component, pageProps }: AppProps) {
function MyApp({ Component, pageProps, router }: AppProps) {
if (router.pathname === "/pokemon") {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
return (
<Provider store={store}>
<ApiProvider api={petApi}>
<Component {...pageProps} />
</Provider>
</ApiProvider>
);
}

Expand Down
10 changes: 6 additions & 4 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ const Home: NextPage = () => {
</a>
</Link>

<a href="https://nextjs.org/learn" className={styles.card}>
<h2>Learn &rarr;</h2>
<p>Learn about Next.js in an interactive course with quizzes!</p>
</a>
<Link href="/pet">
<a className={styles.card}>
<h2>Petstore &rarr;</h2>
<p>OpenAPI + Code Generation</p>
</a>
</Link>

<a
href="https://github.com/vercel/next.js/tree/canary/examples"
Expand Down
32 changes: 32 additions & 0 deletions pages/pet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NextPage } from "next";
import { useFindPetsByStatusQuery } from "../store/petApi";

const Pet: NextPage = (props) => {
const { data, error, isLoading } = useFindPetsByStatusQuery({
status: "available",
});

return (
<div>
<h1>Petstore</h1>
<p>
<a href="https://redux-toolkit.js.org/rtk-query/usage/code-generation">
see the tutorial
</a>
</p>
<div>
{error ? (
<>Oh no, there was an error</>
) : isLoading ? (
<>Loading...</>
) : data ? (
<>
<pre>{JSON.stringify(data, null, 2)}</pre>
</>
) : null}
</div>
</div>
);
};

export default Pet;
8 changes: 8 additions & 0 deletions store/emptyApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Or from '@reduxjs/toolkit/query' if not using the auto-generated hooks
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

// initialize an empty api service that we'll inject endpoints into later as needed
export const emptySplitApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: "https://petstore.swagger.io/v2/" }),
endpoints: () => ({}),
});
Loading

0 comments on commit d8d8b59

Please sign in to comment.