- добавлен contract DTO для picture sources и fallback image - реализована выдача versioned Gateway URLs по static presets - обновлена документация business API и dev smoke flow
138 lines
8.3 KiB
TypeScript
138 lines
8.3 KiB
TypeScript
import { Body, Controller, Get, Param, Post, Query } from "@nestjs/common"
|
||
import {
|
||
ApiBadRequestResponse,
|
||
ApiConflictResponse,
|
||
ApiCreatedResponse,
|
||
ApiNotFoundResponse,
|
||
ApiOkResponse,
|
||
ApiOperation,
|
||
ApiParam,
|
||
ApiQuery,
|
||
ApiTags,
|
||
} from "@nestjs/swagger"
|
||
|
||
import { AssetsService } from "./assets.service"
|
||
import { AssetPictureResponseDto } from "./asset-picture-response.dto"
|
||
import { AssetResponseDto, AssetVariantsResponseDto, AssetsListResponseDto } from "./asset-response.dto"
|
||
import { CreateAssetVersionRequestDto, CreateAssetVersionResponseDto } from "./create-asset-version.dto"
|
||
import { CreateAssetVariantsRequestDto, CreateAssetVariantsResponseDto } from "./create-asset-variants.dto"
|
||
import { CreateAssetRequestDto, CreateAssetResponseDto } from "./create-asset.dto"
|
||
|
||
@ApiTags("assets")
|
||
@Controller("assets")
|
||
export class AssetsController {
|
||
constructor(private readonly assets: AssetsService) {}
|
||
|
||
@Get()
|
||
@ApiOperation({
|
||
summary: "получить список assets",
|
||
description: "Возвращает последние зарегистрированные assets вместе с source URL текущей версии.",
|
||
})
|
||
@ApiQuery({ description: "Максимальное количество assets в ответе.", example: 50, name: "limit", required: false })
|
||
@ApiQuery({ description: "Смещение для простого paging.", example: 0, name: "offset", required: false })
|
||
@ApiOkResponse({ description: "Список assets возвращён.", type: AssetsListResponseDto })
|
||
listAssets(@Query("limit") limit?: string, @Query("offset") offset?: string): Promise<AssetsListResponseDto> {
|
||
return this.assets.listAssets({ limit, offset })
|
||
}
|
||
|
||
@Post()
|
||
@ApiOperation({
|
||
summary: "зарегистрировать исходное изображение",
|
||
description:
|
||
"Создаёт asset и первую версию source image. Source URL сохраняется в PostgreSQL, а публичный image URL строится через Gateway без раскрытия исходной ссылки клиенту.",
|
||
})
|
||
@ApiCreatedResponse({ description: "Asset создан, версия source image зарегистрирована.", type: CreateAssetResponseDto })
|
||
@ApiBadRequestResponse({ description: "Некорректный sourceUrl, publicId или source host запрещён настройками." })
|
||
@ApiConflictResponse({ description: "Asset с таким publicId уже существует." })
|
||
createAsset(@Body() request: CreateAssetRequestDto): Promise<CreateAssetResponseDto> {
|
||
return this.assets.createAsset(request)
|
||
}
|
||
|
||
@Get(":publicId")
|
||
@ApiOperation({
|
||
summary: "получить asset по publicId",
|
||
description: "Возвращает metadata asset и source URL текущей версии.",
|
||
})
|
||
@ApiParam({ description: "Публичный идентификатор asset.", example: "asset_demo", name: "publicId" })
|
||
@ApiOkResponse({ description: "Asset найден.", type: AssetResponseDto })
|
||
@ApiNotFoundResponse({ description: "Asset не найден." })
|
||
getAsset(@Param("publicId") publicId: string): Promise<AssetResponseDto> {
|
||
return this.assets.getAsset(publicId)
|
||
}
|
||
|
||
@Post(":publicId/versions")
|
||
@ApiOperation({
|
||
summary: "создать новую версию source image",
|
||
description:
|
||
"Регистрирует новый source URL для существующего asset, увеличивает currentVersion и тем самым создаёт новый immutable Gateway URL `/v{version}` без purge старых URLs.",
|
||
})
|
||
@ApiParam({ description: "Публичный идентификатор asset.", example: "asset_demo", name: "publicId" })
|
||
@ApiCreatedResponse({ description: "Новая версия source image создана и стала текущей.", type: CreateAssetVersionResponseDto })
|
||
@ApiBadRequestResponse({ description: "Некорректный sourceUrl или source host запрещён настройками." })
|
||
@ApiConflictResponse({ description: "Версия asset изменилась конкурентно." })
|
||
@ApiNotFoundResponse({ description: "Asset не найден." })
|
||
createAssetVersion(
|
||
@Param("publicId") publicId: string,
|
||
@Body() request: CreateAssetVersionRequestDto,
|
||
): Promise<CreateAssetVersionResponseDto> {
|
||
return this.assets.createAssetVersion(publicId, request)
|
||
}
|
||
|
||
@Get(":publicId/picture")
|
||
@ApiOperation({
|
||
summary: "получить picture/srcset URLs",
|
||
description:
|
||
"Возвращает готовый контракт для `<picture>` и `<img>` по static preset: sources, srcset, fallback src, sizes и versioned Gateway URLs. Endpoint не ставит generation jobs: Gateway сгенерирует bytes lazy или отдаст cache.",
|
||
})
|
||
@ApiParam({ description: "Публичный идентификатор asset.", example: "asset_demo", name: "publicId" })
|
||
@ApiQuery({ description: "Static preset для picture contract.", example: "card", name: "preset", required: true })
|
||
@ApiQuery({ description: "Версия source image. Если не передана, используется currentVersion asset.", example: 1, name: "version", required: false })
|
||
@ApiQuery({ description: "Quality. Если не передано, берётся default quality preset.", example: 80, name: "quality", required: false })
|
||
@ApiQuery({ description: "Значение для HTML `sizes`.", example: "(min-width: 768px) 50vw, 100vw", name: "sizes", required: false })
|
||
@ApiOkResponse({ description: "Picture/srcset contract возвращён.", type: AssetPictureResponseDto })
|
||
@ApiBadRequestResponse({ description: "Некорректный preset, version, quality или sizes." })
|
||
@ApiNotFoundResponse({ description: "Asset или version не найдены." })
|
||
getAssetPicture(
|
||
@Param("publicId") publicId: string,
|
||
@Query("preset") preset?: string,
|
||
@Query("version") version?: string,
|
||
@Query("quality") quality?: string,
|
||
@Query("sizes") sizes?: string,
|
||
): Promise<AssetPictureResponseDto> {
|
||
return this.assets.getAssetPicture(publicId, { preset, quality, sizes, version })
|
||
}
|
||
|
||
@Get(":publicId/variants")
|
||
@ApiOperation({
|
||
summary: "получить variants asset",
|
||
description: "Возвращает variants asset: preset/custom параметры, status, S3 key, public URL и ошибку генерации, если она была.",
|
||
})
|
||
@ApiParam({ description: "Публичный идентификатор asset.", example: "asset_demo", name: "publicId" })
|
||
@ApiQuery({ description: "Версия source image. Если не передана, возвращаются variants всех версий.", example: 1, name: "version", required: false })
|
||
@ApiOkResponse({ description: "Variants возвращены.", type: AssetVariantsResponseDto })
|
||
@ApiNotFoundResponse({ description: "Asset не найден." })
|
||
listAssetVariants(
|
||
@Param("publicId") publicId: string,
|
||
@Query("version") version?: string,
|
||
): Promise<AssetVariantsResponseDto> {
|
||
return this.assets.listAssetVariants(publicId, version)
|
||
}
|
||
|
||
@Post(":publicId/variants")
|
||
@ApiOperation({
|
||
summary: "поставить generation jobs для variants",
|
||
description:
|
||
"Business endpoint для явной подготовки variants. В режиме `single` создаёт один variant, в режиме `family` создаёт набор variants preset по всем разрешённым widths/formats. Endpoint не ждёт bytes, а возвращает созданные/переиспользованные rows и public URLs.",
|
||
})
|
||
@ApiParam({ description: "Публичный идентификатор asset.", example: "asset_demo", name: "publicId" })
|
||
@ApiCreatedResponse({ description: "Variants созданы или переиспользованы, jobs поставлены при необходимости.", type: CreateAssetVariantsResponseDto })
|
||
@ApiBadRequestResponse({ description: "Некорректный preset/custom transform config." })
|
||
@ApiNotFoundResponse({ description: "Asset или version не найдены." })
|
||
createAssetVariants(
|
||
@Param("publicId") publicId: string,
|
||
@Body() request: CreateAssetVariantsRequestDto,
|
||
): Promise<CreateAssetVariantsResponseDto> {
|
||
return this.assets.createAssetVariants(publicId, request)
|
||
}
|
||
}
|