Skip to content

Commit

Permalink
Merge branch 'main' into collink/update-openapi-ts-version-for-namesp…
Browse files Browse the repository at this point in the history
…aces
  • Loading branch information
collink authored Aug 7, 2024
2 parents 4c826c2 + 77f0aae commit 54be05a
Show file tree
Hide file tree
Showing 25 changed files with 666 additions and 79 deletions.
85 changes: 77 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## Features

- Generates custom react hooks that use React Query's `useQuery`, `useSuspenseQuery` and `useMutation` hooks
- Generates custom react hooks that use React Query's `useQuery`, `useSuspenseQuery`, `useMutation` and `useInfiniteQuery` hooks
- Generates query keys and functions for query caching
- Generates pure TypeScript clients generated by [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts)

Expand Down Expand Up @@ -45,18 +45,21 @@ Options:
-V, --version output the version number
-i, --input <value> OpenAPI specification, can be a path, url or string content (required)
-o, --output <value> Output directory (default: "openapi")
-c, --client <value> HTTP client to generate [fetch, xhr, node, axios, angular] (default: "fetch")
-c, --client <value> HTTP client to generate (choices: "angular", "axios", "fetch", "node", "xhr", default: "fetch")
--request <value> Path to custom request file
--format <value> Process output folder with formatter? ['biome', 'prettier']
--lint <value> Process output folder with linter? ['eslint', 'biome']
--format <value> Process output folder with formatter? (choices: "biome", "prettier")
--lint <value> Process output folder with linter? (choices: "biome", "eslint")
--operationId Use operation ID to generate operation names?
--serviceResponse <value> Define shape of returned value from service calls ['body', 'response'] (default: "body")
--serviceResponse <value> Define shape of returned value from service calls (choices: "body", "response", default: "body")
--base <value> Manually set base in OpenAPI config instead of inferring from server value
--enums <value> Generate JavaScript objects from enum definitions? ['javascript', 'typescript', 'typescript+namespace']
--enums <value> Generate JavaScript objects from enum definitions? (choices: "javascript", "typescript")
--useDateType Use Date type instead of string for date types for models, this will not convert the data to a Date object
--debug Enable debug mode
--noSchemas Disable generating schemas for request and response objects
--schemaTypes <value> Define the type of schema generation ['form', 'json'] (default: "json")
--debug Run in debug mode?
--noSchemas Disable generating JSON schemas
--schemaType <value> Type of JSON schema [Default: 'json'] (choices: "form", "json")
--pageParam <value> Name of the query parameter used for pagination (default: "page")
--nextPageParam <value> Name of the response parameter used for next page (default: "nextPage")
-h, --help display help for command
```

Expand Down Expand Up @@ -234,6 +237,72 @@ function App() {
export default App;
```

##### Using Infinite Query hooks

This feature will generate a function in infiniteQueries.ts when the name specified by the `pageParam` option exists in the query parameters and the name specified by the `nextPageParam` option exists in the response.

Example Schema:

```yml
paths:
/paginated-pets:
get:
description: |
Returns paginated pets from the system that the user has access to
operationId: findPaginatedPets
parameters:
- name: page
in: query
description: page number
required: false
schema:
type: integer
format: int32
- name: tags
in: query
description: tags to filter by
required: false
style: form
schema:
type: array
items:
type: string
- name: limit
in: query
description: maximum number of results to return
required: false
schema:
type: integer
format: int32
responses:
'200':
description: pet response
content:
application/json:
schema:
type: object
properties:
pets:
type: array
items:
$ref: '#/components/schemas/Pet'
nextPage:
type: integer
format: int32
minimum: 1
```
Usage of Generated Hooks:
```ts
import { useDefaultServiceFindPaginatedPetsInfinite } from "@/openapi/queries/infiniteQueries";

const { data, fetchNextPage } = useDefaultServiceFindPaginatedPetsInfinite({
limit: 10,
tags: [],
});
```

##### Runtime Configuration

You can modify the default values used by the generated service calls by modifying the OpenAPI configuration singleton object.
Expand Down
37 changes: 37 additions & 0 deletions examples/nextjs-app/app/components/PaginatedPets.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";

import { useDefaultServiceFindPaginatedPetsInfinite } from "@/openapi/queries/infiniteQueries";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import React from "react";

export default function PaginatedPets() {
const { data, fetchNextPage } = useDefaultServiceFindPaginatedPetsInfinite({
limit: 10,
tags: [],
});

return (
<>
<h1>Pet List with Pagination</h1>
<ul>
{data?.pages.map((group, i) => (
<React.Fragment key={group.pets?.at(0)?.id}>
{group.pets?.map((pet) => (
<li key={pet.id}>{pet.name}</li>
))}
</React.Fragment>
))}
</ul>
{data?.pages.at(-1)?.nextPage && (
<button
type="button"
onClick={() => fetchNextPage()}
className="bg-blue-500 px-4 py-2 text-white mt-4"
>
Load More
</button>
)}
<ReactQueryDevtools initialIsOpen={false} />
</>
);
}
File renamed without changes.
9 changes: 9 additions & 0 deletions examples/nextjs-app/app/infinite-loader/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import PaginatedPets from "../components/PaginatedPets";

export default async function InfiniteLoaderPage() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<PaginatedPets />
</main>
);
}
6 changes: 5 additions & 1 deletion examples/nextjs-app/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
QueryClient,
dehydrate,
} from "@tanstack/react-query";
import Pets from "./pets";
import Link from "next/link";
import Pets from "./components/Pets";

export default async function Home() {
const queryClient = new QueryClient();
Expand All @@ -19,6 +20,9 @@ export default async function Home() {
<HydrationBoundary state={dehydrate(queryClient)}>
<Pets />
</HydrationBoundary>
<Link href="/infinite-loader" className="underline">
Go to Infinite Loader &rarr;
</Link>
</main>
);
}
5 changes: 4 additions & 1 deletion examples/nextjs-app/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ export const request = <T>(
url: options.url,
data: options.body,
method: options.method,
params: options.path,
params: {
...options.query,
...options.path,
},
headers: formattedHeaders,
cancelToken: source.token,
})
Expand Down
46 changes: 46 additions & 0 deletions examples/petstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,52 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
/paginated-pets:
get:
description: |
Returns paginated pets from the system that the user has access to
operationId: findPaginatedPets
parameters:
- name: page
in: query
description: page number
required: false
schema:
type: integer
format: int32
- name: tags
in: query
description: tags to filter by
required: false
style: form
schema:
type: array
items:
type: string
- name: limit
in: query
description: maximum number of results to return
required: false
schema:
type: integer
format: int32
responses:
'200':
description: pet response
content:
application/json:
schema:
type: object
properties:
pets:
type: array
items:
$ref: '#/components/schemas/Pet'
nextPage:
type: integer
format: int32
minimum: 1

components:
schemas:
Pet:
Expand Down
5 changes: 4 additions & 1 deletion examples/react-app/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ export const request = <T>(
url: options.url,
data: options.body,
method: options.method,
params: options.path,
params: {
...options.query,
...options.path,
},
headers: formattedHeaders,
cancelToken: source.token,
})
Expand Down
52 changes: 27 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,7 @@
{
"name": "@7nohe/openapi-react-query-codegen",
"version": "1.4.1",
"version": "1.5.1",
"description": "OpenAPI React Query Codegen",
"bin": {
"openapi-rq": "dist/cli.mjs"
},
"type": "module",
"workspaces": ["examples/*"],
"scripts": {
"build": "rimraf dist && tsc -p tsconfig.json",
"lint": "biome check .",
"lint:fix": "biome check --apply .",
"preview": "npm run build && npm -C examples/react-app run generate:api",
"prepublishOnly": "npm run build",
"release": "npx git-ensure -a && npx bumpp --commit --tag --push",
"test": "vitest --coverage.enabled true",
"snapshot": "vitest --update"
},
"repository": {
"type": "git",
"url": "git+https://github.com/7nohe/openapi-react-query-codegen.git"
},
"homepage": "https://github.com/7nohe/openapi-react-query-codegen",
"bugs": "https://github.com/7nohe/openapi-react-query-codegen/issues",
"files": ["dist"],
"keywords": [
"codegen",
"react-query",
Expand All @@ -34,8 +12,30 @@
"openapi-typescript-codegen",
"@hey-api/openapi-ts"
],
"author": "Daiki Urata (@7nohe)",
"homepage": "https://github.com/7nohe/openapi-react-query-codegen",
"bugs": "https://github.com/7nohe/openapi-react-query-codegen/issues",
"repository": {
"type": "git",
"url": "git+https://github.com/7nohe/openapi-react-query-codegen.git"
},
"license": "MIT",
"author": "Daiki Urata (@7nohe)",
"type": "module",
"bin": {
"openapi-rq": "dist/cli.mjs"
},
"files": ["dist"],
"workspaces": ["examples/*"],
"scripts": {
"build": "rimraf dist && tsc -p tsconfig.json",
"lint": "biome check .",
"lint:fix": "biome check --apply .",
"prepublishOnly": "npm run build",
"preview": "npm run build && npm -C examples/react-app run generate:api",
"release": "npx git-ensure -a && npx bumpp --commit --tag --push",
"snapshot": "vitest --update",
"test": "vitest --coverage.enabled true"
},
"dependencies": {
"@hey-api/openapi-ts": "0.52.0"
},
Expand All @@ -58,7 +58,9 @@
"ts-morph": "22.x",
"typescript": "5.x"
},
"packageManager": "[email protected]",
"engines": {
"node": ">=14"
"node": ">=14",
"pnpm": ">=9"
}
}
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

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

12 changes: 12 additions & 0 deletions src/cli.mts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export type LimitedUserConfig = {
debug?: boolean;
noSchemas?: boolean;
schemaType?: "form" | "json";
pageParam: string;
nextPageParam: string;
};

async function setupProgram() {
Expand Down Expand Up @@ -90,6 +92,16 @@ async function setupProgram() {
"Type of JSON schema [Default: 'json']",
).choices(["form", "json"]),
)
.option(
"--pageParam <value>",
"Name of the query parameter used for pagination",
"page",
)
.option(
"--nextPageParam <value>",
"Name of the response parameter used for next page",
"nextPage",
)
.parse();

const options = program.opts<LimitedUserConfig>();
Expand Down
2 changes: 1 addition & 1 deletion src/common.mts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function extractPropertiesFromObjectParam(param: ParameterDeclaration) {
* TODO: Replace with a more robust solution.
*/
export function getShortType(type: string) {
return type.replaceAll(/import\(".*"\)\./g, "");
return type.replaceAll(/import\(".*?"\)\./g, "");
}

export function getClassesFromService(node: SourceFile) {
Expand Down
1 change: 1 addition & 0 deletions src/constants.mts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const modalsFileName = "types.gen";

export const OpenApiRqFiles = {
queries: "queries",
infiniteQueries: "infiniteQueries",
common: "common",
suspense: "suspense",
index: "index",
Expand Down
Loading

0 comments on commit 54be05a

Please sign in to comment.