mirror of
https://github.com/valitydev/swag-url-shortener.git
synced 2024-11-06 01:15:19 +00:00
MSPF-321: Introduce swag proto for URL-shortener (#1)
This commit is contained in:
parent
44e803c2a3
commit
cba6775ece
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal 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
1
CODEOWNERS
Normal file
@ -0,0 +1 @@
|
|||||||
|
* @hackstep
|
8
Makefile
Normal file
8
Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
all: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
start:
|
||||||
|
npm start
|
50
gulpfile.js
Normal file
50
gulpfile.js
Normal 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
24
package.json
Normal 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
23
scripts/build.js
Normal 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
24
spec/README.md
Normal 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"
|
||||||
|
```
|
9
spec/code_samples/README.md
Normal file
9
spec/code_samples/README.md
Normal 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.
|
18
spec/definitions/ShortenedUrl.yaml
Normal file
18
spec/definitions/ShortenedUrl.yaml
Normal 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
|
27
spec/paths/shortened-urls.yaml
Normal file
27
spec/paths/shortened-urls.yaml
Normal 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'
|
32
spec/paths/shortened-urls@{shortenedUrlID}.yaml
Normal file
32
spec/paths/shortened-urls@{shortenedUrlID}.yaml
Normal 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
81
spec/swagger.yaml
Normal 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
59
web/index.html
Normal 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
28
wercker.yml
Normal 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"
|
Loading…
Reference in New Issue
Block a user