mirror of
https://github.com/wahyd4/links.git
synced 2026-08-15 16:15:58 +10:00
1093 lines
31 KiB
YAML
1093 lines
31 KiB
YAML
openapi: 3.0.3
|
||
info:
|
||
title: GoLinks API
|
||
description: |
|
||
# GoLinks — Link & Content Management API
|
||
|
||
GoLinks is a self-hosted link management system. It lets you create short links,
|
||
bookmark pages with auto-extracted metadata, manage image collections, upload files,
|
||
write blog posts, and serve random images from a personal library.
|
||
|
||
## Key concepts
|
||
|
||
| Resource | What it is |
|
||
|---|---|
|
||
| **Page** | A bookmarked URL. When created, the server asynchronously fetches its title, description, and a screenshot. |
|
||
| **Post** | A Markdown blog post, optionally tagged. |
|
||
| **Collection** | A named group of uploaded images (e.g. a photo album). |
|
||
| **Image** | An image file belonging to a Collection. |
|
||
| **File** | A generic uploaded file. Files can be made public via a shareable token URL. |
|
||
| **Random image** | Serves a random image from the server's local image library, resized on the fly. Great for placeholder images. |
|
||
|
||
## Common patterns
|
||
|
||
### Pagination
|
||
All list endpoints accept `?page=` (1-based) and `?page_size=` query parameters.
|
||
Responses follow the envelope `{ count, next, previous, results[] }`.
|
||
|
||
### Image embedding
|
||
Use the random image endpoint as a live placeholder:
|
||
```
|
||

|
||
```
|
||
Or import and self-host an external image:
|
||
```
|
||

|
||
```
|
||
|
||
### File sharing
|
||
Upload a file, call `POST /api/files/{id}/toggle-public` to get a public token,
|
||
then share `/public/files/{token}/` — no authentication required for the recipient.
|
||
|
||
## Authentication
|
||
No authentication is currently required on any endpoint.
|
||
version: 1.0.0
|
||
x-logo:
|
||
url: /static/images/logo.png
|
||
|
||
servers:
|
||
- url: http://localhost:8000
|
||
description: Local development server
|
||
|
||
tags:
|
||
- name: Links
|
||
description: Short links with click tracking. Supports listing all links and retrieving the most visited ones sorted by click count.
|
||
- name: Pages
|
||
description: |
|
||
Bookmarked web pages. Creating a page triggers an async background job that fetches
|
||
the page title, description, and screenshot automatically.
|
||
- name: Posts
|
||
description: Markdown blog posts with optional tag categorisation.
|
||
- name: Collections
|
||
description: Named groups of images. Each collection can hold many uploaded image files.
|
||
- name: Images
|
||
description: |
|
||
Image management and random image serving.
|
||
The random image endpoint is useful as a live placeholder — pass `?v={timestamp}`
|
||
to bust the browser cache on each render.
|
||
- name: Files
|
||
description: |
|
||
Generic file uploads with optional public sharing via tokenised URLs.
|
||
Files can be made public/private and given an expiry date.
|
||
|
||
paths:
|
||
/api/links:
|
||
get:
|
||
operationId: listLinks
|
||
tags: [Links]
|
||
summary: List all links
|
||
description: Retrieve a paginated list of all short links ordered by creation date (newest first).
|
||
parameters:
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
default: 1
|
||
description: Page number (1-based).
|
||
- in: query
|
||
name: page_size
|
||
schema:
|
||
type: integer
|
||
default: 10
|
||
maximum: 100
|
||
description: Number of results per page.
|
||
responses:
|
||
'200':
|
||
description: Paginated list of links.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/LinkList'
|
||
|
||
/api/links/most-visited:
|
||
get:
|
||
operationId: listMostVisitedLinks
|
||
tags: [Links]
|
||
summary: Most visited links
|
||
description: Return links that have at least one click, sorted by click count descending.
|
||
parameters:
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
default: 1
|
||
description: Page number (1-based).
|
||
- in: query
|
||
name: page_size
|
||
schema:
|
||
type: integer
|
||
default: 10
|
||
maximum: 100
|
||
description: Number of results per page.
|
||
responses:
|
||
'200':
|
||
description: Paginated list of links sorted by click_count descending.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/LinkList'
|
||
|
||
/api/pages:
|
||
get:
|
||
operationId: listPages
|
||
tags: [Pages]
|
||
summary: List all pages
|
||
description: Retrieve a paginated list of all bookmarked pages.
|
||
parameters:
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
description: Page number for pagination
|
||
- in: query
|
||
name: page_size
|
||
schema:
|
||
type: integer
|
||
description: Number of items per page
|
||
responses:
|
||
'200':
|
||
description: Successful response
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PageList'
|
||
|
||
post:
|
||
operationId: createPage
|
||
tags: [Pages]
|
||
summary: Create a new page
|
||
description: |
|
||
Bookmark a URL. After creation the server starts an async background job that fetches
|
||
the page title, description, content, and a screenshot.
|
||
Poll `GET /api/pages` or check `processing_status` to see when it completes.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PageCreate'
|
||
responses:
|
||
'201':
|
||
description: Page created successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Page'
|
||
|
||
/api/posts:
|
||
get:
|
||
operationId: listPosts
|
||
tags: [Posts]
|
||
summary: List all posts
|
||
description: Retrieve a paginated list of all Markdown blog posts.
|
||
parameters:
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
description: Page number for pagination
|
||
- in: query
|
||
name: page_size
|
||
schema:
|
||
type: integer
|
||
description: Number of items per page
|
||
responses:
|
||
'200':
|
||
description: Successful response
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PostList'
|
||
|
||
post:
|
||
operationId: createPost
|
||
tags: [Posts]
|
||
summary: Create a new post
|
||
description: Create a Markdown blog post. Pass tag slugs in the `tags` array to categorise it.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PostCreate'
|
||
responses:
|
||
'201':
|
||
description: Post created successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Post'
|
||
|
||
/api/collections:
|
||
get:
|
||
operationId: listCollections
|
||
tags: [Collections]
|
||
summary: List all collections
|
||
description: Retrieve a paginated list of all image collections.
|
||
parameters:
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
description: Page number for pagination
|
||
- in: query
|
||
name: page_size
|
||
schema:
|
||
type: integer
|
||
description: Number of items per page
|
||
responses:
|
||
'200':
|
||
description: Successful response
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CollectionList'
|
||
|
||
post:
|
||
operationId: createCollection
|
||
tags: [Collections]
|
||
summary: Create a new collection
|
||
description: Create a new named image collection.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CollectionCreate'
|
||
responses:
|
||
'201':
|
||
description: Collection created successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CollectionResponse'
|
||
|
||
/api/collections/{collection_id}:
|
||
delete:
|
||
operationId: deleteCollection
|
||
tags: [Collections]
|
||
summary: Delete a collection
|
||
description: Permanently delete a collection and all its images.
|
||
parameters:
|
||
- in: path
|
||
name: collection_id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
description: The ID of the collection to delete
|
||
responses:
|
||
'200':
|
||
description: Collection deleted successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SuccessResponse'
|
||
|
||
/api/collections/{collection_id}/upload_images:
|
||
post:
|
||
operationId: uploadImagesToCollection
|
||
tags: [Collections]
|
||
summary: Upload images to a collection
|
||
description: |
|
||
Upload one or more images to a collection. Only `image/*` content types are accepted.
|
||
Optionally provide a parallel `descriptions[]` array — each entry maps to the image at the same index.
|
||
parameters:
|
||
- in: path
|
||
name: collection_id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
description: The ID of the collection to upload images to
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
file:
|
||
type: array
|
||
items:
|
||
type: string
|
||
format: binary
|
||
description: List of image files to upload. Only image/* content types are allowed.
|
||
descriptions:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: Optional list of descriptions for the uploaded images. Each description corresponds to the image at the same index.
|
||
required:
|
||
- file
|
||
responses:
|
||
'201':
|
||
description: Images uploaded successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
status:
|
||
type: string
|
||
enum: [success]
|
||
example: success
|
||
message:
|
||
type: string
|
||
example: "Successfully uploaded 2 images"
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Image'
|
||
|
||
/api/images/{image_id}:
|
||
delete:
|
||
operationId: deleteImage
|
||
tags: [Images]
|
||
summary: Delete an image
|
||
description: Permanently delete a single image from its collection.
|
||
parameters:
|
||
- in: path
|
||
name: image_id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
description: The ID of the image to delete
|
||
responses:
|
||
'200':
|
||
description: Image deleted successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SuccessResponse'
|
||
|
||
/api/files:
|
||
get:
|
||
operationId: listFiles
|
||
tags: [Files]
|
||
summary: List all uploaded files
|
||
description: Retrieve a paginated list of all uploaded files.
|
||
parameters:
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
description: Page number for pagination
|
||
responses:
|
||
'200':
|
||
description: Successful response
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/FileList'
|
||
|
||
post:
|
||
operationId: uploadFiles
|
||
tags: [Files]
|
||
summary: Upload one or more files
|
||
description: |
|
||
Upload one or multiple files via `multipart/form-data`. Files are stored server-side
|
||
in the configured `FILE_UPLOADS_FOLDER`. Returns an array of `FileUpload` objects.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- files
|
||
properties:
|
||
files:
|
||
type: array
|
||
items:
|
||
type: string
|
||
format: binary
|
||
description: One or more files to upload
|
||
responses:
|
||
'201':
|
||
description: Files uploaded successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/FileUpload'
|
||
'400':
|
||
description: No files provided
|
||
|
||
/api/files/{id}:
|
||
get:
|
||
operationId: getFile
|
||
tags: [Files]
|
||
summary: Get file details
|
||
description: Fetch metadata for a single file by its UUID.
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
responses:
|
||
'200':
|
||
description: File details
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/FileUpload'
|
||
'404':
|
||
description: File not found
|
||
|
||
delete:
|
||
operationId: deleteFile
|
||
tags: [Files]
|
||
summary: Delete a file
|
||
description: Permanently delete the file record and remove it from disk.
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
responses:
|
||
'204':
|
||
description: File deleted
|
||
'404':
|
||
description: File not found
|
||
|
||
/api/files/{id}/download:
|
||
get:
|
||
operationId: downloadFile
|
||
tags: [Files]
|
||
summary: Download or view a file
|
||
description: |
|
||
Serve the raw file bytes. Images are returned with `Content-Disposition: inline`
|
||
(viewable in browser); all other files use `attachment` (triggers download).
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
responses:
|
||
'200':
|
||
description: File content
|
||
'404':
|
||
description: File not found
|
||
|
||
/api/files/{id}/toggle-public:
|
||
post:
|
||
operationId: toggleFilePublic
|
||
tags: [Files]
|
||
summary: Toggle public/private visibility
|
||
description: |
|
||
Toggle a file between public and private:
|
||
- **Private → Public**: generates a `public_token` and returns a `public_url`
|
||
(`/public/files/{token}/`) that anyone can access without authentication.
|
||
- **Public → Private**: immediately revokes the token; existing `public_url` links stop working.
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
responses:
|
||
'200':
|
||
description: Updated visibility state
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
is_public:
|
||
type: boolean
|
||
public_token:
|
||
type: string
|
||
nullable: true
|
||
public_url:
|
||
type: string
|
||
nullable: true
|
||
example: /public/files/<token>/
|
||
|
||
/api/files/{id}/set-expiry:
|
||
post:
|
||
operationId: setFileExpiry
|
||
tags: [Files]
|
||
summary: Set or clear expiry date for a public file
|
||
description: |
|
||
Set an expiry datetime for a public file. After the expiry the `public_url` returns 404.
|
||
Send `expires_at: null` (or omit the field) to remove the expiry and make the link permanent.
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
format: uuid
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
expires_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: ISO 8601 datetime. Send null or omit to clear the expiry.
|
||
responses:
|
||
'200':
|
||
description: Updated file details
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/FileUpload'
|
||
|
||
/public/files/{token}/:
|
||
get:
|
||
operationId: getPublicFile
|
||
tags: [Files]
|
||
summary: Access a public file by token
|
||
description: |
|
||
Unauthenticated endpoint. Serves a publicly shared file by its opaque token.
|
||
Returns 404 if the file has been made private or if the expiry date has passed.
|
||
parameters:
|
||
- in: path
|
||
name: token
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: File content (inline for images, attachment for others)
|
||
'404':
|
||
description: File not found, is private, or link has expired
|
||
|
||
/api/images/random/:
|
||
get:
|
||
operationId: getRandomImage
|
||
tags: [Images]
|
||
summary: Get a random image
|
||
description: |
|
||
Returns a randomly selected image from the server's image library, resized to the
|
||
default dimensions. Each request returns a different image.
|
||
|
||
**Cache busting:** Add a `?v={timestamp}` query parameter to prevent browsers from
|
||
caching repeated calls (the server ignores this parameter).
|
||
parameters:
|
||
- in: query
|
||
name: fit
|
||
schema:
|
||
type: string
|
||
enum: [clip, crop, fill, scale]
|
||
default: scale
|
||
description: |
|
||
How to fit the image into the requested dimensions.
|
||
- `scale` — scale to fit, maintaining aspect ratio (may add letterbox)
|
||
- `crop` — crop to exact dimensions
|
||
- `clip` — clip to fit, no upscaling
|
||
- `fill` — fill exact dimensions, may distort
|
||
- in: query
|
||
name: v
|
||
schema:
|
||
type: integer
|
||
description: Cache-busting value (e.g. Unix timestamp). Ignored by the server.
|
||
example: 1774152070
|
||
responses:
|
||
'200':
|
||
description: Image file (JPEG or PNG)
|
||
headers:
|
||
Cache-Control:
|
||
schema:
|
||
type: string
|
||
description: Caching directives (e.g. `public, max-age=3600`)
|
||
X-Image-Source:
|
||
schema:
|
||
type: string
|
||
description: Relative path of the source image that was served
|
||
content:
|
||
image/jpeg:
|
||
schema:
|
||
type: string
|
||
format: binary
|
||
image/png:
|
||
schema:
|
||
type: string
|
||
format: binary
|
||
'404':
|
||
description: |
|
||
No images available, folder not configured, or invalid parameters.
|
||
|
||
/api/images/random/{width}/{height}/:
|
||
get:
|
||
operationId: getRandomImageSized
|
||
tags: [Images]
|
||
summary: Get a random image at specific dimensions
|
||
description: |
|
||
Returns a randomly selected image resized to `{width}×{height}` pixels.
|
||
Minimum 300 px and maximum 4096 px for each dimension.
|
||
|
||
**Cache busting:** Add a `?v={timestamp}` query parameter to prevent browsers from
|
||
caching repeated calls (the server ignores this parameter).
|
||
|
||
**Use in Markdown / posts:**
|
||
```
|
||

|
||
```
|
||
parameters:
|
||
- in: path
|
||
name: width
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
minimum: 300
|
||
maximum: 4096
|
||
description: Target width in pixels
|
||
example: 300
|
||
- in: path
|
||
name: height
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
minimum: 300
|
||
maximum: 4096
|
||
description: Target height in pixels
|
||
example: 450
|
||
- in: query
|
||
name: fit
|
||
schema:
|
||
type: string
|
||
enum: [clip, crop, fill, scale]
|
||
default: scale
|
||
description: |
|
||
How to fit the image into the requested dimensions.
|
||
- `scale` — scale to fit, maintaining aspect ratio (may add letterbox)
|
||
- `crop` — crop to exact dimensions
|
||
- `clip` — clip to fit, no upscaling
|
||
- `fill` — fill exact dimensions, may distort
|
||
- in: query
|
||
name: v
|
||
schema:
|
||
type: integer
|
||
description: Cache-busting value (e.g. Unix timestamp). Ignored by the server.
|
||
example: 1774152070
|
||
responses:
|
||
'200':
|
||
description: Image file (JPEG or PNG) at the requested dimensions
|
||
headers:
|
||
Cache-Control:
|
||
schema:
|
||
type: string
|
||
X-Image-Source:
|
||
schema:
|
||
type: string
|
||
description: Relative path of the source image that was served
|
||
content:
|
||
image/jpeg:
|
||
schema:
|
||
type: string
|
||
format: binary
|
||
image/png:
|
||
schema:
|
||
type: string
|
||
format: binary
|
||
'404':
|
||
description: |
|
||
No images available, folder not configured, invalid dimensions, or invalid fit mode.
|
||
|
||
/import/images/{image_url}:
|
||
get:
|
||
operationId: importExternalImage
|
||
tags: [Files]
|
||
summary: Import and cache an external image
|
||
description: |
|
||
Imports an external image by URL and saves it to the local file store.
|
||
|
||
The `image_url` path parameter is the image URL **without** the `https://` scheme prefix
|
||
(e.g. `example.com/path/to/image.jpg`). The server always tries `https://` first.
|
||
|
||
**Worker mode** — this endpoint is non-blocking:
|
||
- On the **first request** for a given URL the server creates a `FileUpload` record
|
||
(marked `is_public: true`) and kicks off a background thread to download and save the file.
|
||
The response immediately redirects (HTTP 302) to the original `https://` source URL so the
|
||
image is visible right away.
|
||
- On **subsequent requests**, once the background download has completed, the response
|
||
redirects to the locally-saved public file URL (`/public/files/{uuid}-{filename}`) so the
|
||
original host is no longer needed.
|
||
|
||
**Idempotent** — the same external URL always resolves to the same `FileUpload` record;
|
||
the file is only downloaded once.
|
||
|
||
**Use in Markdown / posts:**
|
||
```
|
||

|
||
```
|
||
parameters:
|
||
- in: path
|
||
name: image_url
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: |
|
||
External image URL without the scheme prefix.
|
||
Example: `graziamagazine.com/wp-content/uploads/2024/12/Elle-Fanning-Pigtails-scaled.jpg`
|
||
example: graziamagazine.com/wp-content/uploads/2024/12/Elle-Fanning-Pigtails-scaled.jpg
|
||
responses:
|
||
'302':
|
||
description: |
|
||
Redirect to either the original source URL (while background download is in progress)
|
||
or the locally-saved public file URL (once download has completed).
|
||
headers:
|
||
Location:
|
||
schema:
|
||
type: string
|
||
description: URL to redirect to (original source or local `/public/files/…`)
|
||
|
||
components:
|
||
schemas:
|
||
Page:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
url:
|
||
type: string
|
||
title:
|
||
type: string
|
||
summary:
|
||
type: string
|
||
content:
|
||
type: string
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
PageCreate:
|
||
type: object
|
||
required:
|
||
- url
|
||
- title
|
||
properties:
|
||
url:
|
||
type: string
|
||
title:
|
||
type: string
|
||
summary:
|
||
type: string
|
||
content:
|
||
type: string
|
||
|
||
PageList:
|
||
type: object
|
||
properties:
|
||
count:
|
||
type: integer
|
||
next:
|
||
type: string
|
||
nullable: true
|
||
previous:
|
||
type: string
|
||
nullable: true
|
||
results:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Page'
|
||
|
||
Post:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
title:
|
||
type: string
|
||
content:
|
||
type: string
|
||
tag_details:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Tag'
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
PostCreate:
|
||
type: object
|
||
required:
|
||
- title
|
||
- content
|
||
properties:
|
||
title:
|
||
type: string
|
||
content:
|
||
type: string
|
||
tags:
|
||
type: array
|
||
items:
|
||
type: string
|
||
description: List of tag slugs to associate with the post
|
||
|
||
PostList:
|
||
type: object
|
||
properties:
|
||
count:
|
||
type: integer
|
||
next:
|
||
type: string
|
||
nullable: true
|
||
previous:
|
||
type: string
|
||
nullable: true
|
||
results:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Post'
|
||
|
||
Tag:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
slug:
|
||
type: string
|
||
description:
|
||
type: string
|
||
|
||
Collection:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
image_count:
|
||
type: integer
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
CollectionCreate:
|
||
type: object
|
||
required:
|
||
- name
|
||
properties:
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
|
||
CollectionList:
|
||
type: object
|
||
properties:
|
||
count:
|
||
type: integer
|
||
next:
|
||
type: string
|
||
nullable: true
|
||
previous:
|
||
type: string
|
||
nullable: true
|
||
results:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Collection'
|
||
|
||
CollectionResponse:
|
||
type: object
|
||
properties:
|
||
status:
|
||
type: string
|
||
enum: [success]
|
||
message:
|
||
type: string
|
||
data:
|
||
$ref: '#/components/schemas/Collection'
|
||
|
||
Image:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
collection:
|
||
type: string
|
||
format: uuid
|
||
title:
|
||
type: string
|
||
description:
|
||
type: string
|
||
content_type:
|
||
type: string
|
||
size:
|
||
type: integer
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
url:
|
||
type: string
|
||
|
||
FileUpload:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: string
|
||
format: uuid
|
||
readOnly: true
|
||
name:
|
||
type: string
|
||
description: Original filename
|
||
mime_type:
|
||
type: string
|
||
readOnly: true
|
||
size:
|
||
type: integer
|
||
readOnly: true
|
||
description: File size in bytes
|
||
formatted_size:
|
||
type: string
|
||
readOnly: true
|
||
description: Human-readable size (e.g. "1.4 MB")
|
||
is_public:
|
||
type: boolean
|
||
public_token:
|
||
type: string
|
||
nullable: true
|
||
readOnly: true
|
||
public_url:
|
||
type: string
|
||
nullable: true
|
||
readOnly: true
|
||
example: /public/files/<token>/
|
||
expires_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
is_expired:
|
||
type: boolean
|
||
readOnly: true
|
||
download_count:
|
||
type: integer
|
||
readOnly: true
|
||
source_url:
|
||
type: string
|
||
format: uri
|
||
nullable: true
|
||
description: |
|
||
Original external URL this file was imported from via `/import/images/…`.
|
||
`null` for files uploaded directly.
|
||
example: https://example.com/path/to/image.jpg
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
readOnly: true
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
readOnly: true
|
||
|
||
FileList:
|
||
type: object
|
||
properties:
|
||
count:
|
||
type: integer
|
||
next:
|
||
type: string
|
||
nullable: true
|
||
previous:
|
||
type: string
|
||
nullable: true
|
||
results:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/FileUpload'
|
||
|
||
SuccessResponse:
|
||
type: object
|
||
properties:
|
||
status:
|
||
type: string
|
||
enum: [success]
|
||
message:
|
||
type: string
|
||
|
||
TagSummary:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
slug:
|
||
type: string
|
||
|
||
Link:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
readOnly: true
|
||
alias:
|
||
type: string
|
||
description: Unique slug used as the short-link identifier (e.g. /gh → github.com).
|
||
original_url:
|
||
type: string
|
||
description: Target URL. May contain template parameters like `{param,default=value}`.
|
||
description:
|
||
type: string
|
||
nullable: true
|
||
link_type:
|
||
type: string
|
||
enum: [LINK, CUSTOM]
|
||
description: LINK redirects to original_url; CUSTOM renders Markdown content.
|
||
click_count:
|
||
type: integer
|
||
readOnly: true
|
||
description: Number of times the short link has been visited.
|
||
tags:
|
||
type: array
|
||
readOnly: true
|
||
items:
|
||
$ref: '#/components/schemas/TagSummary'
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
readOnly: true
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
readOnly: true
|
||
|
||
LinkList:
|
||
type: object
|
||
properties:
|
||
count:
|
||
type: integer
|
||
next:
|
||
type: string
|
||
nullable: true
|
||
previous:
|
||
type: string
|
||
nullable: true
|
||
results:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Link'
|