Skip to content

Commit

Permalink
feat: Create a react query hook plugin (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
Embraser01 authored Jun 5, 2024
1 parent 41d6e62 commit 764bd70
Show file tree
Hide file tree
Showing 99 changed files with 3,382 additions and 372 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
examples/src/
lib/

packages/typoas-react-query/src/__tests__/sample-client.ts
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ module.exports = {
node: true,
},
plugins: ['jest', '@typescript-eslint'],
ignorePatterns: ['**/dist/'],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
};
868 changes: 841 additions & 27 deletions .pnp.cjs

Large diffs are not rendered by default.

42 changes: 38 additions & 4 deletions .pnp.loader.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
595 changes: 298 additions & 297 deletions .yarn/releases/yarn-4.1.0.cjs → .yarn/releases/yarn-4.2.2.cjs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .yarn/versions/f5d9f57f.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
releases:
"@typoas/react-query": major
"@typoas/runtime": patch
2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ enableGlobalCache: false

npmPublishAccess: public

yarnPath: .yarn/releases/yarn-4.1.0.cjs
yarnPath: .yarn/releases/yarn-4.2.2.cjs
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Main features are:
- Fully typed and fully customizable
- References `$ref` handling (including cyclic refs)
- **Tree Shaking** out of the box
- **React Query** integration
- Support for `allOf`, `oneOf` and `anyOf` schemas.
- Automatically convert `format: 'date-time'` to JS `Date`
- Handle **API Key**, **HTTP Config** and **OAuth2**<sup>1</sup> auth security schemes
Expand All @@ -27,11 +28,12 @@ Main features are:
> <sup>1</sup>: OAuth2 scheme does not handle flows to retrieve an `accessToken`.
> You need to provide your own `accessToken` through the `provider.getConfig()` function.
The project is split into 3 parts:
The project is split into 4 packages:

- [`@typoas/generator`](./packages/typoas-generator) is used to generate the API specific code.
- [`@typoas/cli`](./packages/typoas-cli) is a CLI entry point built on top of `@typoas/generator`.
- [`@typoas/runtime`](./packages/typoas-runtime) is the package that will be used by the generated code.
- [`@typoas/react-query`](./packages/typoas-react-query) integrates _Typoas_ with [React Query](https://tanstack.com/query/latest).

---

Expand All @@ -44,6 +46,7 @@ The project is split into 3 parts:
- [Customize fetch implementation](#customize-fetch-implementation)
- [Handling authentification](#handling-authentification)
- [Customizing the serialization](#customizing-the-serialization)
- [Using with React Query](#using-with-react-query)
- [Examples](#examples)
- [Notes](#notes)
- [External references](#external-references)
Expand Down Expand Up @@ -264,6 +267,10 @@ You can switch some serialization options by passing a `serializerOptions` objec

> Not every serialization option is supported. See [#11](https://github.com/Embraser01/typoas/issues/11) for more information.
### Using with React Query

Documentation is available in the [`@typoas/react-query`](./packages/typoas-react-query) package.

## Examples

You can find examples in the [`examples`](./examples) folder.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
"prettier": "^3.2.5",
"typescript": "^5.3.3"
},
"packageManager": "yarn@4.1.0"
"packageManager": "yarn@4.2.2"
}
169 changes: 169 additions & 0 deletions packages/typoas-react-query/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# `@typoas/react-query`

> This package is related to the [_Typoas_](https://github.com/Embraser01/typoas) project.
This package provides a set of hook factories to interact with a generated _Typoas_ client in a React application with [`react-query`](https://tanstack.com/query/latest).

## Install

This dependency should be added into your dependencies.

```shell
# @typoas/react-query depends on @tanstack/react-query and @typoas/runtime (peer dependencies)
yarn add @typoas/react-query @tanstack/react-query @typoas/runtime
```

## Usage

### Configuration

First, you will need to add the `ApiContextProvider` to your react application:

```tsx
import { ApiContextProvider } from '@typoas/react-query';
import { createClient } from './generated/client';

const client = createClient();

export function App() {
return (
<ApiContextProvider client={client}>
<MyComponent />
</ApiContextProvider>
);
}
```

Once the `ApiContextProvider` is added, you can use one of the hook factories to interact with your generated client:

- [`createQueryHook`](#createqueryhook)
- [`createInfiniteQueryHook`](#createinfinitequeryhook)
- [`createMutationHook`](#createmutationhook)

### `createQueryHook`

```tsx
import { createQueryHook } from '@typoas/react-query';
import { findPetsByStatus } from './generated/client';

const useFindPetsByStatus = createQueryHook(findPetsByStatus, {
// Base options used for all queries created with this hook
});

export function MyComponent() {
const { data, isLoading } = useFindPetsByStatus({
// These options are typed based on the operation's parameters
// All react-query options are supported except for 'queryFn'
queryKey: [{ status: 'available' }],
});

if (isLoading) {
return <div>Loading...</div>;
}

return (
<ul>
{data.map((pet) => (
<li key={pet.id}>{pet.name}</li>
))}
</ul>
);
}
```

### `createInfiniteQueryHook`

Similar as the `createQueryHook`, supporting infinite queries.

```tsx
import { createQueryHook } from '@typoas/react-query';
import { findPetsByStatus } from './generated/client';

const useFindPetsByStatus = createInfiniteQueryHook(findPetsByStatus, {
initialPageParam: { page: 1 },
getNextPageParam: (lastPage, allPages) => {
if (allPages.length === 1) {
return { page: 2 };
}
return undefined;
},
});

export function MyComponent() {
const { data, isLoading } = useFindPetsByStatus({
// These options are typed based on the operation's parameters
// All react-query options are supported except for 'queryFn'
queryKey: [{ status: 'available' }],
});

if (isLoading) {
return <div>Loading...</div>;
}

return (
<ul>
{data.pages.map((page) =>
page.map((pet) => <li key={pet.id}>{pet.name}</li>),
)}
</ul>
);
}
```

### `createMutationHook`

Mutation are also supported:

```tsx
import { useCallback } from 'react';
import { createQueryHook } from '@typoas/react-query';
import { addPet } from './generated/client';

const useAddPetMutation = createMutationHook(addPet, {});

export function MyComponent() {
const mutation = useAddPetMutation({});

const onClick = useCallback(() => {
mutation.mutate([
{}, // Path params
{ id: 1, name: 'Rufus', status: 'available', photoUrls: [] }, // Body
]);
}, [mutation.mutate]);

return <button onClick={onClick}></button>;
}
```

## Notes

Each hook factory accepts a second argument which is the base options for the query/mutation. This also allows 2 additional options:

- `fetcherData`: Object to be passed to the _Typoas_ fetcher
- `successStatus`: Status code to consider the request as successful (default: 2XX, same as the `ok` function in `@typoas/runtime`)

Note that `fetcherData` can also be passed in the hook options (will override the base one if provided).

If you need, you can also use the `useApiContext` hook to access the client directly:

```tsx
import { useEffect } from 'react';
import { useApiContext } from '@typoas/react-query';
import { addPet } from './generated/client';

// Must be used as a child of the ApiContextProvider
export function MyComponent() {
const ctx = useApiContext();

// Use the client
useEffect(() => {
addPet(
ctx,
{},
{ id: 1, name: 'Rufus', status: 'available', photoUrls: [] },
);
}, []);

return <div></div>;
}
```
6 changes: 6 additions & 0 deletions packages/typoas-react-query/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
testMatch: ['**/__tests__/**/*.spec.[jt]s?(x)'],
testPathIgnorePatterns: ['/node_modules/', '/lib/'],
};
45 changes: 45 additions & 0 deletions packages/typoas-react-query/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "@typoas/react-query",
"version": "3.0.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/embraser01/typoas",
"directory": "packages/typoas-react-query"
},
"main": "./src/index.ts",
"scripts": {
"prepack": "tsc",
"start": "ts-node ./src/bin.ts",
"test:types": "tsc --noEmit",
"test": "jest"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
"@tanstack/react-query": "^5.35.5",
"@testing-library/react": "^15.0.7",
"@types/node": "^20.11.24",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.3.0",
"@typoas/runtime": "workspace:^",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"ts-jest": "^29.1.2",
"typescript": "^5.3.3"
},
"peerDependencies": {
"@tanstack/react-query": "^5.35.5",
"@typoas/runtime": "workspace:^"
},
"files": [
"/lib/**/*.js",
"/lib/**/*.d.ts",
"!/lib/**/__tests__/*"
],
"publishConfig": {
"main": "./lib/index.js",
"types": "./lib/index.d.ts"
}
}
Loading

0 comments on commit 764bd70

Please sign in to comment.