기억의 실마리
2023. 4. 7. 17:28

OpenAPI

openAPI는 애플리케이션의 REST-API 문서를 자동으로 구성해주는 라이브러리이다.

이 라이브러리를 사용하게된다면 개발을 진행할때 backend에서 API를 구성할때

지정한 타입이나 데이터 변수를 따로 문서화하여 frontend개발자에게 전달할 필요가

없어지기 때문에 능률을 올려주고 backend, frontend개발자 모두에게 편의를

제공할 수 있는 라이브러리이다.

 

(* React, NestJS로 구성된 프로젝트를 기준으로 포스팅하였다.)

 

Swagger? or OpenAPI?

Swagger는 2010년대 초 Tam Wordnik가 개발해온 라이브러리이다.
시작은 Wordnik기업에서 자체 API용 UI로 개발되었고 2015년초에SmartBear라는 회사에서 Swagger를 인수했다. 이 후에 2015년 말SmartBear는 Linux Foundation의 후원으로 OpenAPI Initiative에 Swagger를기부하면서 OpenAPI Specification으로 이름이 변경되었다.

지금의 Swagger는 OpenAPI를 Implement하기 위한 도구를 뜻하며

명세된API를 공유하는 swagger-ui이며 web에서 공유하는 ui-tool이다.

 

결과적으로 라이브러리 자체는 openAPI라고 명칭하며 swagger는 tool을 명칭한다.

 

 

swagger & openAPI Install

// express를 사용하는 경우
npm install --save nest-openapi-tools @nestjs/swagger swagger-ui-express

// fastify를 사용하는 경우
npm install --save nest-openapi-tools @nestjs/swagger swagger-ui-fastify

단순 명세기능을 사용할땐 swagger설치만 해도 명세가 가능하지만 필자는

codegen에 대해서도 다루기 때문에 nest-openapi-tools 를 함께 install 해주어

편의성을 더했다.

 

 

사용예시

 

1. DTO와 Controller 명세하기

// DTO or Entity
export class Dto {
  @ApiProperty({ type: Number }) // default타입(string)이 아니므로 타입지정
  id: number;

  @ApiProperty() // default타입 = string
  email: string;

  @ApiProperty({ required: false })
  password?: string;  // chaning = 필수요소x

  @ApiProperty()
  name: string;

  @ApiProperty()
  mobile: string;
}

// Controller
export class Controller {
  @ApiResponse({ type: CoreOutput }) // return 타입을 지정
  @Post('register')
  createAccount(@Body() input: CreateAccountDto): Promise<CoreOutput> {
    return this.userService.createAccount(input);
  }

  /** 유저데이터 수정 */
  @ApiResponse({ type: CoreOutput }) // return 타입을 지정
  @Patch('modify')
  @UseGuards(JwtAuthGuard)
  profileUpdate(
    @Req() req,
    @Body() updateData: UpdateAccountDto,
  ): Promise<CoreOutput> {
    return this.userService.profileUpdate(req.user, updateData);
  }
}

단순하게 데코레이터를 넣어줌으로서 명세가 가능하다.

 

 

2.  Front에 API명세파일 보내기

main.ts에 적용해도 되지만 main.ts에서 설정해야하는 것들이 많아지고

복잡해질 수 있기 때문에 openApi.ts를 만들어서 main.ts에 import시켜서 사용했다.

 

  • openApi.ts
import { OpenApiNestFactory } from 'nest-openapi-tools';
import { DocumentBuilder } from '@nestjs/swagger';

export const useOpenApi = (app) => {
  return OpenApiNestFactory.configure(
    app,
    new DocumentBuilder()
      .setTitle('My API')
      .setDescription('An API to do awesome things')
      .addBearerAuth(),
    {
      // swagger-ui 설정 (web-ui)
      webServerOptions: {
        enabled: process.env.NODE_ENV !== 'production',
        path: 'api-docs',
      },

      // 자동생성된 api문서 경로 및 설정
      fileGeneratorOptions: {
        enabled: process.env.NODE_ENV !== 'production',
        outputFilePath: './openapi.yaml', // or ./openapi.json
      },

      // 서버에 저장된 api문서를 프론트로 보내주는 설정
      clientGeneratorOptions: {
        enabled: process.env.NODE_ENV !== 'production',
        type: 'typescript-axios', //typescript-axios
        outputFolderPath: '../frontend/src/openapi',
        additionalProperties:
          'apiPackage=apis,modelPackage=models,withoutPrefixEnums=true,withSeparateModelsAndApi=true',
        openApiFilePath: './openapi.yaml', // or ./openapi.json
        skipValidation: true, // optional, false by default
      },
    },
    {
      // 명세함수의 기본값을 설정해준다.
      operationIdFactory: (c: string, method: string) => method,
    },
  );
};

 

  • main.ts
function bootstrap() {
  (async () => {
    try {
      const app = await NestFactory.create(AppModule);

      await useOpenApi(app);
      
      // ...
}
bootstrap();

 

사용팁

서버를 돌리고 있을때 위의 설정들이 제대로 갖춰질 경우 해당 경로에

openapi.yaml 의 API명세파일이 생길 것이고 서버가 수정될 때마다

openapi.yaml를 최신화 시킨다. 그렇기 때문에 계속해서 최신화때문에

서버로딩이 길어지게 되니 개발중엔 enabled 설정을 'production'일때로 바꿔주고

최신화시켜주고 싶을때 다시 설정을 'production'가 아닐때로 바꿔주면 된다.

 

 

3.  Front에서 서버의 API명세파일 가져오기

Front에서는 package.json에서 script설정을 통해 npm 명령어를 사용하여

명세파일을 가져오거나 최신화 시켜 줄 수 있다.

이를 위해서는 Front에 openapi-generator-cli 를 install해야한다.

 

  • openapi-generator-cli Install
// 패키지가 많은경우 충돌방지목적으로 -D 옵션을 사용하면 좋다.
npm install @openapitools/openapi-generator-cli -D

 

  • package.json
{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "codegen": "npx @openapitools/openapi-generator-cli generate -i ../backend/openapi.yaml -g typescript-axios --additional-properties apiPackage=apis,modelPackage=models,withoutPrefixEnums=true,withSeparateModelsAndApi=true -o ./src/openapi"
  },
}

 

codegen script의 설명

  • "npx @openapitools/openapi-generator-cli"는 OpenAPI Generator CLI를 실행하기 위한 명령어
  • generate는 생성 명령을 나타내는 옵션
  • -i ../backend/openapi.yaml는 가져오는 API명세파일의 위치와 이름
  • -g typescript-axios는 TypeScript Axios Front에서 통신할 함수를 생성하기 위한 Generator 모듈을 지정
  • --additional-properties apiPackage=apis,
    modelPackage=models,
    withoutPrefixEnums=true,
    withSeparateModelsAndApi=true
    코드 생성에 사용되는 추가 속성 설정이다. 이 예제에서는 생성된 코드의 패키지 이름을 지정하고, Enum의 접두사를 제거한 후, 모델 및 API 코드를 분리하는 옵션이다.
  • -o ./src/openapi"는 생성된 파일의 위치를 지정하고 이 예제에서는 src/openapi 폴더에 생성된 파일을 저장한다.

 

명령어로 가져오기

// 터미널에 입력
npm run codegen

 Thanks for using OpenAPI Generator. 

문구가 뜨면 코드젠이 완료된 상태이다.

 

마치며...

작성일자에 진행중인 개인프로젝트에서 openAPI-codegen을 처음 사용해보았는데 typeORM을 사용했을때 만큼의 신선한 충격이었다. codegen은 효율을 혁신적으로 올려주는 라이브러리임을 확실하게 깨달았다. 실무에 들어가게 됐을때 openAPI-codegen과 swagger를 사용하지 않는 배경이라면 API명세문서의 간편화를 주장하며 이를 채용하자고 적극적으로 행동해야겠다는 생각이 들었다.

'Backend > Nest.js' 카테고리의 다른 글

[ Nest.js ] Node.js기반의 API 프레임워크  (0) 2023.01.24