From cba6775ececff924f1687a0b561f47a21d969caa Mon Sep 17 00:00:00 2001 From: Dmitry Manik Date: Tue, 28 Nov 2017 19:59:50 +0300 Subject: [PATCH] MSPF-321: Introduce swag proto for URL-shortener (#1) --- .gitignore | 38 +++++++++ CODEOWNERS | 1 + Makefile | 8 ++ gulpfile.js | 50 ++++++++++++ package.json | 24 ++++++ scripts/build.js | 23 ++++++ spec/README.md | 24 ++++++ spec/code_samples/README.md | 9 +++ spec/definitions/ShortenedUrl.yaml | 18 +++++ spec/paths/shortened-urls.yaml | 27 +++++++ .../shortened-urls@{shortenedUrlID}.yaml | 32 ++++++++ spec/swagger.yaml | 81 +++++++++++++++++++ web/index.html | 59 ++++++++++++++ wercker.yml | 28 +++++++ 14 files changed, 422 insertions(+) create mode 100644 .gitignore create mode 100644 CODEOWNERS create mode 100644 Makefile create mode 100644 gulpfile.js create mode 100644 package.json create mode 100644 scripts/build.js create mode 100644 spec/README.md create mode 100644 spec/code_samples/README.md create mode 100644 spec/definitions/ShortenedUrl.yaml create mode 100644 spec/paths/shortened-urls.yaml create mode 100644 spec/paths/shortened-urls@{shortenedUrlID}.yaml create mode 100644 spec/swagger.yaml create mode 100644 web/index.html create mode 100644 wercker.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..30f08f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Dir for API portal deploy +web_deploy +out + +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +node_modules + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# CI +.wercker + diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..a8cb02a --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @hackstep diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8f43e2b --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +all: build + +build: + npm install + npm run build + +start: + npm start diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..c019b1c --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,50 @@ +var gulp = require('gulp'); +var util = require('gulp-util') +var gulpConnect = require('gulp-connect'); +var connect = require('connect'); +var cors = require('cors'); +var path = require('path'); +var exec = require('child_process').exec; +var portfinder = require('portfinder'); +var swaggerRepo = require('swagger-repo'); + +var DIST_DIR = 'web_deploy'; + +gulp.task('serve', ['build', 'watch', 'edit'], function() { + portfinder.getPort({port: 3000}, function (err, port) { + gulpConnect.server({ + root: [DIST_DIR], + livereload: true, + port: port, + middleware: function (gulpConnect, opt) { + return [ + cors() + ] + } + }); + }); +}); + +gulp.task('edit', function() { + portfinder.getPort({port: 5000}, function (err, port) { + var app = connect(); + app.use(swaggerRepo.swaggerEditorMiddleware()); + app.listen(port); + util.log(util.colors.green('swagger-editor started http://localhost:' + port)); + }); +}); + +gulp.task('build', function (cb) { + exec('npm run build', function (err, stdout, stderr) { + console.log(stderr); + cb(err); + }); +}); + +gulp.task('reload', ['build'], function () { + gulp.src(DIST_DIR).pipe(gulpConnect.reload()) +}); + +gulp.task('watch', function () { + gulp.watch(['spec/**/*', 'web/**/*'], ['reload']); +}); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..fad28b7 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "RBKmoney-openapi-spec", + "version": "0.0.1", + "dependencies": { + "bower": "^1.7.7", + "connect": "^3.4.1", + "cors": "^2.7.1", + "deploy-to-gh-pages": "^1.1.0", + "gulp": "^3.9.1", + "gulp-connect": "^4.2.0", + "gulp-util": "^3.0.7", + "portfinder": "^1.0.3", + "shelljs": "^0.7.0", + "swagger-repo": "^1.0.0", + "swagger-ui": "^2.1.4" + }, + "private": true, + "scripts": { + "build": "node ./scripts/build.js", + "swagger": "swagger-repo", + "test": "swagger-repo validate", + "start": "gulp serve" + } +} \ No newline at end of file diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..875ee3d --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,23 @@ +#!/usr/bin/env node +'use strict'; +var Path = require('path'); + +var TARGET_DIR = 'web_deploy' +if (process.argv[2]) { + TARGET_DIR = process.argv[2] +} + +require('shelljs/global'); +set('-e'); + +mkdir('-p', TARGET_DIR); + +cp('-R', 'web/*', TARGET_DIR + '/'); + +exec('npm run swagger bundle -- -o ' + TARGET_DIR + '/swagger.json'); +exec('npm run swagger bundle -- --yaml -o ' + TARGET_DIR + '/swagger.yaml'); + +var SWAGGER_UI_DIST = Path.dirname(require.resolve('swagger-ui')); +rm('-rf', TARGET_DIR + '/swagger-ui/') +cp('-R', SWAGGER_UI_DIST, TARGET_DIR + '/swagger-ui/') +sed('-i', 'http://petstore.swagger.io/v2/swagger.json', '../swagger.json', TARGET_DIR + '/swagger-ui/index.html') diff --git a/spec/README.md b/spec/README.md new file mode 100644 index 0000000..46f862c --- /dev/null +++ b/spec/README.md @@ -0,0 +1,24 @@ +## Global headers + +In order to minimize duplications you can use `headers` global object (similar to `definitions`, `responses`). +During build process all references to global `headers` will be inlined and `headers` will be removed form resulting spec so spec will be valid (global `headers` is not allowed by Swagger spec): + +Example: +```yaml +... +headers: + Rate-Limit-Limit: + description: The number of allowed requests in the current period + type: integer +... +paths: + /api-keys: + get: + summary: Retrieve a list of api keys + responses: + 200: + description: A list of api keys was retrieved successfully + headers: + Rate-Limit-Limit: + $ref: "#/headers/Rate-Limit-Limit" +``` diff --git a/spec/code_samples/README.md b/spec/code_samples/README.md new file mode 100644 index 0000000..0470a94 --- /dev/null +++ b/spec/code_samples/README.md @@ -0,0 +1,9 @@ +Code samples +===== + +Generate [x-code-samples](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-code-samples) +Path `//.` where: + * `` - name of the language from [this](https://github.com/github/linguist/blob/master/lib/linguist/popular.yml) list. + * `` - path of target method, where all slashes replaced with `@` sign. + * `` - verb of target method. + * `` - ignored. diff --git a/spec/definitions/ShortenedUrl.yaml b/spec/definitions/ShortenedUrl.yaml new file mode 100644 index 0000000..593bf46 --- /dev/null +++ b/spec/definitions/ShortenedUrl.yaml @@ -0,0 +1,18 @@ +type: object +required: + - id + - shortenedUrl + - sourceUrl + - expiresAt +properties: + id: + type: string + shortenedUrl: + type: string + format: uri + sourceUrl: + type: string + format: uri + expiresAt: + type: string + format: date-time diff --git a/spec/paths/shortened-urls.yaml b/spec/paths/shortened-urls.yaml new file mode 100644 index 0000000..c6d2680 --- /dev/null +++ b/spec/paths/shortened-urls.yaml @@ -0,0 +1,27 @@ +post: + description: Создать новую короткую ссылку + tags: + - Shortener + operationId: shortenUrl + parameters: + - $ref: '#/parameters/requestID' + - name: shortenedUrlParams + description: Параметры для создания короткой ссылки + in: body + required: true + schema: + type: object + properties: + sourceUrl: + type: string + format: uri + expiresAt: + type: string + format: date-time + responses: + '201': + description: Короткая ссылка создана + schema: + $ref: '#/definitions/ShortenedUrl' + '400': + $ref: '#/responses/BadRequest' diff --git a/spec/paths/shortened-urls@{shortenedUrlID}.yaml b/spec/paths/shortened-urls@{shortenedUrlID}.yaml new file mode 100644 index 0000000..5a499ac --- /dev/null +++ b/spec/paths/shortened-urls@{shortenedUrlID}.yaml @@ -0,0 +1,32 @@ +get: + description: Получить данные созданной короткой ссылки + operationId: getShortenedUrl + tags: + - Shortener + parameters: + - $ref: '#/parameters/requestID' + - $ref: '#/parameters/shortenedUrlID' + responses: + '200': + description: Данные короткой ссылки + schema: + $ref: '#/definitions/ShortenedUrl' + '400': + $ref: '#/responses/BadRequest' + '404': + $ref: '#/responses/NotFound' +delete: + description: Удалить короткую ссылку + operationId: deleteShortenedUrl + tags: + - Shortener + parameters: + - $ref: '#/parameters/requestID' + - $ref: '#/parameters/shortenedUrlID' + responses: + '204': + description: Короткая ссылка удалена + '400': + $ref: '#/responses/BadRequest' + '404': + $ref: '#/responses/NotFound' diff --git a/spec/swagger.yaml b/spec/swagger.yaml new file mode 100644 index 0000000..8078986 --- /dev/null +++ b/spec/swagger.yaml @@ -0,0 +1,81 @@ +swagger: '2.0' +host: rbk.mn +basePath: /v1 +info: + version: '1.0' + title: RBKmoney URL shortener API + termsOfService: 'http://rbkmoney.com/' + contact: + name: RBKmoney support team + email: tech-support@rbkmoney.com + url: 'https://api.rbk.money' + description: | + URL shortener API +schemes: + - https +consumes: + - application/json; charset=utf-8 +produces: + - application/json; charset=utf-8 +securityDefinitions: + bearer: + type: apiKey + name: Authorization + in: header + description: > + Для аутентификации вызовов мы используем [JWT](https://jwt.io). + Cоответствующий ключ передается в заголовке. + + ```shell + Authorization: Bearer {TOKENIZATION|PRIVATE_JWT} + ``` + + Посмотреть ваш API-ключ вы можете в [личном + кабинете](https://dashboard.rbk.money/api/key). + Ключи не разделяются на тестовые и боевые, ваш API ключ открывает доступ + ко всем функциям платформы. Для тестовых транзакций используйте ID + тестовых магазинов. + Помните, что вы никому не должны передавать ваш API ключ! +security: + - bearer: [] +responses: + NotFound: + description: Entity not found + schema: + type: object + required: + - message + properties: + message: + type: string + BadRequest: + description: Illegal input for operation + schema: + type: object + required: + - code + - message + properties: + code: + type: string + message: + type: string +parameters: + requestID: + name: X-Request-ID + in: header + description: Уникальный идентификатор запроса к системе + required: true + type: string + maxLength: 32 + minLength: 1 + shortenedUrlID: + name: shortenedUrlID + in: path + description: Идентификатор короткой ссылки + required: true + type: string +tags: + - name: Shortener + x-displayName: Короткие ссылки + description: Получение и работа с короткими ссылками diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..998d4c9 --- /dev/null +++ b/web/index.html @@ -0,0 +1,59 @@ + + + + RBKmoney URL shortener + + + + + + + + + + + + + + + + + + diff --git a/wercker.yml b/wercker.yml new file mode 100644 index 0000000..d9bb6fb --- /dev/null +++ b/wercker.yml @@ -0,0 +1,28 @@ +box: node:7 + +build: + steps: + - npm-install + - npm-test + - script: + name: build docsite + code: npm run build -- ${WERCKER_OUTPUT_DIR} + after-steps: + - slack-notifier: + url: ${SLACK_WEBHOOK_URL} + username: "wercker" + +release: + steps: + - script: + name: prepare release artifacts for branch master. + code: mkdir -p out && cp ./swagger.{yaml,json} out/ + - lordlothar99/git-push: + gh_oauth: ${GITHUB_API_TOKEN} + branch: release/${WERCKER_GIT_BRANCH} + basedir: out + message: Release ${WERCKER_GIT_OWNER}/${WERCKER_GIT_REPOSITORY}@${WERCKER_GIT_COMMIT} + after-steps: + - slack-notifier: + url: ${SLACK_WEBHOOK_URL} + username: "wercker"