MSPF-321: Introduce swag proto for URL-shortener (#1)

This commit is contained in:
Dmitry Manik 2017-11-28 19:59:50 +03:00 committed by GitHub
parent 44e803c2a3
commit cba6775ece
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 422 additions and 0 deletions

38
.gitignore vendored Normal file
View File

@ -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

1
CODEOWNERS Normal file
View File

@ -0,0 +1 @@
* @hackstep

8
Makefile Normal file
View File

@ -0,0 +1,8 @@
all: build
build:
npm install
npm run build
start:
npm start

50
gulpfile.js Normal file
View File

@ -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']);
});

24
package.json Normal file
View File

@ -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"
}
}

23
scripts/build.js Normal file
View File

@ -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')

24
spec/README.md Normal file
View File

@ -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"
```

View File

@ -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 `<lang>/<path>/<HTTP verb>.<extension>` where:
* `<lang>` - name of the language from [this](https://github.com/github/linguist/blob/master/lib/linguist/popular.yml) list.
* `<path>` - path of target method, where all slashes replaced with `@` sign.
* `<HTTP verb>` - verb of target method.
* `<extension>` - ignored.

View File

@ -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

View File

@ -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'

View File

@ -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'

81
spec/swagger.yaml Normal file
View File

@ -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: Получение и работа с короткими ссылками

59
web/index.html Normal file
View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<title>RBKmoney URL shortener</title>
<!-- needed for adaptive design -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--
ReDoc uses font options from the parent element
So override default browser styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url="./swagger.json" suppress-warnings="true" lazy-rendering="true">
</redoc>
<script src="//rebilly.github.io/ReDoc/releases/v1.x.x/redoc.min.js"> </script>
<!-- GA -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-92343978-1', 'auto');
ga('send', 'pageview');
</script>
<!-- Yandex.Metrika counter -->
<script type="text/javascript">
(function (d, w, c) {
(w[c] = w[c] || []).push(function() {
try {
w.yaCounter42980494 = new Ya.Metrika({
id:42980494,
clickmap:true,
trackLinks:true,
accurateTrackBounce:true
});
} catch(e) { }
});
var n = d.getElementsByTagName("script")[0],
s = d.createElement("script"),
f = function () { n.parentNode.insertBefore(s, n); };
s.type = "text/javascript";
s.async = true;
s.src = "https://mc.yandex.ru/metrika/watch.js";
if (w.opera == "[object Opera]") {
d.addEventListener("DOMContentLoaded", f, false);
} else { f(); }
})(document, window, "yandex_metrika_callbacks");
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/42980494" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->
</body>
</html>

28
wercker.yml Normal file
View File

@ -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"