UNPKG

mares-swagger-spec-maker

Version:

mares framework ���조에 맞춰서openapi spec을 combine 해주는 모듈입니다.

215 lines (197 loc) 7.74 kB
# mares-swagger-spec-maker mares framework 구조에 맞춰서openapi spec을 combine 해주는 모듈입니다. ## Installation `npm install --save mares-swagger-spec-maker` ## Example ```javascript const specMaker = require('mares-swagger-spec-maker')() // setting project root spec, let rootSpec = require('./.root-api-spec.js') // 서비스의 폴더를 추가해준다. 배열로 추가가 가능하다. 서비스별 폴더 구조는 아래에서 다시 설명한다. rootSpec = specMaker.merge(rootSpec, [require('./service-name')]) // api prefix가 있다면 추가해준다. rootSpec.paths = specMaker.addPrefix(rootSpec.paths, this._prefix) //optional ``` root spec의 경우 `.root-api-spec.js` 라고 이름지어 줘야 하며, 형태는 다음과 같다. `version`, `servers`, `info`, `components` 정의가 가능하다. ```javascript module.exports = { openapi: "3.0.0", servers: [{ url: env === 'development' ? 'http://localhost:8080' : 'https://aaaaa.com' }], info: { description: packageJson.description, version: packageJson.version, title: packageJson.name, termsOfService: 'http://swagger.io/terms/', contact: { email: 'aaa@aaaa.com' }, license: { name: 'Private', url: 'http://aaaa.com' } }, components: { schemas: { Error: { type: 'object', required: ['rows', 'count'], properties: { rows: { type: 'string', }, count: { type: 'integer', description: '전체 에러의 수', example: 1, nullable: false } } } } } } ``` 컨텍스트별 스펙의 경우 `.context-api-spec.js` 같이 파일명을 지어야 하며 형태는 아래와 같다. root components를 overriding 하고, tag를 지정하는데 사용된다. ```javascript const meta = GET_META('infra-message'); const spec = { tags: [{ name: 'message', description: '문자 발송, 발송된 문자 조회 등의 기능을 담은 API.' }], components: { securitySchemes: { ApiKeyAuth: { type: 'apiKey', in: 'header', name: 'X-API-TOKEN' } }, schemas: { PhoneNum: { type: 'string', pattern: /(^\+[0-9]{2}|^\+[0-9]{2}\(0\)|^\(\+[0-9]{2}\)\(0\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\-\s]{10}$)/, minLength: meta.std.message.minPhoneNumLength, maxLength: meta.std.message.maxPhoneNumLength, description: '문자를 받을 수 있는 전화번호, +국가코드 형태가 되어야 한다.', example: '+821011112222', nullable: false } }, parameters: { messageContextLimitParam: { in: 'query', name: 'limit', description: '최대 불러올 데이터 row 수', required: false, schema: { type: 'integer' }, example: meta.std.default.defaultContentsLength } } } } module.exports = spec ``` 다음으로 버전에 대한 스펙이 있다. `.version-api-spec.js` 라고 이름 지어줘야 한다. ```javascript module.exports = { in: 'path', name: 'version', description: '버전 값', required: false, schema: { type: 'string', enum: ['v1'], default: 'v1', example: 'v1' } } ``` 마지막으로 실제 router spec을 정의해야한다. `.spec.js` 정의한다. 전체 스펙에서 url 부분부터 정의를 해주면 된다. ```javascript const meta = GET_META('message-context'); const spec = { '/{version}/messages': { get: { tags: ['message'], summary: '문자 내역 확인', operationId: 'findMessages', description: '해당 스펙에서 message 라는 의미는 발송된 문자를 의미한다. 해당 API는 발송했던 문자 내역을 불러온다.', parameters: [{ $ref: '#/components/parameters/messageContextOffsetParam' }, { $ref: '#/components/parameters/messageContextLimitParam' }, { in: 'query', name: 'templateKey', description: '문자 발송시 이용된 템플릿의 키 겁색 (prefix 검색 가능)', required: false, schema: { type: 'string', example: 'templateKey123', nullable: false } }], responses: { '200': { description: '불러오기 성공', content: { 'application/json': { schema: { type: 'object', properties: { rows: { type: 'array', items: { $ref: '#/components/schemas/MessageDomain' }, description: '문자 도메인 배열' }, count: { type: 'integer', description: '해당 조건에 해당하는 전체 문자 도메인 카운트' } } } } } } } } } } module.exports = spec ``` 최종적으로는 아래와 같이 사용이 가능하다. ```javascript const getSpec = () => { // 최상단 루트 스펙을 가져온다. let rootSpec = require(path.resolve(rootPath, '.root-api-spec.js')) // 루프를 돌면서 마레스 모듈을 읽어와서 루트스펙에 머지한다,. for (let i = 0; i < contexts.length; ++i) { let moduleName = path.basename(contexts[i]) rootSpec = specMaker.merge(rootSpec, path.resolve(rootPath, moduleName)) } // 모든 url에 prefix를 붙여준다. 예를들면 account/users 라는 리소스가 있다면 prefix/account/users라고 변경이 된다. rootSpec.paths = specMaker.addPrefix(rootSpec.paths, prefix) // 모든 루트스펙에 선언된 컴포넌트 ($ref) 실제 객체로 바꿔준다. (이유는 실제 객체를 통해 router에서 parameter, requestBody 등을 validation하기 위함이다.) rootSpec = specMaker.replaceAllComponents(rootSpec) // 필요한 곳에 리턴한다. return rootSpec } ``` ## Structure 폴더 파일 구조는 다음과 같다. 1. 루트 프로젝트: `.root-api-spec.js`가 위치한다. 2. service 폴더: 서비스폴더 루트에 `.context-api-spec.js` 존재한다. 1. presentation: 프레젠테이션 레이어 1. v1: api 버전폴더: 해당폴더 안에 `version-api-spec.js`가 존재한다. 1. resourceName: 해당폴더 안에 `.spec.js`가 존재한다. 2. application: 어플리케이션 레이어 3. domain: 도메인 레이어 4. infra: 인프라스트럭쳐 레이어 5. test: test 코드