427 lines
13 KiB
YAML
427 lines
13 KiB
YAML
openapi: 3.0.3
|
||
|
||
info:
|
||
title: Drawings API
|
||
version: "0.0.1"
|
||
description: |
|
||
REST API сервиса **drawings-api** (`gitlab.com/sarex-team/rnd/drawings-api`) —
|
||
управление разрезами (cross-sections) чертежей, их данными и экспортом
|
||
в DWG через сервис workflows.
|
||
|
||
Сервис написан на **Go** (gorilla/mux, go-pg). Роутер собирается в
|
||
`cmd/drawings-api/bootstrap.go`. Помимо служебных эндпоинтов
|
||
(`/ping`, `/metrics`) есть две группы бизнес-маршрутов с одинаковым
|
||
набором операций:
|
||
|
||
- `/api/v1/*` — публичный роутинг;
|
||
- `/internal/v1/*` — внутренний роутинг (набор тот же плюс webhook
|
||
экспорта, вызываемый воркером workflow).
|
||
|
||
На все бизнес-маршруты навешены middleware: JSON-ответ (`rest.JSONResponse`),
|
||
request-id (`reqid.Middleware`) и логирование. Явной аутентификации в коде
|
||
сервиса нет — доступ ограничивается на уровне ingress/сети кластера.
|
||
|
||
### Экспорт в DWG
|
||
`POST /exports` создаёт запись экспорта и запускает workflow из двух задач
|
||
(парсинг cross-section в DWG + webhook-уведомление). По завершении workflow
|
||
вызывает `POST /internal/v1/exports/{export_id}/webhook`, который переводит
|
||
экспорт в статус `done`.
|
||
|
||
servers:
|
||
- url: /api/v1
|
||
description: Публичный префикс
|
||
- url: /internal/v1
|
||
description: Внутренний префикс
|
||
|
||
tags:
|
||
- name: service
|
||
description: Служебные эндпоинты
|
||
- name: cross-sections
|
||
description: Разрезы чертежей
|
||
- name: exports
|
||
description: Экспорт разрезов в DWG
|
||
|
||
paths:
|
||
/ping:
|
||
get:
|
||
tags: [service]
|
||
summary: Healthcheck
|
||
description: Возвращает статус готовности. Доступен в корне (без префикса).
|
||
responses:
|
||
"200":
|
||
description: Сервис готов
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
status:
|
||
type: string
|
||
example: ready
|
||
|
||
/metrics:
|
||
get:
|
||
tags: [service]
|
||
summary: Prometheus-метрики
|
||
description: Метрики в формате Prometheus. Доступен в корне (без префикса).
|
||
responses:
|
||
"200":
|
||
description: Метрики
|
||
content:
|
||
text/plain:
|
||
schema:
|
||
type: string
|
||
|
||
# ----- Публичные маршруты (/api/v1) и внутренние (/internal/v1) идентичны,
|
||
# кроме webhook, который есть только на /internal/v1. Пути ниже указаны
|
||
# относительно префикса из блока servers. -----
|
||
|
||
/cross-sections:
|
||
post:
|
||
tags: [cross-sections]
|
||
summary: Создать разрез
|
||
description: Создаёт cross-section вместе с его данными (`data.raw_data`).
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/CreateCrossSectionRequest"
|
||
responses:
|
||
"200":
|
||
description: Созданный разрез
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/CrossSection"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
get:
|
||
tags: [cross-sections]
|
||
summary: Список разрезов по instance_id
|
||
parameters:
|
||
- name: instance_id
|
||
in: query
|
||
required: true
|
||
description: UUID инстанса (чертежа)
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
responses:
|
||
"200":
|
||
description: Массив разрезов (пустой, если ничего не найдено)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/CrossSection"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
|
||
/cross-sections/{cs_id}:
|
||
delete:
|
||
tags: [cross-sections]
|
||
summary: Удалить разрез (soft-delete)
|
||
parameters:
|
||
- $ref: "#/components/parameters/CrossSectionId"
|
||
responses:
|
||
"200":
|
||
$ref: "#/components/responses/OK"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"404":
|
||
description: Разрез не найден (возможно, уже удалён)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/Error"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
|
||
/cross-sections/{cs_id}/data:
|
||
get:
|
||
tags: [cross-sections]
|
||
summary: Данные разреза
|
||
parameters:
|
||
- $ref: "#/components/parameters/CrossSectionId"
|
||
responses:
|
||
"200":
|
||
description: Данные разреза
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/Data"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
|
||
/exports:
|
||
post:
|
||
tags: [exports]
|
||
summary: Создать экспорт разреза в DWG
|
||
description: |
|
||
Создаёт запись экспорта и запускает workflow экспорта в DWG.
|
||
В ответе `workflow_status` = `running`.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/CreateExportRequest"
|
||
responses:
|
||
"200":
|
||
description: Созданный экспорт
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/Export"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
get:
|
||
tags: [exports]
|
||
summary: Список экспортов по фильтрам
|
||
description: |
|
||
Хотя бы один из фильтров должен быть задан, иначе `400`.
|
||
Каждый параметр — список UUID/чисел через запятую.
|
||
parameters:
|
||
- name: cross_section_ids
|
||
in: query
|
||
required: false
|
||
description: UUID разрезов через запятую
|
||
schema:
|
||
type: string
|
||
- name: export_ids
|
||
in: query
|
||
required: false
|
||
description: UUID экспортов через запятую
|
||
schema:
|
||
type: string
|
||
- name: workflow_ids
|
||
in: query
|
||
required: false
|
||
description: UUID workflow через запятую
|
||
schema:
|
||
type: string
|
||
- name: attachment_ids
|
||
in: query
|
||
required: false
|
||
description: ID вложений (целые) через запятую
|
||
schema:
|
||
type: string
|
||
responses:
|
||
"200":
|
||
description: Массив экспортов (пустой, если ничего не найдено)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/Export"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
|
||
/exports/{export_id}:
|
||
delete:
|
||
tags: [exports]
|
||
summary: Удалить экспорт
|
||
parameters:
|
||
- $ref: "#/components/parameters/ExportId"
|
||
responses:
|
||
"200":
|
||
$ref: "#/components/responses/OK"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
|
||
/exports/{export_id}/webhook:
|
||
post:
|
||
tags: [exports]
|
||
summary: Webhook завершения экспорта (только /internal/v1)
|
||
description: |
|
||
Вызывается воркером workflow по завершении экспорта. Переводит
|
||
экспорт в статус `done`. Доступен только по внутреннему префиксу
|
||
`/internal/v1`.
|
||
parameters:
|
||
- $ref: "#/components/parameters/ExportId"
|
||
responses:
|
||
"200":
|
||
$ref: "#/components/responses/OK"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequest"
|
||
"500":
|
||
$ref: "#/components/responses/StorageError"
|
||
|
||
components:
|
||
parameters:
|
||
CrossSectionId:
|
||
name: cs_id
|
||
in: path
|
||
required: true
|
||
description: UUID разреза
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
ExportId:
|
||
name: export_id
|
||
in: path
|
||
required: true
|
||
description: UUID экспорта
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
|
||
responses:
|
||
OK:
|
||
description: Успешно (тело — строка `"OK"`)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: string
|
||
example: OK
|
||
BadRequest:
|
||
description: Некорректный запрос
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/Error"
|
||
StorageError:
|
||
description: Внутренняя ошибка (ошибка хранилища)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/Error"
|
||
|
||
schemas:
|
||
CrossSection:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
name:
|
||
type: string
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
deleted_at:
|
||
type: string
|
||
format: date-time
|
||
instance_id:
|
||
type: string
|
||
format: uuid
|
||
documents:
|
||
type: object
|
||
additionalProperties:
|
||
$ref: "#/components/schemas/ConnectedDocument"
|
||
exports:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/Export"
|
||
|
||
ConnectedDocument:
|
||
type: object
|
||
properties:
|
||
color:
|
||
type: string
|
||
name:
|
||
type: string
|
||
|
||
Data:
|
||
type: object
|
||
properties:
|
||
cross_section_id:
|
||
type: string
|
||
format: uuid
|
||
raw_data:
|
||
type: string
|
||
|
||
CreateCrossSectionRequest:
|
||
type: object
|
||
description: Разрез плюс его данные. Наследует поля CrossSection.
|
||
allOf:
|
||
- $ref: "#/components/schemas/CrossSection"
|
||
- type: object
|
||
properties:
|
||
data:
|
||
$ref: "#/components/schemas/Data"
|
||
|
||
Author:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
format: int64
|
||
first_name:
|
||
type: string
|
||
last_name:
|
||
type: string
|
||
|
||
Export:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
name:
|
||
type: string
|
||
author:
|
||
$ref: "#/components/schemas/Author"
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
deleted_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
cross_section_id:
|
||
type: string
|
||
format: uuid
|
||
workflow_id:
|
||
type: string
|
||
format: uuid
|
||
nullable: true
|
||
workflow_status:
|
||
type: string
|
||
nullable: true
|
||
enum: [done, running, error]
|
||
file_type:
|
||
type: string
|
||
enum: [dwg]
|
||
attachment_id:
|
||
type: integer
|
||
nullable: true
|
||
|
||
CreateExportRequest:
|
||
type: object
|
||
required: [cross_section_id, author, file_type, company_id]
|
||
properties:
|
||
cross_section_id:
|
||
type: string
|
||
format: uuid
|
||
author:
|
||
$ref: "#/components/schemas/Author"
|
||
file_type:
|
||
type: string
|
||
enum: [dwg]
|
||
company_id:
|
||
type: integer
|
||
format: int64
|
||
|
||
Error:
|
||
type: object
|
||
description: Ответ об ошибке (gotools/httperror).
|
||
properties:
|
||
error:
|
||
type: string
|