Skip to content

chroe: Release v2 #161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/comment-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { issue: { number: issue_number }, repo: { owner, repo }, payload } = context;
const { name: packageName, version } = require(`${process.env.GITHUB_WORKSPACE}/package.json`);
const fs = require('fs')
const jsonString = fs.readFileSync(`${process.env.GITHUB_WORKSPACE}/package.json`)
var packageJson = JSON.parse(jsonString)
const { name: packageName, version } = packageJson;

const body = [
`npm package published to pre tag.`,
Expand Down
20 changes: 16 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,30 @@ jobs:
- name: Build
run: pnpm -w build

- name: Run codegen
- name: Run codegen for react-app
run: pnpm --filter @7nohe/react-app generate:api

- name: Archive generated query file
- name: Run codegen for nextjs-app
run: pnpm --filter nextjs-app generate:api

- name: Run codegen for tanstack-router-app
run: pnpm --filter tanstack-router-app generate:api

- name: Archive generated query files
uses: actions/upload-artifact@v4
with:
name: generated-query-file-${{ matrix.os }}
path: examples/react-app/openapi/queries/index.ts
path: examples/react-app/openapi/queries

- name: Run tsc
- name: Run tsc in react-app
run: pnpm --filter @7nohe/react-app test:generated

- name: Run tsc in nextjs-app
run: pnpm --filter nextjs-app test:generated

- name: Run tsc in tanstack-router-app
run: pnpm --filter tanstack-router-app test:generated

- name: Run biome
run: pnpm biome check .
if: ${{ matrix.os == 'ubuntu-latest' }}
Expand Down
85 changes: 28 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ Register the command to the `scripts` property in your package.json file.
```json
{
"scripts": {
"codegen": "openapi-rq -i ./petstore.yaml -c axios"
"codegen": "openapi-rq -i ./petstore.yaml -c @hey-api/client-fetch"
}
}
```

You can also run the command without installing it in your project using the npx command.

```bash
$ npx --package @7nohe/openapi-react-query-codegen openapi-rq -i ./petstore.yaml -c axios
$ npx --package @7nohe/openapi-react-query-codegen openapi-rq -i ./petstore.yaml -c @hey-api/client-fetch
```

## Usage
Expand All @@ -46,23 +46,20 @@ 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 (choices: "angular", "axios", "fetch", "node", "xhr", default: "fetch")
--request <value> Path to custom request file
-c, --client <value> HTTP client to generate (choices: "@hey-api/client-fetch", "@hey-api/client-axios", default: "@hey-api/client-fetch")
--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 (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 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")
--initialPageParam <value> Initial value for the pagination parameter (default: "1")
-h, --help display help for command
--initialPageParam <value> Initial page value to query (default: "initialPageParam")
-h, --help display help for command
```

### Example Usage
Expand Down Expand Up @@ -95,9 +92,9 @@ $ openapi-rq -i ./petstore.yaml

```tsx
// App.tsx
import { usePetServiceFindPetsByStatus } from "../openapi/queries";
import { useFindPets } from "../openapi/queries";
function App() {
const { data } = usePetServiceFindPetsByStatus({ status: ["available"] });
const { data } = useFindPets();

return (
<div className="App">
Expand All @@ -114,16 +111,16 @@ export default App;

```tsx
import { useQuery } from "@tanstack/react-query";
import { PetService } from "../openapi/requests/services";
import { usePetServiceFindPetsByStatusKey } from "../openapi/queries";
import { findPets } from "../openapi/requests/services.gen";
import { useFindPetsKey } from "../openapi/queries";

function App() {
// You can still use the auto-generated query key
const { data } = useQuery({
queryKey: [usePetServiceFindPetsByStatusKey],
queryKey: [useFindPetsKey],
queryFn: () => {
// Do something here
return PetService.findPetsByStatus(["available"]);
return findPets();
},
});

Expand All @@ -137,9 +134,11 @@ export default App;

```tsx
// App.tsx
import { useDefaultClientFindPetsSuspense } from "../openapi/queries/suspense";
import { useFindPetsSuspense } from "../openapi/queries/suspense";
function ChildComponent() {
const { data } = useDefaultClientFindPetsSuspense({ tags: [], limit: 10 });
const { data } = useFindPetsSuspense({
query: { tags: [], limit: 10 },
});

return <ul>{data?.map((pet, index) => <li key={pet.id}>{pet.name}</li>)}</ul>;
}
Expand Down Expand Up @@ -170,13 +169,13 @@ export default App;

```tsx
// App.tsx
import { usePetServiceAddPet } from "../openapi/queries";
import { useAddPet } from "../openapi/queries";

function App() {
const { mutate } = usePetServiceAddPet();
const { mutate } = useAddPet();

const handleAddPet = () => {
mutate({ name: "Fluffy", status: "available" });
mutate({ body: { name: "Fluffy" } });
};

return (
Expand All @@ -200,22 +199,22 @@ To ensure the query key is created the same way as the query hook, you can use t

```tsx
import {
usePetServiceFindPetsByStatus,
usePetServiceAddPet,
UsePetServiceFindPetsByStatusKeyFn,
useFindPetsByStatus,
useAddPet,
UseFindPetsByStatusKeyFn,
} from "../openapi/queries";

// App.tsx
function App() {
const [status, setStatus] = React.useState(["available"]);
const { data } = usePetServiceFindPetsByStatus({ status });
const { mutate } = usePetServiceAddPet({
const { data } = useFindPetsByStatus({ status });
const { mutate } = useAddPet({
onSuccess: () => {
queryClient.invalidateQueries({
// Call the query key function to get the query key
// This is important to ensure the query key is created the same way as the query hook
// This insures the cache is invalidated correctly and is typed correctly
queryKey: [UsePetServiceFindPetsByStatusKeyFn({
queryKey: [UseFindPetsByStatusKeyFn({
status
})],
});
Expand Down Expand Up @@ -300,42 +299,13 @@ paths:
Usage of Generated Hooks:

```ts
import { useDefaultServiceFindPaginatedPetsInfinite } from "@/openapi/queries/infiniteQueries";
import { useFindPaginatedPetsInfinite } from "@/openapi/queries/infiniteQueries";

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

##### Runtime Configuration

You can modify the default values used by the generated service calls by modifying the OpenAPI configuration singleton object.

It's default location is `openapi/requests/core/OpenAPI.ts` and it is also exported from `openapi/index.ts`

Import the constant into your runtime and modify it before setting up the react app.

```typescript
/** main.tsx */
import { OpenAPI as OpenAPIConfig } from './openapi/requests/core/OpenAPI';
...
OpenAPIConfig.BASE = 'www.domain.com/api';
OpenAPIConfig.HEADERS = {
'x-header-1': 'value-1',
'x-header-2': 'value-2',
};
...
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>
);

```

## Development

### Install dependencies
Expand Down Expand Up @@ -365,6 +335,7 @@ pnpm snapshot
```

### Build example and validate generated code

```bash
npm run build && pnpm --filter @7nohe/react-app generate:api && pnpm --filter @7nohe/react-app test:generated
```
Expand Down
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
},
"files": {
"ignore": [
".vscode",
"dist",
"examples/react-app/openapi",
"coverage",
Expand Down
14 changes: 8 additions & 6 deletions examples/nextjs-app/app/components/PaginatedPets.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
"use client";

import { useDefaultServiceFindPaginatedPetsInfinite } from "@/openapi/queries/infiniteQueries";
import { useFindPaginatedPetsInfinite } 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: [],
const { data, fetchNextPage } = useFindPaginatedPetsInfinite({
query: {
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) => (
<React.Fragment key={group?.pets?.at(0)?.id}>
{group?.pets?.map((pet) => (
<li key={pet.id}>{pet.name}</li>
))}
</React.Fragment>
Expand Down
7 changes: 3 additions & 4 deletions examples/nextjs-app/app/components/Pets.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"use client";

import { useDefaultServiceFindPets } from "@/openapi/queries";
import { useFindPets } from "@/openapi/queries";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

export default function Pets() {
const { data } = useDefaultServiceFindPets({
limit: 10,
tags: [],
const { data } = useFindPets({
query: { tags: [], limit: 10 },
});

return (
Expand Down
7 changes: 3 additions & 4 deletions examples/nextjs-app/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { prefetchUseDefaultServiceFindPets } from "@/openapi/queries/prefetch";
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from "@tanstack/react-query";
import Link from "next/link";
import { prefetchUseFindPets } from "../openapi/queries/prefetch";
import Pets from "./components/Pets";

export default async function Home() {
const queryClient = new QueryClient();

await prefetchUseDefaultServiceFindPets(queryClient, {
limit: 10,
tags: [],
await prefetchUseFindPets(queryClient, {
query: { tags: [], limit: 10 },
});

return (
Expand Down
5 changes: 3 additions & 2 deletions examples/nextjs-app/app/providers.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import "../fetchClient";

// We can not useState or useRef in a server component, which is why we are
// extracting this part out into it's own file with 'use client' on top
import { useState } from "react";
// extracting this part out into

function makeQueryClient() {
return new QueryClient({
Expand Down
5 changes: 5 additions & 0 deletions examples/nextjs-app/fetchClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { client } from "@/openapi/requests/services.gen";

client.setConfig({
baseUrl: "http://localhost:4010",
});
4 changes: 2 additions & 2 deletions examples/nextjs-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
"build": "next build",
"start": "next start",
"lint": "next lint",
"generate:api": "rimraf ./openapi && node ../../dist/cli.mjs -i ../petstore.yaml -c axios --request ./request.ts --format=biome --lint=biome"
"generate:api": "rimraf ./openapi && node ../../dist/cli.mjs -i ../petstore.yaml --format=biome --lint=biome",
"test:generated": "tsc -p ./tsconfig.json --noEmit"
},
"dependencies": {
"@tanstack/react-query": "^5.32.1",
"@tanstack/react-query-devtools": "^5.32.1",
"axios": "^1.6.7",
"next": "^14.2.3",
"react": "^18",
"react-dom": "^18"
Expand Down
Loading