npm package: @nijesmik/openapi-ky
Description: Type-safe API client powered by [ky](https://github.com/sindresorhus/ky) and [openapi-typescript](https://github.com/openapi-ts/openapi-typescript).
Latest version: 0.2.0

# @nijesmik/openapi-ky

Type-safe API client powered by [ky](https://github.com/sindresorhus/ky) and [openapi-typescript](https://github.com/openapi-ts/openapi-typescript).

[한국어](#한국어)

## Installation

```bash
npm install @nijesmik/openapi-ky ky
```

> `ky` is a peer dependency.

## Usage

### Creating a Client

```ts
import { createClient } from '@nijesmik/openapi-ky';
import type { paths } from './schema'; // generated by openapi-typescript

const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
});
```

### Making Requests

```ts
// GET
const users = await client.get('/users');

// GET with path params
const user = await client.get('/users/{userId}', {
  params: { userId: 1 },
});

// POST with JSON body
const created = await client.post('/posts', {
  json: { title: 'Hello', content: 'World' },
});

// PUT with path params + body
await client.put('/posts/{postId}', {
  params: { postId: 1 },
  json: { title: 'Replaced', content: 'New content' },
});

// PATCH with path params + body
await client.patch('/posts/{postId}', {
  params: { postId: 1 },
  json: { title: 'Updated' },
});

// DELETE
await client.delete('/posts/{postId}', {
  params: { postId: 1 },
});
```

All [ky options](https://github.com/sindresorhus/ky#options) such as `searchParams`, `headers`, etc. can also be passed in.

### Hooks

Hooks allow you to intercept and modify requests, responses, and errors. All [ky hooks](https://github.com/sindresorhus/ky#hooks) are supported, with the following additions:

#### `beforeHTTPError`

Maps to ky's `beforeError`. Called before an `HTTPError` is thrown, allowing you to modify the error. The hook must return the error object.

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  hooks: {
    beforeHTTPError: [
      async (error) => {
        const body = await error.response.json();
        error.message = `${body.message} (${error.response.status})`;
        return error;
      },
    ],
  },
});
```

#### `beforeAnyError`

Called for all errors (`HTTPError`, `TimeoutError`, network errors, etc.) before they are thrown. Unlike `beforeHTTPError`, this hook does not return or modify the error.

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  hooks: {
    beforeAnyError: [
      (error) => {
        console.error('Request failed:', error);
      },
    ],
  },
});
```

### Retry

Ky's [retry](https://github.com/sindresorhus/ky#retry) options are fully supported.

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  retry: {
    limit: 3,
    statusCodes: [408, 429, 500, 502, 503, 504],
  },
});
```

### Timeout

Ky's [timeout](https://github.com/sindresorhus/ky#timeout) is fully supported (default: 10 seconds).

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  timeout: 30000,
});
```

### Type Utilities

```ts
import type { BodyOf, SuccessOf } from '@nijesmik/openapi-ky';
import type { paths } from './schema';

// Extract POST body type
type CreatePostBody = BodyOf<paths, '/posts', 'post'>;

// Extract success response type
type UserResponse = SuccessOf<paths, '/users/{userId}', 'get'>;
```

`PathOf` and `Options` are also available for advanced use cases.

## License

MIT

---

## 한국어

`openapi-typescript`로 생성한 `schema.d.ts`를 기반으로 path, method, request/response 타입이 자동 추론되는 타입 세이프 API 클라이언트입니다.

### 설치

```bash
npm install @nijesmik/openapi-ky ky
```

> `ky`는 peer dependency입니다.

### 사용법

#### 클라이언트 생성

```ts
import { createClient } from '@nijesmik/openapi-ky';
import type { paths } from './schema'; // openapi-typescript로 생성

const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
});
```

#### 요청 보내기

```ts
// GET
const users = await client.get('/users');

// GET with path params
const user = await client.get('/users/{userId}', {
  params: { userId: 1 },
});

// POST with JSON body
const created = await client.post('/posts', {
  json: { title: 'Hello', content: 'World' },
});

// PUT with path params + body
await client.put('/posts/{postId}', {
  params: { postId: 1 },
  json: { title: 'Replaced', content: 'New content' },
});

// PATCH with path params + body
await client.patch('/posts/{postId}', {
  params: { postId: 1 },
  json: { title: 'Updated' },
});

// DELETE
await client.delete('/posts/{postId}', {
  params: { postId: 1 },
});
```

`searchParams`, `headers` 등 모든 [ky 옵션](https://github.com/sindresorhus/ky#options)을 함께 전달할 수 있습니다.

### Hooks

hooks를 사용하여 요청, 응답, 에러를 가로채고 수정할 수 있습니다. 모든 [ky hooks](https://github.com/sindresorhus/ky#hooks)를 지원하며, 다음 훅이 추가로 제공됩니다:

#### `beforeHTTPError`

ky의 `beforeError`에 매핑됩니다. `HTTPError`가 throw되기 전에 호출되어 에러를 수정할 수 있습니다. 훅에서 에러 객체를 반환해야 합니다.

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  hooks: {
    beforeHTTPError: [
      async (error) => {
        const body = await error.response.json();
        error.message = `${body.message} (${error.response.status})`;
        return error;
      },
    ],
  },
});
```

#### `beforeAnyError`

모든 에러(`HTTPError`, `TimeoutError`, 네트워크 에러 등)에 대해 throw되기 전에 호출됩니다. `beforeHTTPError`와 달리 에러를 반환하거나 수정하지 않습니다.

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  hooks: {
    beforeAnyError: [
      (error) => {
        console.error('Request failed:', error);
      },
    ],
  },
});
```

### Retry

ky의 [retry](https://github.com/sindresorhus/ky#retry) 옵션을 그대로 지원합니다.

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  retry: {
    limit: 3,
    statusCodes: [408, 429, 500, 502, 503, 504],
  },
});
```

### Timeout

ky의 [timeout](https://github.com/sindresorhus/ky#timeout)을 그대로 지원합니다 (기본값: 10초).

```ts
const client = createClient<paths>({
  prefixUrl: 'https://api.example.com',
  timeout: 30000,
});
```

### 타입 유틸리티

```ts
import type { BodyOf, SuccessOf } from '@nijesmik/openapi-ky';
import type { paths } from './schema';

// POST body 타입 추출
type CreatePostBody = BodyOf<paths, '/posts', 'post'>;

// 성공 응답 타입 추출
type UserResponse = SuccessOf<paths, '/users/{userId}', 'get'>;
```

`PathOf`, `Options` 타입도 제공됩니다.

### 라이선스

MIT