mirror of
https://github.com/valitydev/swag-api-keys-v2.git
synced 2024-11-06 02:25:17 +00:00
TD-635: Add initial specs (#1)
* TD-635: Add initial specs * Add workflows * Fix tests * Add 404 to listApiKeys
This commit is contained in:
parent
4990362d67
commit
73d97d2d06
23
.github/workflows/build.yml
vendored
Normal file
23
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: build
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
NODEJS_VERSION: '16'
|
||||
|
||||
jobs:
|
||||
bundle:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.NODEJS_VERSION }}
|
||||
cache: npm
|
||||
- run: npm install
|
||||
- name: Bundle specification
|
||||
run: npm run build
|
||||
- name: Validate specification
|
||||
run: npm run test
|
22
.github/workflows/frontend-pr.yml
vendored
Normal file
22
.github/workflows/frontend-pr.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: 'Frontend: PR'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: ['*']
|
||||
|
||||
jobs:
|
||||
configured:
|
||||
uses: valitydev/action-frontend/.github/workflows/configured.yml@v0.1
|
||||
check:
|
||||
name: Check
|
||||
runs-on: ubuntu-latest
|
||||
needs: configured
|
||||
if: needs.configured.outputs.exists == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: valitydev/action-frontend/setup@v0.1
|
||||
- run: npm ci
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Codegen
|
||||
run: npm run codegen
|
26
.github/workflows/frontend-publish.yml
vendored
Normal file
26
.github/workflows/frontend-publish.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: 'Frontend: Publish'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['master', 'main', 'v0']
|
||||
|
||||
jobs:
|
||||
configured:
|
||||
uses: valitydev/action-frontend/.github/workflows/configured.yml@v0.1
|
||||
publish:
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
needs: configured
|
||||
if: needs.configured.outputs.exists == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: valitydev/action-frontend/setup@v0.1
|
||||
- run: npm ci
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Codegen
|
||||
run: npm run codegen
|
||||
- uses: valitydev/action-frontend/publish@v0.1
|
||||
with:
|
||||
npm-token: ${{ secrets.NPM_TOKEN }}
|
||||
directory: ./lib
|
28
.github/workflows/gh-pages.yml
vendored
Normal file
28
.github/workflows/gh-pages.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: gh-pages
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
env:
|
||||
NODEJS_VERSION: "16"
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.NODEJS_VERSION }}
|
||||
cache: npm
|
||||
- run: npm install
|
||||
- name: Bundle specification
|
||||
run: npm run build
|
||||
- name: Publish ReDoc on Github Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./dist
|
||||
exclude_assets: "swagger-ui"
|
60
.github/workflows/release-erlang.yml
vendored
Normal file
60
.github/workflows/release-erlang.yml
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
name: Release Erlang Libraries
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: ['**']
|
||||
|
||||
env:
|
||||
NODEJS_VERSION: '16'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup swagger-codegen
|
||||
uses: valitydev/action-setup-swagger-codegen@v0.0.4
|
||||
with:
|
||||
codegen-version: "2.4.25"
|
||||
generator-version: "1.0.3"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.NODEJS_VERSION }}
|
||||
cache: npm
|
||||
|
||||
- name: Install deps
|
||||
run: npm install
|
||||
|
||||
- name: Bundle spec and build docsite
|
||||
run: npm run build -- build_public
|
||||
|
||||
- name: Generate stubs
|
||||
run: |
|
||||
mkdir -p out
|
||||
echo "Generate apikeys stubs"
|
||||
swagger-codegen generate -l vality-erlang-client -i build_public/api/apikeys/swagger.json -o out/erlang-client-apikeys --additional-properties packageName=swag_client_apikeys
|
||||
swagger-codegen generate -l vality-erlang-server -i build_public/api/apikeys/swagger.json -o out/erlang-server-apikeys --additional-properties packageName=swag_server_apikeys
|
||||
|
||||
#
|
||||
|
||||
- name: Deploy erlang-client-apikeys artifact to release branch
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
with:
|
||||
branch: release/erlang/client/master
|
||||
folder: out/erlang-client-apikeys
|
||||
commit-message: Release ${{ github.repository }}@${{ github.sha }}
|
||||
|
||||
- name: Deploy erlang-server-apikeys artifact to release branch
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
with:
|
||||
branch: release/erlang/server/master
|
||||
folder: out/erlang-server-apikeys
|
||||
commit-message: Release ${{ github.repository }}@${{ github.sha }}
|
30
.github/workflows/release.yml
vendored
Normal file
30
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: release
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
NODEJS_VERSION: '16'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.NODEJS_VERSION }}
|
||||
cache: npm
|
||||
- run: npm install
|
||||
- name: Bundle specification
|
||||
run: npm run build -- ../public
|
||||
- name: Deploy to release branch
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
with:
|
||||
branch: release/master
|
||||
folder: ../public/api
|
||||
target-folder: api
|
||||
commit-message: release ${{ github.repository }}@${{ github.sha }} by ${{ github.actor }}
|
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
# Dir for API portal deploy
|
||||
dist/
|
||||
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
|
||||
|
||||
# Frontend
|
||||
/lib
|
||||
|
||||
# Other
|
||||
.DS_Store
|
25
LICENSE
25
LICENSE
@ -174,28 +174,3 @@
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
11
api/apikeys/spec/definitions/AccessToken.yaml
Normal file
11
api/apikeys/spec/definitions/AccessToken.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
type: object
|
||||
required:
|
||||
- accessToken
|
||||
properties:
|
||||
accessToken:
|
||||
description: Токен доступа, ассоциированный с данным ключом
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 4000
|
||||
example: |
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0a2kiOiIxS2dJWUJHc0NncSIsImlhdCI6MTUxNjIzOTAyMn0.6YsaZQC9A7BjxXHwRbJfUO6VujOb4rHTKrqmMt64TbQ
|
28
api/apikeys/spec/definitions/ApiKey.yaml
Normal file
28
api/apikeys/spec/definitions/ApiKey.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
description: Ключ для авторизации запросов к API
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- createdAt
|
||||
- name
|
||||
- status
|
||||
properties:
|
||||
id:
|
||||
$ref: '#/definitions/ApiKeyID'
|
||||
createdAt:
|
||||
description: Дата и время создания
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
name:
|
||||
description: Запоминающееся название ключа
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 40
|
||||
example: live-site-integration
|
||||
status:
|
||||
$ref: '#/definitions/ApiKeyStatus'
|
||||
metadata:
|
||||
description: |
|
||||
Произвольный набор данных, специфичный для клиента API и
|
||||
непрозрачный для системы
|
||||
type: object
|
6
api/apikeys/spec/definitions/ApiKeyID.yaml
Normal file
6
api/apikeys/spec/definitions/ApiKeyID.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
description: Идентификатор ключа
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 40
|
||||
example: 1KgIYBGsCgq
|
||||
readOnly: true
|
6
api/apikeys/spec/definitions/ApiKeyStatus.yaml
Normal file
6
api/apikeys/spec/definitions/ApiKeyStatus.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
description: Статус ключа
|
||||
type: string
|
||||
enum:
|
||||
- Active
|
||||
- Revoked
|
||||
readOnly: true
|
26
api/apikeys/spec/definitions/BadRequest.yaml
Normal file
26
api/apikeys/spec/definitions/BadRequest.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
type: object
|
||||
required:
|
||||
- errorType
|
||||
properties:
|
||||
errorType:
|
||||
description: Error type
|
||||
type: string
|
||||
enum:
|
||||
- SchemaViolated
|
||||
- NotFound
|
||||
- WrongType
|
||||
- NotInRange
|
||||
- WrongSize
|
||||
- WrongLength
|
||||
- WrongArray
|
||||
- NoMatch
|
||||
- InvalidToken
|
||||
example: NotFound
|
||||
name:
|
||||
description: Name or identifier of message element containing invalid data
|
||||
type: string
|
||||
example: X-Request-ID
|
||||
description:
|
||||
description: Explanation of why the data is invalid
|
||||
type: string
|
||||
example: Required parameter was not sent
|
49
api/apikeys/spec/docs/api.md
Normal file
49
api/apikeys/spec/docs/api.md
Normal file
@ -0,0 +1,49 @@
|
||||
Vality API Keys Management API является интерфейсом для управления набором
|
||||
API-ключей, используемых для авторизации запросов к основному API с ваших
|
||||
бэкенд-сервисов. Любые сторонние приложения, включая ваш личный кабинет,
|
||||
являются внешними приложениями-клиентами данного API.
|
||||
|
||||
Мы предоставляем REST API поверх HTTP-протокола, схема которого описывается в
|
||||
соответствии со стандартом [OpenAPI 3][OAS3].
|
||||
Коды возврата описываются соответствующими HTTP-статусами. Платформа принимает и
|
||||
возвращает значения JSON в теле запросов и ответов.
|
||||
|
||||
[OAS3]: https://swagger.io/specification/
|
||||
|
||||
## Идентификатор запроса
|
||||
|
||||
При любом обращении к API в заголовке `X-Request-ID` соответствующего запроса необходимо
|
||||
передать его уникальный идентификатор:
|
||||
|
||||
```
|
||||
X-Request-ID: 37d735d4-0f42-4f05-89fa-eaa478fb5aa9
|
||||
```
|
||||
|
||||
## Формат содержимого
|
||||
|
||||
Любой запрос к API должен выполняться в кодировке UTF-8 и с указанием
|
||||
содержимого в формате JSON.
|
||||
|
||||
```
|
||||
Content-Type: application/json; charset=utf-8
|
||||
```
|
||||
|
||||
## Максимальное время обработки запроса
|
||||
|
||||
При любом обращении к API в заголовке `X-Request-Deadline` соответствующего запроса можно
|
||||
передать параметр отсечки по времени, определяющий максимальное время ожидания завершения
|
||||
операции по запросу:
|
||||
|
||||
```
|
||||
X-Request-Deadline: 10s
|
||||
```
|
||||
|
||||
По истечении указанного времени система прекращает обработку запроса. Рекомендуется указывать
|
||||
значение не более одной минуты, но не менее трёх секунд.
|
||||
|
||||
`X-Request-Deadline` может:
|
||||
|
||||
* задаваться в формате `date-time` согласно
|
||||
[RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339);
|
||||
* задаваться в относительных величинах: в миллисекундах (`150000ms`), секундах (`540s`) или
|
||||
минутах (`3.5m`).
|
34
api/apikeys/spec/docs/errors.md
Normal file
34
api/apikeys/spec/docs/errors.md
Normal file
@ -0,0 +1,34 @@
|
||||
## Общие ошибки
|
||||
|
||||
Ошибки возникающие при попытках совершения недопустимых операций, операций с невалидными объектами или несуществующими ресурсами. Имеют следующий вид:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "string",
|
||||
"message": "string"
|
||||
}
|
||||
```
|
||||
|
||||
В поле `message` содержится информация по произошедшей ошибке. Например:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "invalidRequest",
|
||||
"message": "Property 'name' is required."
|
||||
}
|
||||
```
|
||||
|
||||
## Ошибки обработки запросов
|
||||
|
||||
В процессе обработки запросов силами нашей платформы могут происходить различные непредвиденные ситуации. Об их появлении платформа сигнализирует по протоколу HTTP соответствующими [статусами][5xx], обозначающими ошибки сервера.
|
||||
|
||||
| Код | Описание |
|
||||
| ------- | ---------- |
|
||||
| **500** | В процессе обработки платформой запроса возникла непредвиденная ситуация. При получении подобного кода ответа мы рекомендуем обратиться в техническую поддержку. |
|
||||
| **503** | Платформа временно недоступна и не готова обслуживать данный запрос. Запрос гарантированно не выполнен, при получении подобного кода ответа попробуйте выполнить его позднее, когда доступность платформы будет восстановлена. |
|
||||
| **504** | Платформа превысила допустимое время обработки запроса, результат запроса не определён. Попробуйте отправить запрос повторно или выяснить результат выполнения исходного запроса, если повторное исполнение запроса нежелательно. |
|
||||
|
||||
[5xx]: https://tools.ietf.org/html/rfc7231#section-6.6
|
||||
|
||||
|
||||
Если вы получили ошибку, которой нет в данном описании, обратитесь в техническую поддержку.
|
61
api/apikeys/spec/paths/orgs@{partyId}@api-keys.yaml
Normal file
61
api/apikeys/spec/paths/orgs@{partyId}@api-keys.yaml
Normal file
@ -0,0 +1,61 @@
|
||||
---
|
||||
get:
|
||||
summary: Перечислить ключи организации
|
||||
operationId: listApiKeys
|
||||
tags:
|
||||
- apiKeys
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestID'
|
||||
- $ref: '#/parameters/deadline'
|
||||
- $ref: '#/parameters/partyId'
|
||||
- name: status
|
||||
description: |
|
||||
Фильтр по статусу ключа. По умолчанию `active`.
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
enum:
|
||||
- Active
|
||||
- Revoked
|
||||
responses:
|
||||
'200':
|
||||
description: Ключи найдены
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- results
|
||||
properties:
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ApiKey'
|
||||
'401':
|
||||
$ref: "#/responses/Unauthorized"
|
||||
'404':
|
||||
$ref: "#/responses/NotFound"
|
||||
'400':
|
||||
$ref: '#/responses/BadRequest'
|
||||
|
||||
post:
|
||||
summary: Выпустить новый ключ
|
||||
operationId: issueApiKey
|
||||
tags:
|
||||
- apiKeys
|
||||
parameters:
|
||||
- $ref: '#/parameters/partyId'
|
||||
- name: apiKey
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/ApiKey'
|
||||
responses:
|
||||
'200':
|
||||
description: Ключ выпущен
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/ApiKey'
|
||||
- $ref: '#/definitions/AccessToken'
|
||||
'401':
|
||||
$ref: "#/responses/Unauthorized"
|
||||
'400':
|
||||
$ref: '#/responses/BadRequest'
|
@ -0,0 +1,22 @@
|
||||
---
|
||||
get:
|
||||
summary: Получить данные ключа
|
||||
operationId: getApiKey
|
||||
tags:
|
||||
- apiKeys
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestID'
|
||||
- $ref: '#/parameters/deadline'
|
||||
- $ref: '#/parameters/partyId'
|
||||
- $ref: '#/parameters/apiKeyId'
|
||||
responses:
|
||||
'200':
|
||||
description: Ключ найден
|
||||
schema:
|
||||
$ref: '#/definitions/ApiKey'
|
||||
'404':
|
||||
$ref: "#/responses/NotFound"
|
||||
'401':
|
||||
$ref: "#/responses/Unauthorized"
|
||||
'400':
|
||||
$ref: '#/responses/BadRequest'
|
@ -0,0 +1,32 @@
|
||||
---
|
||||
put:
|
||||
summary: Запросить отзыв ключа
|
||||
description: |
|
||||
Просит отозвать Api Key, для подтверждения запроса
|
||||
посылает на почту запросившего письмо с ссылкой на
|
||||
revokeApiKey для подтверждения операции
|
||||
operationId: requestRevokeApiKey
|
||||
tags:
|
||||
- apiKeys
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestID'
|
||||
- $ref: '#/parameters/deadline'
|
||||
- $ref: '#/parameters/partyId'
|
||||
- $ref: '#/parameters/apiKeyId'
|
||||
- name: status
|
||||
description: Status to change Api Key into
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- Revoked
|
||||
responses:
|
||||
'204':
|
||||
description: Запрос на операцию получен
|
||||
"404":
|
||||
$ref: "#/responses/NotFound"
|
||||
'401':
|
||||
$ref: "#/responses/Unauthorized"
|
||||
'400':
|
||||
$ref: '#/responses/BadRequest'
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
get:
|
||||
summary: Отозвать ключ
|
||||
description: |
|
||||
Ссылка на этот запрос приходит на почту запросившего
|
||||
requestRevokeApiKey, в результате выполнения этого запроса
|
||||
Api Key будет отозван
|
||||
operationId: revokeApiKey
|
||||
tags:
|
||||
- apiKeys
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestID'
|
||||
- $ref: '#/parameters/deadline'
|
||||
- $ref: '#/parameters/partyId'
|
||||
- $ref: '#/parameters/apiKeyId'
|
||||
- $ref: '#/parameters/apiKeyRevokeToken'
|
||||
responses:
|
||||
'204':
|
||||
description: Ключ отозван
|
||||
"404":
|
||||
$ref: "#/responses/NotFound"
|
||||
'401':
|
||||
$ref: "#/responses/Unauthorized"
|
||||
'400':
|
||||
$ref: '#/responses/BadRequest'
|
189
api/apikeys/spec/swagger.yaml
Normal file
189
api/apikeys/spec/swagger.yaml
Normal file
@ -0,0 +1,189 @@
|
||||
---
|
||||
swagger: "2.0"
|
||||
info:
|
||||
version: "0.1.0"
|
||||
title: Vality Api Keys API
|
||||
description: >
|
||||
Vality API Keys Management API является интерфейсом для управления набором
|
||||
API-ключей, используемых для авторизации запросов к основному API с ваших
|
||||
бэкенд-сервисов. Любые сторонние приложения, включая ваш личный кабинет,
|
||||
являются внешними приложениями-клиентами данного API.
|
||||
|
||||
Мы предоставляем REST API поверх HTTP-протокола, схема которого описывается в
|
||||
соответствии со стандартом [OpenAPI 3][OAS3].
|
||||
Коды возврата описываются соответствующими HTTP-статусами. Платформа принимает и
|
||||
возвращает значения JSON в теле запросов и ответов.
|
||||
|
||||
[OAS3]: https://swagger.io/specification/
|
||||
|
||||
## Идентификатор запроса
|
||||
|
||||
При любом обращении к API в заголовке `X-Request-ID` соответствующего запроса необходимо
|
||||
передать его уникальный идентификатор:
|
||||
|
||||
```
|
||||
X-Request-ID: 37d735d4-0f42-4f05-89fa-eaa478fb5aa9
|
||||
```
|
||||
|
||||
## Формат содержимого
|
||||
|
||||
Любой запрос к API должен выполняться в кодировке UTF-8 и с указанием
|
||||
содержимого в формате JSON.
|
||||
|
||||
```
|
||||
Content-Type: application/json; charset=utf-8
|
||||
```
|
||||
|
||||
## Максимальное время обработки запроса
|
||||
|
||||
При любом обращении к API в заголовке `X-Request-Deadline` соответствующего запроса можно
|
||||
передать параметр отсечки по времени, определяющий максимальное время ожидания завершения
|
||||
операции по запросу:
|
||||
|
||||
```
|
||||
X-Request-Deadline: 10s
|
||||
```
|
||||
|
||||
По истечении указанного времени система прекращает обработку запроса. Рекомендуется указывать
|
||||
значение не более одной минуты, но не менее трёх секунд.
|
||||
|
||||
`X-Request-Deadline` может:
|
||||
|
||||
* задаваться в формате `date-time` согласно
|
||||
[RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339);
|
||||
* задаваться в относительных величинах: в миллисекундах (`150000ms`), секундах (`540s`) или
|
||||
минутах (`3.5m`).
|
||||
|
||||
termsOfService: "https://vality.dev/"
|
||||
contact:
|
||||
name: Technical support team
|
||||
email: support@vality.dev
|
||||
url: "https://api.vality.dev"
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
host: api.vality.dev
|
||||
basePath: /apikeys/v2
|
||||
schemes:
|
||||
- https
|
||||
consumes:
|
||||
- application/json; charset=utf-8
|
||||
produces:
|
||||
- application/json; charset=utf-8
|
||||
securityDefinitions:
|
||||
bearer:
|
||||
type: apiKey
|
||||
name: Authorization
|
||||
in: header
|
||||
description: >
|
||||
Use [JWT](https://jwt.io) for call authentication. The corresponding key is passed in the header.
|
||||
|
||||
```shell
|
||||
Authorization: Bearer {YOUR_API_KEY_JWT}
|
||||
```
|
||||
|
||||
security:
|
||||
- bearer: []
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Invalid input data for operation
|
||||
schema:
|
||||
$ref: "#/definitions/BadRequest"
|
||||
NotFound:
|
||||
description: The content you are looking for was not found
|
||||
Unauthorized:
|
||||
description: Authorization error
|
||||
parameters:
|
||||
requestID:
|
||||
name: X-Request-ID
|
||||
in: header
|
||||
description: Unique identifier of the request to the system
|
||||
required: true
|
||||
type: string
|
||||
maxLength: 32
|
||||
minLength: 1
|
||||
deadline:
|
||||
name: X-Request-Deadline
|
||||
in: header
|
||||
description: Maximum request processing time
|
||||
required: false
|
||||
type: string
|
||||
maxLength: 40
|
||||
minLength: 1
|
||||
apiKeyId:
|
||||
name: apiKeyId
|
||||
in: path
|
||||
description: Идентификатор ключа
|
||||
required: true
|
||||
type: string
|
||||
# schema:
|
||||
# $ref: '#/definitions/ApiKeyID'
|
||||
# type: string
|
||||
minLength: 1
|
||||
maxLength: 40
|
||||
# example: 1KgIYBGsCgq
|
||||
apiKeyRevokeToken:
|
||||
name: apiKeyRevokeToken
|
||||
in: query
|
||||
description: Токен отзыва ключа
|
||||
required: true
|
||||
type: string
|
||||
# schema:
|
||||
# $ref: '#/definitions/RevokeToken'
|
||||
|
||||
minLength: 1
|
||||
maxLength: 4000
|
||||
# example: |
|
||||
# f767b77e-300f-47a7-84e2-e24ea585a9f0
|
||||
partyId:
|
||||
name: partyId
|
||||
in: path
|
||||
description: Идентификатор участника
|
||||
required: true
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 40
|
||||
# example: |
|
||||
# bdaf9e76-1c5b-4798-b154-19b87a61dc94
|
||||
|
||||
tags:
|
||||
- name: apiKeys
|
||||
x-displayName: API-ключи
|
||||
- name: errorCodes
|
||||
x-displayName: Коды ошибок
|
||||
description: >
|
||||
## Общие ошибки
|
||||
|
||||
Ошибки возникающие при попытках совершения недопустимых операций, операций с невалидными объектами или несуществующими ресурсами. Имеют следующий вид:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "string",
|
||||
"message": "string"
|
||||
}
|
||||
```
|
||||
|
||||
В поле `message` содержится информация по произошедшей ошибке. Например:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "invalidRequest",
|
||||
"message": "Property 'name' is required."
|
||||
}
|
||||
```
|
||||
|
||||
## Ошибки обработки запросов
|
||||
|
||||
В процессе обработки запросов силами нашей платформы могут происходить различные непредвиденные ситуации. Об их появлении платформа сигнализирует по протоколу HTTP соответствующими [статусами][5xx], обозначающими ошибки сервера.
|
||||
|
||||
| Код | Описание |
|
||||
| ------- | ---------- |
|
||||
| **500** | В процессе обработки платформой запроса возникла непредвиденная ситуация. При получении подобного кода ответа мы рекомендуем обратиться в техническую поддержку. |
|
||||
| **503** | Платформа временно недоступна и не готова обслуживать данный запрос. Запрос гарантированно не выполнен, при получении подобного кода ответа попробуйте выполнить его позднее, когда доступность платформы будет восстановлена. |
|
||||
| **504** | Платформа превысила допустимое время обработки запроса, результат запроса не определён. Попробуйте отправить запрос повторно или выяснить результат выполнения исходного запроса, если повторное исполнение запроса нежелательно. |
|
||||
|
||||
[5xx]: https://tools.ietf.org/html/rfc7231#section-6.6
|
||||
|
||||
|
||||
Если вы получили ошибку, которой нет в данном описании, обратитесь в техническую поддержку.
|
||||
|
51
gulpfile.js
Normal file
51
gulpfile.js
Normal file
@ -0,0 +1,51 @@
|
||||
const gulp = require('gulp');
|
||||
const util = require('gulp-util');
|
||||
const gulpConnect = require('gulp-connect');
|
||||
const connect = require('connect');
|
||||
const cors = require('cors');
|
||||
const exec = require('child_process').exec;
|
||||
const portfinder = require('portfinder');
|
||||
const swaggerRepo = require('swagger-repo');
|
||||
|
||||
const DIST_DIR = 'dist';
|
||||
const SPEC_DIR = 'spec';
|
||||
|
||||
gulp.task('build', function (cb) {
|
||||
exec('npm run build', function (err, stdout, stderr) {
|
||||
console.log(stderr);
|
||||
cb(err);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
gulp.task('edit', function () {
|
||||
portfinder.getPort({ port: 5000 }, function (err, port) {
|
||||
let app = connect();
|
||||
app.use(swaggerRepo.swaggerEditorMiddleware());
|
||||
app.listen(port);
|
||||
util.log(util.colors.green('swagger-editor started http://localhost:' + port));
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('reload', gulp.series('build', function () {
|
||||
gulp.src(DIST_DIR).pipe(gulpConnect.reload())
|
||||
}));
|
||||
|
||||
gulp.task('watch', function () {
|
||||
gulp.watch([`${SPEC_DIR}/**/*`, 'web/**/*'], gulp.series('reload'));
|
||||
});
|
||||
|
||||
gulp.task('serve', gulp.parallel('build', 'edit', 'watch', function () {
|
||||
portfinder.getPort({ port: 3000 }, function (err, port) {
|
||||
gulpConnect.server({
|
||||
root: [DIST_DIR],
|
||||
livereload: true,
|
||||
port: port,
|
||||
middleware: function (gulpConnect, opt) {
|
||||
return [
|
||||
cors()
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
}));
|
7
openapitools.json
Normal file
7
openapitools.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||
"spaces": 2,
|
||||
"generator-cli": {
|
||||
"version": "6.0.0-beta"
|
||||
}
|
||||
}
|
16112
package-lock.json
generated
Normal file
16112
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@vality/swag-api-keys-v2",
|
||||
"version": "0.1.1",
|
||||
"scripts": {
|
||||
"build": "node ./scripts/build.js",
|
||||
"swagger": "swagger-repo",
|
||||
"test": "swagger-repo validate --basedir api/apikeys/spec/",
|
||||
"start": "gulp serve",
|
||||
"codegen": "vality-openapi generate ./dist/api/apikeys/swagger.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vality/openapi-generator-cli": "0.1.1-fbfe66e.0",
|
||||
"connect": "3.7.0",
|
||||
"cors": "2.8.5",
|
||||
"gulp": "github:gulpjs/gulp",
|
||||
"gulp-connect": "5.7.0",
|
||||
"gulp-util": "3.0.8",
|
||||
"json-merge-patch": "1.0.2",
|
||||
"portfinder": "1.0.32",
|
||||
"shelljs": "0.8.5",
|
||||
"swagger-repo": "1.5.1",
|
||||
"swagger-ui": "4.15.5"
|
||||
}
|
||||
}
|
6
renovate.json
Normal file
6
renovate.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"local>valitydev/.github:renovate-config"
|
||||
]
|
||||
}
|
32
scripts/build.js
Executable file
32
scripts/build.js
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
var Path = require('path');
|
||||
|
||||
require('shelljs/global');
|
||||
set('-e');
|
||||
|
||||
var TARGET_DIR = 'dist'
|
||||
if (process.argv[2]) {
|
||||
TARGET_DIR = process.argv[2]
|
||||
}
|
||||
|
||||
var APIS = ls('api')
|
||||
if (process.argv[3]) {
|
||||
APIS = [process.argv[3]]
|
||||
}
|
||||
|
||||
mkdir('-p', TARGET_DIR);
|
||||
cp('-R', 'web/*', TARGET_DIR + '/');
|
||||
|
||||
APIS.forEach(function (api) {
|
||||
var basedir = 'api/' + api + '/spec/';
|
||||
var targetdir = TARGET_DIR + '/api/' + api;
|
||||
mkdir('-p', targetdir);
|
||||
exec('npm run swagger bundle -- --basedir ' + basedir + ' -o ' + targetdir + '/swagger.json');
|
||||
exec('npm run swagger bundle -- --basedir ' + basedir + ' --yaml -o ' + targetdir + '/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')
|
28
scripts/plugins/x-rebillyMerge.js
Normal file
28
scripts/plugins/x-rebillyMerge.js
Normal file
@ -0,0 +1,28 @@
|
||||
var jpointer = require('json-pointer');
|
||||
var mergePatch = require('json-merge-patch');
|
||||
|
||||
module.exports = {
|
||||
pathExpression: '$..["x-rebillyMerge"]',
|
||||
init: function(swagger) {
|
||||
console.log('* x-rebillyMerge plugin');
|
||||
},
|
||||
process: function(parent, name, jsonpath, swagger) {
|
||||
var value = parent[name];
|
||||
if (!Array.isArray(value)) {
|
||||
throw Error('x-rebillyMerge argument should be array at ' + jsonpath);
|
||||
}
|
||||
let res = null;
|
||||
value.forEach(function(obj) {
|
||||
if (typeof obj !== 'object') throw Error('Can\'t merge non-object values at ' + jsonpath);
|
||||
if (obj.$ref && (typeof obj.$ref === 'string')) {
|
||||
obj = jpointer.get(swagger, obj.$ref.substring(1));
|
||||
}
|
||||
res = mergePatch.apply(res, obj);
|
||||
});
|
||||
delete parent[name];
|
||||
Object.assign(parent, res);
|
||||
},
|
||||
finish: function(swagger) {
|
||||
// TODO: cleanup unused $refs
|
||||
},
|
||||
}
|
27
spec/definitions/responses/BadRequest.yaml
Normal file
27
spec/definitions/responses/BadRequest.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
type: object
|
||||
required:
|
||||
- errorType
|
||||
properties:
|
||||
errorType:
|
||||
description: Error type
|
||||
type: string
|
||||
enum:
|
||||
- SchemaViolated
|
||||
- NotFound
|
||||
- WrongType
|
||||
- NotInRange
|
||||
- WrongSize
|
||||
- WrongLength
|
||||
- WrongArray
|
||||
- NoMatch
|
||||
- InvalidResourceToken
|
||||
- InvalidToken
|
||||
example: NotFound
|
||||
name:
|
||||
description: Name or identifier of message element containing invalid data
|
||||
type: string
|
||||
example: X-Request-ID
|
||||
description:
|
||||
description: Explanation of why the data is invalid
|
||||
type: string
|
||||
example: Required parameter was not sent
|
46
web/index.html
Normal file
46
web/index.html
Normal file
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Vality Api Keys Management API</title>
|
||||
<!-- needed for adaptive design -->
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js">
|
||||
</script>
|
||||
<!--
|
||||
ReDoc doesn't change outer page styles
|
||||
-->
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id='redoc'></div>
|
||||
<script type="text/javascript">
|
||||
// Since we serve three different specs from a single domain we hack up a
|
||||
// simple way to redirect user to one or another
|
||||
var spec = window.location.search.substring(1);
|
||||
if (spec.length == 0) {
|
||||
spec = "api/apikeys/swagger.json";
|
||||
}
|
||||
Redoc.init(
|
||||
spec,
|
||||
{
|
||||
theme: {
|
||||
breakpoints: {
|
||||
// 3-panel view fix
|
||||
medium: '75rem'
|
||||
}
|
||||
}
|
||||
},
|
||||
document.getElementById('redoc')
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user