
Security News
/Research
Fake Corepack Site Distributes Infostealer and Proxyware to Developers
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.
swagger-client-autogen
Advanced tools
Swagger/OpenAPI에서 TypeScript API 클라이언트 코드를 자동 생성하는 CLI 도구
🎯 한 번의 명령어로 완전한 TypeScript API 클라이언트를 생성하세요!
init 명령어로 빠른 설정# 프로젝트에 개발 의존성으로 설치 (권장)
npm install -D swagger-client-autogen
# 또는 yarn
yarn add -D swagger-client-autogen
[!TIP]
💡 개발 의존성 설치를 권장하는 이유:
🎯 타입 지원: 설정 파일 작성 시InputCodegenConfig타입 힌트 및 자동완성
📋 package.json 스크립트 활용 (선택사항):
{
"scripts": {
"api:init": "swagger-client-autogen init",
"api:fetch": "swagger-client-autogen fetch --config swagger/config.ts --output swagger/api.yml",
"api:generate": "swagger-client-autogen generate --config swagger/config.ts"
}
}
그러면 npm run api:generate로 간편하게 실행할 수 있습니다.
🎯 인터랙티브 설정으로 빠른 시작!
# 1. 프로젝트 루트에서 초기화 실행
npx swagger-client-autogen init
대화형 질문에 답변하세요:
🚀 swagger-client-autogen 초기화
💡 지원하는 입력 형식
│ 로컬 파일: ./swagger.yml, api/swagger.json
│ 원격 URL: https://api.example.com/swagger.json
│ 개발 서버: http://localhost:3000/api-docs
📋 Swagger JSON/YAML 경로: https://api.example.com/swagger.json
🔒 인증이 필요한 API인가요? No
📝 Zod 스키마를 생성할까요? Yes
📂 Config 파일명: swagger/config.ts
# 2. Swagger 파일 다운로드 및 병합
npx swagger-client-autogen fetch --config swagger/config.ts --output swagger/api.yml
# 3. API 클라이언트 코드 생성
npx swagger-client-autogen generate --config swagger/config.ts
src/
├── shared/api/ # 공통 API 파일들
│ ├── dto.ts # TypeScript 타입 정의
│ ├── schema.gen.ts # Zod 스키마 (선택)
│ ├── utils.gen.ts # API 유틸리티
│ ├── stream.gen.ts # 스트림 유틸리티
│ └── type-guards.gen.ts # 타입 가드
└── entities/{moduleName}/api/ # 모듈별 API 파일들
├── index.ts # API 클라이언트 클래스
├── instance.ts # API 클라이언트 인스턴스
├── queries.ts # TanStack Query hooks
└── mutations.ts # TanStack Query mutations
✨ 바로 사용 가능한 코드가 생성됩니다!
import { useGetUsersQuery, usePostUsersMutation } from '@/entities/users/api';
// GET 요청 - Query Hook
const { data: users, isLoading } = useGetUsersQuery();
// POST 요청 - Mutation Hook
const createUserMutation = usePostUsersMutation({
onSuccess: (data) => {
console.log('사용자 생성 성공:', data);
}
});
// 뮤테이션 실행
createUserMutation.mutate({
payload: { name: 'John', email: 'john@example.com' },
});
init - 초기화npx swagger-client-autogen init
인터랙티브 방식으로 설정 파일을 생성합니다. 이곳에서 생성된 설정 파일은 fetch, generate 명령에서 사용됩니다.
fetch - Swagger 파일 다운로드npx swagger-client-autogen fetch --config swagger/config.ts --output swagger/api.yml
Config 파일에서 지정된 웹 URL로부터 Swagger 파일을 다운로드하고 병합합니다.
옵션:
--config, -c: 설정 파일 경로 (필수)--output, -o: 출력 파일 경로 (선택, 기본값: swagger/{title}.yml)generate - 코드 생성npx swagger-client-autogen generate --config swagger/config.ts
API 클라이언트 코드를 생성합니다.
npx swagger-client-autogen --help
npx swagger-client-autogen init --help
init 명령어로 생성되는 설정 파일 예시:
// swagger/config.ts
import type { InputCodegenConfig } from 'swagger-client-autogen';
const config: InputCodegenConfig = {
// Swagger 설정
uri: 'https://api.example.com/swagger.json',
// 인증 정보 (선택)
username: 'your-username',
password: 'your-password',
// 스키마 생성 여부
createSchema: true,
// 출력 설정 (필요에 따라 주석 해제하여 사용)
/*
customOutput: {
aliasInfo: {
aliasMap: { '@': 'src' }, // path alias 설정
aliasMapDepth: 2, // alias 탐색 깊이
},
pathInfo: {
dto: 'src/shared/api/dto.ts',
api: 'src/entities/{moduleName}/api/index.ts',
apiInstance: 'src/entities/{moduleName}/api/instance.ts',
queries: 'src/entities/{moduleName}/api/queries.ts',
mutations: 'src/entities/{moduleName}/api/mutations.ts',
schema: 'src/shared/api/schema.gen.ts',
apiUtils: 'src/shared/api/utils.gen.ts',
streamUtils: 'src/shared/api/stream.gen.ts',
typeGuards: 'src/shared/api/type-guards.gen.ts',
streamHandlers: 'src/entities/{moduleName}/api/stream-handlers',
},
},
*/
};
export default config;
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
uri | string | - | Swagger JSON/YAML 파일 경로 또는 URL |
createSchema | boolean | false | Zod 스키마 생성 여부 |
swagger에 인증 정보가 필요한 경우에만 입력해주세요.
{
// 최상위 레벨에 설정
username: 'your-username',
password: 'your-password'
}
{
customOutput: {
aliasInfo: {
aliasMap: { '@': 'src' }, // path alias 설정
aliasMapDepth: 2 // alias 탐색 깊이
},
pathInfo: {
dto: 'src/shared/api/dto.ts',
api: 'src/entities/{moduleName}/api/index.ts',
apiInstance: 'src/entities/{moduleName}/api/instance.ts',
queries: 'src/entities/{moduleName}/api/queries.ts',
mutations: 'src/entities/{moduleName}/api/mutations.ts',
schema: 'src/shared/api/schema.gen.ts',
// ... 기타 경로 설정
}
}
}
💡 개선된 점:
pathInfo에서 alias 필드 제거 - 중복 제거!aliasMap을 기반으로 alias 자동 계산Swagger 스펙에 x- 프로퍼티를 추가하여 코드 생성을 세밀하게 제어할 수 있습니다.
x-ignore - 엔드포인트 무시특정 엔드포인트의 코드 생성을 건너뛸 수 있습니다.
paths:
/health:
x-ignore: true # 이 경로의 모든 메서드 무시
get:
summary: Health Check
# ... (코드 생성되지 않음)
/users:
get:
x-ignore: true # GET /users만 무시
# ...
post:
# POST /users는 정상적으로 생성됨
# ...
x-staleTime - TanStack Query staleTime 설정Query의 staleTime을 엔드포인트별로 설정할 수 있습니다.
paths:
/users:
get:
x-staleTime: '5m' # 5분
summary: Get Users
# ...
/config:
get:
x-staleTime: 'Infinity' # 무한대 (수동 무효화 전까지 fresh 유지)
summary: Get Config
# ...
/static-data:
get:
x-staleTime: 'static' # 절대 stale로 간주되지 않음 (함수로 사용 시 항상 0 반환)
summary: Get Static Data
# ...
지원 형식:
숫자: 밀리초 단위 (예: 300000)시간 단위: '5h', '30m', '45s', '1h30m45s''Infinity': 무한대 (수동 무효화 전까지 fresh 유지)'static': 절대 stale로 간주되지 않음 (함수로 사용 시 항상 0 반환)생성되는 코드:
const queries = {
getUsers: ({ kyInstance, options }) => queryOptions({
queryKey: USERS_QUERY_KEY.GET_USERS(),
queryFn: () => usersApi.getUsers({ kyInstance, options }),
staleTime: 5 * 60 * 1000 // 5분
}),
};
x-gcTime - TanStack Query gcTime 설정Query의 gcTime (가비지 컬렉션 시간)을 엔드포인트별로 설정할 수 있습니다.
paths:
/users:
get:
x-gcTime: '10m' # 10분
summary: Get Users
# ...
/permanent-cache:
get:
x-gcTime: 'Infinity' # 가비지 컬렉션 비활성화
summary: Get Permanent Data
# ...
지원 형식:
숫자: 밀리초 단위시간 단위: '5h', '30m', '45s', '1h30m45s''Infinity': 가비지 컬렉션 비활성화생성되는 코드:
const queries = {
getUsers: ({ kyInstance, options }) => queryOptions({
queryKey: USERS_QUERY_KEY.GET_USERS(),
queryFn: () => usersApi.getUsers({ kyInstance, options }),
gcTime: 10 * 60 * 1000 // 10분
}),
};
fetch 명령어를 실행할 때 기존 파일의 x- 프로퍼티가 자동으로 유지됩니다.
npx swagger-client-autogen fetch --config swagger/config.ts
유지된 x- 프로퍼티:
┌─────────┬──────────────┬──────────┬─────────────────────────────┐
│ (index) │ 엔드포인트 │ 메서드 │ x- 프로퍼티 │
├─────────┼──────────────┼──────────┼─────────────────────────────┤
│ 0 │ '/health' │ '-' │ 'x-ignore' │
│ 1 │ '/users' │ 'GET' │ 'x-staleTime, x-gcTime' │
└─────────┴──────────────┴──────────┴─────────────────────────────┘
// src/entities/user/api/index.ts
import type { KyInstance, Options } from 'ky';
import { z } from 'zod';
import type { GetUserResponseDto, CreateUserRequestDto, CreateUserResponseDto } from '@/shared/api/dto';
import { getUserResponseDtoSchema, createUserRequestDtoSchema, createUserResponseDtoSchema } from '@/shared/api/schema.gen';
import { validateSchema } from '@/shared/api/utils.gen';
export class UserApi {
private readonly instance: KyInstance;
constructor(instance: KyInstance) {
this.instance = instance;
}
/**
* @tags users
* @summary Get User
* @request GET:/users/{id}
*/
async getUser({
id,
kyInstance,
options,
}: TUserApiRequestParameters['getUser']) {
const instance = kyInstance ?? this.instance;
const response = await instance
.get<GetUserResponseDto>(`users/${id}`, {
...options,
})
.json();
const validateResponse = validateSchema(getUserResponseDtoSchema, response);
return validateResponse;
}
/**
* @tags users
* @summary Create User
* @request POST:/users
*/
async createUser({
payload,
kyInstance,
options,
}: TUserApiRequestParameters['createUser']) {
const instance = kyInstance ?? this.instance;
const validatedPayload = validateSchema(createUserRequestDtoSchema, payload);
const response = await instance
.post<CreateUserResponseDto>(`users`, {
json: validatedPayload,
...options,
})
.json();
const validateResponse = validateSchema(createUserResponseDtoSchema, response);
return validateResponse;
}
}
export type TUserApiRequestParameters = {
getUser: {
id: number;
kyInstance?: KyInstance;
options?: Options;
};
createUser: {
payload: CreateUserRequestDto;
kyInstance?: KyInstance;
options?: Options;
};
};
// src/entities/user/api/instance.ts
import { UserApi } from './index';
// API 클래스의 인스턴스를 생성하여 내보냄
export const userApi = new UserApi();
// src/shared/api/dto.ts
export type GetUserResponseDto = {
id: number;
name: string;
email: string;
createdAt: string;
}
export type CreateUserRequestDto = {
name: string;
email: string;
}
// src/shared/api/schema.gen.ts
import { z } from 'zod';
export const GetUserResponseSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
createdAt: z.string()
});
export const CreateUserRequestSchema = z.object({
name: z.string().min(1),
email: z.string().email()
});
📋 queries.ts - 쿼리 훅
// src/entities/users/api/queries.ts
import type { DefaultError, UseQueryOptions } from '@tanstack/react-query';
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
import type { UserResponseDto, UnknownConceptReadResponseDto } from '@/shared/api/dto';
import type { TUsersApiRequestParameters } from './index';
import { usersApi } from './instance';
// Query Keys
export const USERS_QUERY_KEY = {
GET_USERS: () => ['users'],
GET_USERS_USERID: (userId: string) => ['users', userId],
GET_USERS_USERID_UNKNOWN_CONCEPTS: (userId: string, params?: any) =>
['users', userId, 'unknown_concepts', params],
};
// Query 객체 (재사용 가능)
const queries = {
getUsers: ({ kyInstance, options }: TUsersApiRequestParameters['getUsers']) => ({
queryKey: USERS_QUERY_KEY.GET_USERS(),
queryFn: () => usersApi.getUsers({ kyInstance, options }),
}),
getUsersByUserId: ({ userId, kyInstance, options }: TUsersApiRequestParameters['getUsersByUserId']) => ({
queryKey: USERS_QUERY_KEY.GET_USERS_USERID(userId),
queryFn: () => usersApi.getUsersByUserId({ userId, kyInstance, options }),
}),
};
export { queries as usersQueries };
// Query Hooks
export const useGetUsersQuery = <TData = UserResponseDto[]>(
requestArgs: TUsersApiRequestParameters['getUsers'],
options?: Omit<UseQueryOptions<UserResponseDto[], DefaultError, TData>, 'queryKey' | 'queryFn'>,
) => {
return useQuery({
...queries.getUsers(requestArgs),
...options,
});
};
// Suspense Query Hooks
export const useGetUsersSuspenseQuery = <TData = UserResponseDto[]>(
requestArgs: TUsersApiRequestParameters['getUsers'],
options?: Omit<UseQueryOptions<UserResponseDto[], DefaultError, TData>, 'queryKey' | 'queryFn'>,
) => {
return useSuspenseQuery({
...queries.getUsers(requestArgs),
...options,
});
};
🔄 mutations.ts - 뮤테이션 훅
// src/entities/users/api/mutations.ts
import type { DefaultError, UseMutationOptions } from '@tanstack/react-query';
import { useMutation } from '@tanstack/react-query';
import type { UserResponseDto } from '@/shared/api/dto';
import type { TUsersApiRequestParameters } from './index';
import { usersApi } from './instance';
// Mutation Keys
export const USERS_MUTATION_KEY = {
POST_USERS: ['users'] as const,
DELETE_USERS_USERID: ['users', 'userId'] as const,
};
// Mutation 객체 (재사용 가능)
const mutations = {
postUsers: () => ({
mutationFn: ({ payload, kyInstance, options }: TUsersApiRequestParameters['postUsers']) => {
return usersApi.postUsers({ payload, kyInstance, options });
},
mutationKey: USERS_MUTATION_KEY.POST_USERS,
meta: {
mutationFnName: 'postUsers',
}
}),
};
export { mutations as usersMutations };
// Mutation Hooks
export const usePostUsersMutation = <TContext = unknown>(
options?: Omit<
UseMutationOptions<UserResponseDto, DefaultError, TUsersApiRequestParameters['postUsers'], TContext>,
'mutationFn' | 'mutationKey'
>,
) => {
return useMutation({
...mutations.postUsers(),
...options,
});
};
swagger-client-autogen은 TanStack Query의 mutation 성공 시 전역적으로 쿼리를 무효화하거나 특정 로직을 실행할 수 있는 Global Mutation Effect 시스템을 제공합니다.
generate 명령어를 실행하면 global-mutation-effect.type.ts 파일이 자동으로 생성됩니다:
// src/shared/api/global-mutation-effect.type.ts
export type GlobalMutationEffectMap<M extends MutationMap> = Partial<{
[K in keyof M]: {
onSuccess: {
invalidate: (
data: ExtractMutationData<M, K>,
variables: ExtractMutationVariables<M, K>,
context: unknown,
mutation: Mutation<...>,
) => void;
};
};
}>;
// 각 모듈별 타입
export type TUsersGlobalMutationEffects = GlobalMutationEffectMap<typeof usersMutations>;
export type TChatsGlobalMutationEffects = GlobalMutationEffectMap<typeof chatsMutations>;
// ...
// 통합 팩토리 타입
export type TGlobalMutationEffectFactory = (
queryClient: QueryClient,
) => Partial<
TUsersGlobalMutationEffects &
TChatsGlobalMutationEffects &
// ...
>;
1. 전역 Mutation Effects 구현
// src/shared/api/global-mutation-effects.ts
import type { QueryClient } from '@tanstack/react-query';
import { queryClient } from '@/app/provider/tanstack-query';
import { usersQueries } from '@/entities/users/api/queries';
import type {
TUsersGlobalMutationEffects,
TGlobalMutationEffectFactory,
} from './global-mutation-effect.type';
export const globalMutationEffects: TGlobalMutationEffectFactory = (queryClient) => ({
...userGlobalMutationEffects(queryClient),
// 다른 모듈의 effects도 여기에 추가
});
export const isGlobalMutationEffectKey = (
key: unknown
): key is keyof ReturnType<typeof globalMutationEffects> => {
return typeof key === 'string' &&
Object.keys(globalMutationEffects(queryClient)).includes(key);
};
function userGlobalMutationEffects(
queryClient: QueryClient
): TUsersGlobalMutationEffects {
return {
// mutation 함수명을 키로 사용
postUsers: {
onSuccess: {
invalidate: (_data, variables) => {
// 관련 쿼리 무효화
queryClient.invalidateQueries({
queryKey: usersQueries.getUsers({}).queryKey,
exact: true,
});
},
},
},
};
}
2. TanStack Query Provider 설정
// src/app/provider/tanstack-query.tsx
import { MutationCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { globalMutationEffects, isGlobalMutationEffectKey } from '@/shared/api/global-mutation-effects';
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: (failureCount, error) => {
return failureCount < 2;
},
},
},
mutationCache: new MutationCache({
onSuccess: async (_data, _variables, _context, mutation) => {
const disableGlobalInvalidation = mutation.options.meta?.disableGlobalInvalidation;
const mutationFnName = mutation.options.meta?.mutationFnName;
// 전역 무효화 비활성화 체크
if (disableGlobalInvalidation) {
return;
}
// 전역 mutation effect 실행
if (isGlobalMutationEffectKey(mutationFnName)) {
const invalidate = globalMutationEffects(queryClient)[mutationFnName]?.onSuccess.invalidate;
if (invalidate) {
invalidate(_data as never, _variables as never, _context as never, mutation as never);
return; // 전역 효과를 실행했으면 entity 단위 무효화는 하지 않음
}
}
// entity 단위 기본 무효화 (전역 효과가 없는 경우)
const mutationKey = mutation.options.mutationKey;
if (!mutationKey) return;
await queryClient.invalidateQueries({
queryKey: [mutationKey?.at(0)],
exact: false,
});
},
}),
});
export const TanstackQueryProvider = ({ children }: PropsWithChildren) => {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
};
3. 전역 무효화 비활성화 (선택적)
특정 mutation 호출 시 전역 무효화를 비활성화하려면:
const mutation = usePostUsersMutation({
meta: {
disableGlobalInvalidation: true, // 전역 무효화 비활성화
},
onSuccess: (data) => {
// 커스텀 로직만 실행
},
});
전역 Mutation Effects 시스템에 대한 자세한 설명은 다음 문서를 참고하세요:
이 가이드에서는 다음 내용을 다룹니다:
swagger-client-autogen/
├── scripts/ # CLI 스크립트
│ ├── cli.ts # 메인 CLI
│ ├── init.ts # 초기화 스크립트
│ ├── fetch-swagger.js
│ └── generate-all.js
├── templates/ # 코드 생성 템플릿
├── config-builders/ # 설정 빌더
├── utils/ # 유틸리티 함수
└── types/ # 타입 정의
# 개발 환경 설정
git clone https://github.com/your-org/swagger-client-autogen
cd swagger-client-autogen
yarn install
# 빌드
yarn build
# 개발 모드 (watch)
yarn build:watch
git checkout -b feature/amazing-featuregit commit -m 'Add amazing feature'git push origin feature/amazing-featureA: init 명령어 실행 시 인증 정보를 입력하거나, 설정 파일에 직접 추가하세요.
{
username: 'your-username',
password: 'your-password'
}
A: 현재는 템플릿 커스터마이징을 지원하지 않습니다. 생성된 코드를 직접 수정하거나, 래퍼 함수를 만들어 사용하세요.
A: TypeScript만 지원합니다.
Error: Failed to fetch swagger file
해결 방법:
username, password 설정 확인Type 'unknown' is not assignable to type 'UserDto'
해결 방법:
🚀 Happy Coding!
이 도구가 도움이 되었다면 ⭐ 별표를 눌러주세요!
FAQs
Swagger/OpenAPI에서 TypeScript API 클라이언트 코드를 자동 생성하는 CLI 도구
We found that swagger-client-autogen demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.

Research
/Security News
A large-scale campaign abused GitHub Actions in compromised repositories to exploit CVE-2026-41940 in cPanel and WHM and steal server credentials.

Security News
Five frontier LLMs generated the same nonexistent package names, leaving 53 available for potential slopsquatting across PyPI and npm.