
이전에 작성했던 블로그 글 OpenAPI Generator로 API의 안전한 Model과 정형화된 구현코드 자동생성하기에 이어서 작성하는 글이다.
기본 설정된 template이 아닌 커스텀 template을 만들어 적용하기 위해 author 스크립트를 사용하여 template을 추출하였다.
"author": "openapi-generator-cli author template -g typescript-axios -o ./mustaches"
첫 번째 글에서 generator를 적용하였지만 여러 시행 착오를 하였으며, 그 중
에 대해 개선하여 적용한 내용을 정리하겠다.
OpenAPI Generator 공식 문서의 내용 일부를 가지고 왔다.
author 스크립트를 돌린 후 -o에서 설정한 path에 *.mustache 파일들이 생성되며, 그 중 apiInner.mustache, modelGeneric.mustache 파일을 개선하였다.
여러 mustache 파일을 검색해본 결과 구현할 수 있는 로직은 다음과 같다.
사용 예제
{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}
Extensions
Vendor Extensions를 사용하여 스펙 문서의 configurations을 제공할 수 있다.
mustache templates에 내장된 x- 접두사로 만들어진 변수명을 따로 생성, 사용할 수 있다.
사용 예제
{{#vendorExtensions}} {{x-merge-sample-json}} {{/vendorExtensions}}
그래서 어떻게 해결하였는가? 공통 함수를 만들어 사용한다.
Axios 클래스는 다음과 같다.

주로 사용하는 get, delete, post, patch와 같은 메소드들마다 파라미터 형태가 다르다. 처음에는 httpMethod별로 각기 다른 mustache 코드 템플릿을 작성하려고 하였으나 코드가 엄청 지저분해지고 원하는대로 코드가 만들어지지 않는 한계점을 느꼈다.
// AS-IS
return instance.{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}(...)
파라미터 부분의 코드를 어떻게 템플릿화할 지 고민을 많이 하였다.
리턴 값을 래핑하는 공통 함수를 만들게 되었다.
// TO-BE
const 인스턴스_리턴_공통_함수 = ({
httpMethod,
url,
data,
config,
}: {
httpMethod: HttpMethod;
url: string;
data?: unknown;
config?: unknown;
}) => {
if (['request'].includes(httpMethod)) {
return instance[httpMethod](config);
}
if (['get', 'delete', 'head', 'options'].includes(httpMethod)) {
return instance[httpMethod](localVarPath, config);
}
return instance[httpMethod](localVarPath, data, config);
}
// ...
const get_도메인_함수 = ({
// 파라미터...
}: {
// 파라미터_타입...
}): Promise<...> => {
// 로직...
return 인스턴스_리턴_공통_함수({
httpMethod,
url,
data,
config,
});
};
단순한 것이 가장 직관적이라고 단순히 스크립트 나열을 통해 한 번에 모든 코드, 파일을 생성하도록 구성하였다.
npm run gen:common && npm run gen:도메인1 && npm run gen:도메인2 && ...
처음 openapi-generator를 도입하였을 때는 코드의 가독성과 퀄리티를 우선순위로 두었기 때문에 생성하고 나서 후처리를 수작업으로 진행하였다. 하지만 빈번한 API 수정과 유지보수 관리/편의성때문에 코드의 퀄리티를 낮춰서라도 100% 자동화를 통해 공수를 줄이고자 하였다.
템플릿 내 mustache 문법이 어떤 것을 제공하고 다른 사람들의 레퍼런스를 찾아보려 하였지만, 생각보다 찾기가 힘들었다.
위 깃헙의 파일 코드에서 사용되는 변수는 다음과 같다.
이를 통해 if 처리와 for 반복문을 통한 API 파라미터의 코드 템플릿을 구현할 수 있었고, 다음과 같이 mustache 파일의 코드가 아래와 같이 개선되었다.
// apiInner.mustache
{{#operations}}
{{#operation}}
{{^isDeprecated}}
const {{nickname}}_함수 = ({
{{#allParams}}
{{paramName}},
{{/allParams}}
추가적인_정적_파라미터,
}: {
{{#allParams}}
{{paramName}}{{^required}}?{{/required}}: {{=<% %>=}}<%&dataType%><%={{ }}=%>;
{{/allParams}}
추가적인_정적_파라미터: 타입;
}): Promise<{{{returnType}}}{{^returnType}}void{{/returnType}}> => {
const url: string = `{{{path}}}`{{#pathParams}}
.replace(`{${"{{baseName}}"}}`, encodeURIComponent(String({{paramName}}))){{/pathParams}};
const httpMethod: string = '{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}';
let data = undefined;
{{#hasBodyParam}}
data = {
{{#bodyParams}}
...{{paramName}}
{{/bodyParams}}
};
{{/hasBodyParam}}
{{#hasFormParams}}
data = {
{{#formParams}}
...{{paramName}}
{{/formParams}}
};
{{/hasFormParams}}
{{^hasQueryParams}}
let config = {};
{{#hasQueryParams}}
config = {
params: {
{{#queryParams}}
{{paramName}},
{{/queryParams}}
추가적인_정적_파라미터,
},
};
{{/hasQueryParams}}
return 인스턴스_리턴_공통_함수({
httpMethod,
url,
data,
config,
});
};