Skip to content
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
1 change: 1 addition & 0 deletions .changepacks/changepack_log_XguILLsu4POI-o73d3Thd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"packages/next-plugin/package.json":"Patch","packages/react-query/package.json":"Patch","packages/fetch/package.json":"Patch","packages/generator/package.json":"Patch","packages/core/package.json":"Patch","packages/utils/package.json":"Patch","packages/rsbuild-plugin/package.json":"Patch","packages/vite-plugin/package.json":"Patch","packages/webpack-plugin/package.json":"Patch"},"note":"Add DevupObject for typing","date":"2025-12-18T10:26:39.561791300Z"}
1 change: 1 addition & 0 deletions .changepacks/changepack_log_a3GPxwlaj0mikZBFNbEBC.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"packages/vite-plugin/package.json":"Patch","packages/next-plugin/package.json":"Patch","packages/rsbuild-plugin/package.json":"Patch","packages/webpack-plugin/package.json":"Patch","packages/react-query/package.json":"Patch","packages/utils/package.json":"Patch","packages/generator/package.json":"Patch","packages/fetch/package.json":"Patch","packages/core/package.json":"Patch"},"note":"Update lib","date":"2025-12-18T10:01:52.928637600Z"}
1 change: 1 addition & 0 deletions .changepacks/changepack_log_dMMF8UdE2s43x7QZwbIr6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"packages/next-plugin/package.json":"Patch","packages/rsbuild-plugin/package.json":"Patch","packages/core/package.json":"Patch","packages/vite-plugin/package.json":"Patch","packages/webpack-plugin/package.json":"Patch","packages/fetch/package.json":"Patch","packages/utils/package.json":"Patch","packages/generator/package.json":"Patch","packages/react-query/package.json":"Patch"},"note":"Fix interface indent struct","date":"2025-12-18T10:02:43.863144900Z"}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# Finder (MacOS) folder config
.DS_Store

.claude
146 changes: 146 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ This is a monorepo containing multiple packages:
- **`@devup-api/utils`** - Utility functions for OpenAPI processing
- **`@devup-api/generator`** - TypeScript interface generator from OpenAPI schemas
- **`@devup-api/fetch`** - Type-safe API client
- **`@devup-api/react-query`** - TanStack React Query integration
- **`@devup-api/vite-plugin`** - Vite plugin
- **`@devup-api/next-plugin`** - Next.js plugin
- **`@devup-api/webpack-plugin`** - Webpack plugin
Expand Down Expand Up @@ -276,6 +277,151 @@ if (result.data) {
}
```

### **Using DevupObject for Type References**

`DevupObject` allows you to reference generated schema types directly, which is useful for typing variables, function parameters, or component props.

```ts
import { createApi, type DevupObject } from '@devup-api/fetch'

// Access response types from the default OpenAPI schema
type User = DevupObject['User']
type Product = DevupObject['Product']

// Use in your code
const user: User = {
id: '123',
name: 'John Doe',
email: '[email protected]'
}

// For request/error types, specify the type category
type CreateUserRequest = DevupObject<'request'>['CreateUserBody']
type ApiError = DevupObject<'error'>['ErrorResponse']
```

---

## 🌐 Multiple API Servers

devup-api supports multiple OpenAPI schemas for working with different API servers.

### **Configuration**

Place multiple OpenAPI files in your project (e.g., `openapi.json`, `openapi2.json`) and the plugin will generate types for each.

### **Usage**

```ts
import { createApi, type DevupObject } from '@devup-api/fetch'

// Default server (uses openapi.json)
const api = createApi({
baseUrl: 'https://api.example.com',
})

// Second server (uses openapi2.json)
const api2 = createApi({
baseUrl: 'https://api.another-service.com',
serverName: 'openapi2.json',
})

// Make requests to different servers
const users = await api.get('getUsers', {})
const products = await api2.get('getProducts', {})

// Access types from different schemas
type User = DevupObject['User'] // From openapi.json
type Product = DevupObject<'response', 'openapi2.json'>['Product'] // From openapi2.json
```

---

## 🔄 React Query Integration

devup-api provides first-class support for TanStack React Query through the `@devup-api/react-query` package.

### **Installation**

```bash
npm install @devup-api/react-query @tanstack/react-query
```

### **Setup**

```ts
import { createApi } from '@devup-api/fetch'
import { createQueryClient } from '@devup-api/react-query'

const api = createApi('https://api.example.com')
const queryClient = createQueryClient(api)
```

### **useQuery**

```ts
function UserProfile({ userId }: { userId: string }) {
const { data, isLoading, error } = queryClient.useQuery(
'get',
'/users/{id}',
{ params: { id: userId } }
)

if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return <div>{data.name}</div>
}
```

### **useMutation**

```ts
function CreateUser() {
const mutation = queryClient.useMutation('post', 'createUser')

return (
<button onClick={() => mutation.mutate({
body: { name: 'John', email: '[email protected]' }
})}>
Create User
</button>
)
}
```

### **useSuspenseQuery**

```ts
function UserList() {
const { data } = queryClient.useSuspenseQuery('get', 'getUsers', {})
return <ul>{data.map(user => <li key={user.id}>{user.name}</li>)}</ul>
}
```

### **useInfiniteQuery**

```ts
function InfiniteUserList() {
const { data, fetchNextPage, hasNextPage } = queryClient.useInfiniteQuery(
'get',
'getUsers',
{
initialPageParam: 1,
getNextPageParam: (lastPage) => lastPage.nextPage,
}
)

return (
<>
{data?.pages.map(page =>
page.users.map(user => <div key={user.id}>{user.name}</div>)
)}
{hasNextPage && <button onClick={() => fetchNextPage()}>Load More</button>}
</>
)
}
```

---

## ⚙️ Configuration Options
Expand Down
72 changes: 72 additions & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ This skill helps you invoke the `devup-api` library to generate and use fully ty
- **Fetch-compatible:** Ergonomic API similar to standard `fetch`.
- **Zero Generics:** No complex generic types to manage manually.
- **Build Tool Integration:** Plugins for Vite, Next.js, Webpack, and Rsbuild.
- **React Query Integration:** First-class support for TanStack React Query with `@devup-api/react-query`.
- **Multiple API Servers:** Support for multiple OpenAPI schemas with `serverName` and `DevupObject` type access.
- **Two-phase Typing:** "Cold Typing" (relaxed types for initial setup) and "Bold Typing" (strict types after generation).

## Usage Instructions
Expand Down Expand Up @@ -98,6 +100,76 @@ if (response.data) {
}
```

## Using DevupObject for Type References

`DevupObject` provides direct access to generated schema types:

```ts
import { createApi, type DevupObject } from '@devup-api/fetch'

// Access response types
type User = DevupObject['User']

// Access request/error types
type CreateUserRequest = DevupObject<'request'>['CreateUserBody']
type ApiError = DevupObject<'error'>['ErrorResponse']

// For multiple OpenAPI schemas, specify the server name
type Product = DevupObject<'response', 'openapi2.json'>['Product']
```

## Multiple API Servers

Support multiple OpenAPI schemas with `serverName`:

```ts
import { createApi, type DevupObject } from '@devup-api/fetch'

// Default server
const api = createApi({ baseUrl: 'https://api.example.com' })

// Second server
const api2 = createApi({
baseUrl: 'https://api.another-service.com',
serverName: 'openapi2.json',
})

// Types from different schemas
type User = DevupObject['User'] // openapi.json
type Product = DevupObject<'response', 'openapi2.json'>['Product'] // openapi2.json
```

## React Query Integration

For React applications using TanStack React Query, use `@devup-api/react-query`:

```bash
npm install @devup-api/react-query @tanstack/react-query
```

```ts
import { createApi } from '@devup-api/fetch'
import { createQueryClient } from '@devup-api/react-query'

const api = createApi('https://api.example.com')
const queryClient = createQueryClient(api)

// useQuery
const { data } = queryClient.useQuery('get', '/users/{id}', { params: { id: '123' } })

// useMutation
const mutation = queryClient.useMutation('post', 'createUser')

// useSuspenseQuery
const { data } = queryClient.useSuspenseQuery('get', 'getUsers', {})

// useInfiniteQuery
const { data, fetchNextPage } = queryClient.useInfiniteQuery('get', 'getUsers', {
initialPageParam: 1,
getNextPageParam: (lastPage) => lastPage.nextPage,
})
```

## Guidelines

- **"Cold" vs "Bold" Typing:** When you first start, types might be `any` (Cold Typing). Run your build command (`dev` or `build`) to generate the types and enable strict checking (Bold Typing).
Expand Down
Loading