๐Ÿ”Œ
๊ฐœ๋ฐœโ€ขDevOps/๋„๊ตฌ

openapi code generator ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

2024.09.02

FEConf 2024๋ฅผ ๋‹ค๋…€์™€ ๋ฐ”ํ€ด ๋Œ€์‹  ๋กœ์ผ“ ๋งŒ๋“ค๊ธฐ ๋ฐœํ‘œ๋ฅผ ๋“ฃ๊ณ  openapi code generator๋ฅผ ํ•™์Šตํ•ด๋ณด๊ณ  ์‹ค๋ฌด์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ์œ„ํ•ด ํ•™์Šต์„ ํ•˜๋Š” ๊ณผ์ •์„ ๊ธฐ๋กํ•œ๋‹ค.

ํ•™์Šตํ•ด๋ณด๊ณ  ์ ์šฉํ•ด๋ณด๊ณ  ์‹ถ์€ ์ฃผ์ œ๋Š” 14๋ถ„ 30์ดˆ ์ •๋„๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ์„œ๋ฒ„ API ์ฃผ์ œ ๋ฐœํ‘œ์ธ๋ฐ, ์ผ๋ฐ˜์ ์ธ api ์—ฐ๋™ ๊ณผ์ •์ธ ์ŠคํŽ™๋ฌธ์„œ ํ™•์ธ -> ์ฝ”๋“œ ์ด๊ด€ -> data fetcher ์ž‘์„ฑ -> ์ฝ”๋“œ ์ˆ˜์ • ์˜ ๊ณผ์ •์„ ํšจ์œจํ™” ํ•˜๋Š” ๋‚ด์šฉ์ด์˜€๋‹ค.

OpenAPI Generator๋กœ API์˜ ์•ˆ์ „ํ•œ Model๊ณผ ์ •ํ˜•ํ™”๋œ ๊ตฌํ˜„์ฝ”๋“œ ์ž๋™์ƒ์„ฑํ•˜๊ธฐ ๋ธ”๋กœ๊ทธ ๊ธ€์„ ์ฐธ๊ณ ํ–ˆ๋‹ค.

openapi-generator ์„ค์น˜

์šฐ์„  openapi-generator๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด openapi-generator๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•œ๋‹ค. ๋‚˜๋Š” macos๋ฅผ ์‚ฌ์šฉ์ค‘์ด์—ฌ์„œ ๊ณต์‹๋ฌธ์„œ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ homebrew๋ฅผ ํ†ตํ•ด ์„ค์น˜ํ–ˆ๋‹ค.

์„ค์น˜ ํ›„ ํ„ฐ๋ฏธ๋„์— openapi-generator๋ฅผ ์ž…๋ ฅํ•ด๋ดค๋‹ค.

The most commonly used openapi-generator-cli commands are:
    author        Utilities for authoring generators or customizing templates.
    batch         Generate code in batch via external configs.
    config-help   Config help for chosen lang
    generate      Generate code with the specified generator.
    help          Display help information about openapi-generator
    list          Lists the available generators
    meta          MetaGenerator. Generator for creating a new template set and configuration for Codegen.  The output will be based on the language you specify, and includes default templates to include.
    validate      Validate specification
    version       Show version information used in tooling

See 'openapi-generator-cli help <command>' for more information on a specific

๋‹ค์Œ์œผ๋กœ ์œ„ ๋„์›€๋ง ์ค‘ ๋‚˜๋Š” ์ƒ์„ฑ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•ด์„œ openapi-generator help generate ๋ฅผ ์ž…๋ ฅํ•ด๋ดค๋‹ค.

OPTIONS
        ...
        -c <configuration file>, --config <configuration file>
            Path to configuration file. It can be JSON or YAML. If file is JSON,
            the content should have the format {"optionKey":"optionValue",
            "optionKey1":"optionValue1"...}. If file is YAML, the content should
            have the format optionKey: optionValue. Supported options can be
            different for each language. Run config-help -g {generator name}
            command for language-specific config options.


        -e <templating engine>, --engine <templating engine>
            templating engine: "mustache" (default) or "handlebars" (beta)

        -g <generator name>, --generator-name <generator name>
            generator to use (see list command for list)

        -i <spec file>, --input-spec <spec file>
            location of the OpenAPI spec, as URL or file (required if not loaded
            via config using -c)

        -o <output directory>, --output <output directory>
            where to write the generated files (current dir by default)
        ...

๋งŽ์€ ์˜ต์…˜์ด ๋‚˜์™”๋Š”๋ฐ, ๊ทธ ์ค‘์—์„œ ๋ช‡ ๊ฐœ๋งŒ ์ถ”๋ ค๋ดค๋‹ค.

์šฐ์„ ์€ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด config ์„ค์ • ์—†์ด ์ตœ์†Œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋‚˜๋Š” generator๋กœ typescript-fetch๋ฅผ, input์œผ๋กœ๋Š” swagger ์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

swagger api์—์„œ ์ œ๊ณตํ•˜๋Š” json, yaml ํŒŒ์ผ๊ฒฝ๋กœ๋ฅผ i ์˜ต์…˜์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

swagger์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์ œ api์™€ json๊ฒฝ๋กœ png

๋‚˜๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์—…ํ•˜๊ธฐ ์œ„ํ•ด script๋กœ ๋“ฑ๋กํ–ˆ๋‹ค.

// package.json

 "scripts": {
    "generate": "openapi-generator generate -g typescript-fetch -i https://petstore3.swagger.io/api/v3/openapi.json"
  },

// command line
pnpm generate

์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋‹ˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋””๋ ‰ํ† ๋ฆฌ์™€ ํŒŒ์ผ์ด ์ƒ์„ฑ๋๋‹ค.

openapi-generator-์‹คํ–‰-ํ›„-๋””๋ ‰ํ† ๋ฆฌ

orval

์‹ค๋ฌด์—์„œ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ๋ฆฌ์„œ์น˜๋ฅผ ํ–ˆ๋‹ค. ํ˜„์žฌ ์‹ค๋ฌด์—์„  httpClient๋กœ๋Š” fetch, ์ƒํƒœ๊ด€๋ฆฌ๋Š” react-query ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” zod๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์‚ฌ์šฉ์ค‘์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ†ตํ•ฉ์ด ๊ฐ€๋Šฅํ•ด์•ผํ•˜๋Š” ์กฐ๊ฑด์ด ์žˆ์—ˆ๋‹ค.

์—ฌ๋Ÿฌ openapi generator ์ค‘์—์„œ ์กฐ๊ฑด์— ์ ํ•ฉํ•œ generator๋กœ Orval์„ ์ฑ„ํƒํ–ˆ๋‹ค.

์šฐ์„  orval๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„ค์น˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค

pnpm add orval -D

petstore ์˜ˆ์ œ๋ฅผ ๋”ฐ๋ผ config๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ถ€๋ถ„์—” ํฐ ์–ด๋ ค์›€์€ ์—†์—ˆ๋‹ค. orval.config.ts๋ฅผ ์ƒ์„ฑํ•˜๊ณ  config๋ฅผ ์ž‘์„ฑํ•œ ๋‹ค์Œ pnpm orval ์„ ํ•ด์ฃผ๋ฉด ๋๋‚œ๋‹ค.

๋‚ด๊ฐ€ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ํ™˜๊ฒฝ์— ๋งž๋„๋ก client, httpClient, zod ์„ค์ •์„ ์ž‘์„ฑํ–ˆ๋‹ค.

์ž์„ธํ•œ config๋Š” ๊ณต์‹๋ฌธ์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

import { defineConfig } from 'orval';

export default defineConfig({
  petstore: {
    output: {
      mode: 'tags-split', // ํŒŒ์ผ ์ƒ์„ฑ๋ฐฉ๋ฒ• // ๋‹จ์ผ๋กœ ๋งŒ๋“ค๊ฑด์ง€ ๋ถ„๊ธฐํ• ๊ฑด์ง€ ๋“ฑ
      target: 'src/petstore.ts', // ํŒŒ์ผ ์ƒ์„ฑ์œ„์น˜
      schemas: 'src/model', // ๋ชจ๋ธ ์ƒ์„ฑ์œ„์น˜
      mock: true, // mocks ์ƒ์„ฑ ์—ฌ๋ถ€ (๊ธฐ๋ณธ generator๋Š” MSW)
      // baseUrl: "/api/v2",
      baseUrl: 'https://petstore3.swagger.io/api/v3',
      client: 'react-query', // ํด๋ผ์ด์–ธํŠธ
      httpClient: 'fetch', // http ํด๋ผ์ด์–ธํŠธ
      override: {
        query: {
          useQuery: true,
          useInfinite: true,
          useInfiniteQueryParam: 'nextId',
          options: {
            staleTime: 60_000,
          },
        },
      },
    },
    input: {
      target: 'https://petstore3.swagger.io/api/v3/openapi.json',
    },
  },
  petstoreZod: {
    output: {
      mode: 'tags-split',
      client: 'zod',
      target: 'src/gen/endpoints',
      fileExtension: '.zod.ts',
    },
    input: {
      target: 'https://petstore3.swagger.io/api/v3/openapi.json',
    },
  },
});

์•„๋ž˜ ์ด๋ฏธ์ง€์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑ๋๋‹ค.

orval ์‹คํ–‰ ๊ฒฐ๊ณผ

ํ›„๊ธฐ

๋Œ€๋žต์ ์ธ ๋ฐฉ๋ฒ•์€ ์•Œ๊ฒŒ๋๋‹ค. ํ…Œ์ŠคํŠธ ํ•ด๋ณธ ๊ฒƒ ์ฒ˜๋Ÿผ ํ™˜๊ฒฝ๋งŒ ๊ฐ–์ถฐ์ง€๊ณ  ์ปจ๋ฒค์…˜๋งŒ ์ •ํ•ด๋‘๋ฉด ํšจ์œจ์ ์ธ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•  ๊ฒƒ ๊ฐ™๋‹ค. ์ด์ œ ํšŒ์‚ฌ์—์„œ ๋™๋ฃŒ ๊ฐœ๋ฐœ์ž๋ถ„๋“ค๊ณผ ์ปจ์„ผ์„œ์Šค๋ฅผ ๋งž์ถ”๊ณ  ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ์ปค์Šคํ…€์„ ํ•ด๋ด์•ผ ํ•œ๋‹ค.

orval๊นŒ์ง€ ์‚ฌ์šฉํ•˜๊ณ  ๋‚˜๋‹ˆ orval config ์„ค์ • ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋” ๊นŠ๊ฒŒ ํ•™์Šตํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์•˜๊ณ , pet store ์˜ˆ์ œ์ฒ˜๋Ÿผ ์ž‘์„ฑ๋˜์–ด์žˆ์ง€ ์•Š์€ ์‹ค๋ฌด์ฝ”๋“œ์— ์ ์šฉํ•˜๋ ค๋ฉด ๋™๋ฃŒ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ swagger json ๊ด€๋ จ ์ปจ๋ฒค์…˜๋„ ๋…ผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์šฐ์„  ์‹ค๋ฌด์—์„œ ์ ์šฉํ•ด๋ณด๊ณ  ์ถ”๊ฐ€ ํฌ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด์•ผ๊ฒ ๋‹ค.