npm package: @mintwoo/restapi
Description: `package.json`에 description이 없습니다.
Latest version: 1.4.1

# @mintwoo/restapi
`package.json`에 description이 없습니다.

## Why / What it solves
- React Query + Axios 기반의 REST 헬퍼로 API 호출과 에러 포맷을 표준화합니다.
- CRUD 훅과 알림 처리 흐름을 한 번에 제공합니다.
- 페이지네이션 및 검색 조건 결합을 지원합니다.

## Features
- [x] Axios 인스턴스 생성 및 에러 표준화
- [x] GET/POST/PUT/DELETE 헬퍼 제공
- [x] React Query 기반 CRUD 훅
- [x] invalidate/patch/none 캐시 갱신 전략
- [x] 검색 조건 통합 훅 제공
- [x] Provider 기반 알림 콜백
- [x] TypeScript 타입 제공 (`dist/index.d.ts`)

## Installation
```bash
# npm
npm install @mintwoo/restapi

# yarn
yarn add @mintwoo/restapi

# pnpm
pnpm add @mintwoo/restapi
```

Peer dependencies (`package.json` 기준):
```bash
npm install axios@^1.6.8 query-string@^7.1.0 @tanstack/react-query@^5.36.2 react@18.3.1 react-dom@18.3.1 react-native@0.76.7
```

## Quick Start
```tsx
import { RaProvider, createApiInstance, useRestQuery } from '@mintwoo/restapi'

createApiInstance({
  baseURL: 'https://api.example.com',
  headers: { Authorization: 'Bearer <token>' }
})

const Users = () => {
  const { data, onRefresh } = useRestQuery('users', {
    notiTitle: 'User',
    getProps: { enabled: true }
  })

  return (
    <div>
      <button onClick={() => onRefresh()}>Refresh</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}

export default function App() {
  return (
    <RaProvider
      value={{
        api: ({ type, title, subTitle }) => console.log(type, title, subTitle)
      }}
    >
      <Users />
    </RaProvider>
  )
}
```

## Usage

### 기본 사용
```tsx
import { useRestQuery } from '@mintwoo/restapi'

const { data, onPost, onPut, onDelete } = useRestQuery('users', {
  notiTitle: 'User',
  notiShow: ['get', 'post', 'put', 'delete', 'get_err', 'post_err', 'put_err', 'delete_err'],
  getProps: { enabled: true },
  postProps: { enabled: true },
  putProps: { enabled: true },
  deleteProps: { enabled: true },
  refresh: { strategy: 'invalidate' }
})
```

### 옵션 / 설정

`useRestQuery(routerName, routerProps, onFinish)` 옵션 요약:

| 이름 | 타입 | 기본값 | 설명 |
| --- | --- | --- | --- |
| `notiTitle` | `string` | 없음 | 알림 제목의 기본 문자열입니다. |
| `notiShow` | `restApiType[]` | 없음 | 알림을 표시할 이벤트 목록입니다. |
| `getProps` | `object` | `enabled: false` | GET 쿼리 옵션입니다. |
| `getPageProps` | `object` | `enabled: false` | 무한 스크롤 쿼리 옵션입니다. |
| `postProps` | `object` | `enabled: false` | POST 뮤테이션 옵션입니다. |
| `putProps` | `object` | `enabled: false` | PUT 뮤테이션 옵션입니다. |
| `deleteProps` | `object` | `enabled: false` | DELETE 뮤테이션 옵션입니다. |
| `gcTime` | `number` | `30` | 캐시 GC 시간(초 단위, 내부에서 1000 곱)입니다. |
| `staleTime` | `number` | `30` | stale time(초 단위, 내부에서 1000 곱)입니다. |
| `refresh` | `RestQueryRefreshOptions` | `invalidate` | 뮤테이션 후 갱신 전략입니다. |
| `patch` | `RestQueryPatchHandlers` | 없음 | `refresh.strategy = 'patch'`일 때 캐시 수정 핸들러입니다. |

### 반환값 / 에러

| 이름 | 타입 | 설명 |
| --- | --- | --- |
| `data` | `ItemType \| null` | 최신 GET 데이터입니다. |
| `dataProps` | `{ isLoading; isFetching }` | GET 로딩 상태입니다. |
| `pageData` | `InfiniteData<ItemType[]> \| undefined` | 무한 쿼리 데이터입니다. |
| `pageDataProps` | `{ page; setPage; isLoading; isFetching }` | 페이지 상태 및 로딩 플래그입니다. |
| `onPost` / `onPut` / `onDelete` | `mutate` 함수 | POST/PUT/DELETE 요청 트리거입니다. |
| `onRefresh` | `() => void` | GET + 페이지 쿼리 무효화입니다. |
| `onClear` | `() => Promise<void>` | 캐시 제거 및 page 초기화입니다. |

에러는 `errorType`으로 정규화됩니다:
```ts
type errorType = {
  r_result_type: string
  r_result_msg: string
  r_result_id: string | number
}
```

## API Reference
전체 API 문서는 `docs/API.md`에 있습니다.

## TypeScript
- 타입은 `types: "dist/index.d.ts"`로 제공됩니다.
- 공개 타입은 모두 `src/types`에서 re-export 됩니다.
```ts
import type { errorType, ProviderType, routerPropsType } from '@mintwoo/restapi'
```

## Compatibility
- React: `18.3.1` (peer dependency)
- React DOM: `18.3.1` (peer dependency)
- React Native: `0.76.7` (peer dependency)
- Node 버전: Not found in repository / TBD
- ESM/CJS: 둘 다 지원 (`module` + `main` 필드)

## Bundling / Tree-shaking
- `sideEffects`: Not found in repository / TBD
- `exports` map: Not found in repository / TBD
- 빌드 출력: `dist/index.esm.js`, `dist/index.cjs.js` (`tsup.config.ts` 기준)

## Examples

### Basic: GET + 알림
```tsx
import { useRestQuery } from '@mintwoo/restapi'

const Users = () => {
  const { data } = useRestQuery('users', {
    notiTitle: 'User',
    notiShow: ['get', 'get_err'],
    getProps: { enabled: true }
  })

  return <pre>{JSON.stringify(data, null, 2)}</pre>
}
```

### Advanced: Patch 전략
```tsx
import { useRestQuery } from '@mintwoo/restapi'

const { onPost } = useRestQuery('users', {
  notiTitle: 'User',
  getProps: { enabled: true },
  postProps: { enabled: true },
  refresh: { strategy: 'patch' },
  patch: {
    onPost: (old, serverData) => {
      if (Array.isArray(old)) return [...old, serverData]
      return serverData
    }
  }
})

onPost({ name: 'Kim' })
```

### Real-world: 검색 조건 통합
```tsx
import { RaProvider, useRestSearchQuery } from '@mintwoo/restapi'

const Users = () => {
  const { searchData, setSearchData, searchOption } = useRestSearchQuery({
    routerName: 'users',
    routerProps: {
      notiTitle: 'User',
      getProps: { enabled: true }
    },
    baseSearchData: { search: false, keyword: '' },
    baseSearchOptions: [
      { key: 'base', title: 'Base', items: [{ type: 'text', key: 'keyword', title: 'Keyword' }] }
    ]
  })

  return (
    <div>
      <button onClick={() => setSearchData({ ...searchData, search: true })}>
        Search
      </button>
      <pre>{JSON.stringify(searchOption, null, 2)}</pre>
    </div>
  )
}

export default function App() {
  return (
    <RaProvider
      value={{
        api: ({ type, title, subTitle }) => console.log(type, title, subTitle)
      }}
    >
      <Users />
    </RaProvider>
  )
}
```

## Troubleshooting
- `useTopkeyState should be used within RaProvider`: `useRaState`가 `RaProvider` 밖에서 호출되었습니다.
- 쿼리가 실행되지 않음: `getProps.enabled` 또는 `getPageProps.enabled`가 기본 `false`입니다.
- `"not_post_props"`/`"not_put_props"`/`"not_delete_props"`: 해당 `*_Props.enabled`가 `false`입니다.
- `__disabled__` 키가 보임: `enabled=false`일 때 캐시 키 오염 방지를 위한 정상 동작입니다.
- ESM/CJS 충돌: `import { useRestQuery } from '@mintwoo/restapi'` 사용 및 번들러 설정을 확인하세요.
- 타입 인식 불가: `dist/index.d.ts`가 없을 수 있습니다. `yarn build`를 실행하세요.
- peer dependency 경고: `react`, `react-dom`, `react-native`, `@tanstack/react-query`, `axios`, `query-string` 버전을 맞추세요.

## FAQ
- Q: QueryClient가 포함되어 있나요?
  A: `RaProvider` 내부에 `QueryClientProvider`가 포함되어 있습니다.
- Q: Axios 인스턴스를 커스터마이즈할 수 있나요?
  A: `createApiInstance`로 내부 인스턴스를 구성합니다.
- Q: 알림을 끄려면?
  A: `notiShow`에서 해당 이벤트를 제거하거나 `RaProvider` 연동을 생략하세요.
- Q: 캐시 갱신을 바꾸려면?
  A: `refresh.strategy`에 `invalidate | patch | none`을 지정하세요.
- Q: 페이지네이션은 어떻게 동작하나요?
  A: `useInfiniteQuery` + 로컬 `page` 상태로 다음 페이지를 호출합니다.
- Q: exports map이 있나요?
  A: Not found in repository / TBD
- Q: changelog이 있나요?
  A: Not found in repository / TBD

## Contributing
로컬 개발:
```bash
yarn install
yarn build
```

테스트/린트:
- Not found in repository / TBD

릴리즈/배포:
- Not found in repository / TBD

## Security
- 실제 토큰/시크릿은 커밋하지 말고 환경변수로 관리하세요.
- 취약점 제보 방법은 레포에서 확인할 수 없습니다. 공개 이슈 대신 비공개 채널을 권장합니다.

## License
Not found in repository / TBD.

## Breaking Changes / Migration
No changelog found.

## Quick Commands

| 작업 | 명령 |
| --- | --- |
| Build | `yarn build` |
| Test | Not found in repository / TBD |
| Lint | Not found in repository / TBD |
| Typecheck | Not found in repository / TBD |
| Publish | Not found in repository / TBD |