mirror of
https://github.com/wahyd4/links.git
synced 2026-08-09 05:06:16 +10:00
Make API docs LLM-friendly
- Add operationId to all 20 API operations - Add tag groups (Pages, Posts, Collections, Images, Files) with descriptions - Enrich info.description with concept table, usage patterns, and examples - Add /llms.txt (llmstxt.org standard) with plain-text API overview - Add /.well-known/ai-plugin.json (OpenAI plugin manifest) - Add URL routes for llms.txt and ai-plugin.json Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -3,6 +3,7 @@ from django.urls import path, include
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.views.static import serve
|
||||
from django.views.generic import TemplateView
|
||||
from links.views import LinkDetailView, LinkUpdateView, CustomLinkView
|
||||
from links.file_views import PublicFileView, import_image_view
|
||||
from django.urls import path, include, re_path
|
||||
@@ -41,6 +42,10 @@ urlpatterns = [
|
||||
name='public-file',
|
||||
),
|
||||
|
||||
# LLM-friendly discovery endpoints
|
||||
path('llms.txt', serve, {'document_root': settings.STATIC_ROOT, 'path': 'llms.txt'}),
|
||||
path('.well-known/ai-plugin.json', serve, {'document_root': settings.STATIC_ROOT, 'path': '.well-known/ai-plugin.json'}),
|
||||
|
||||
# Include main app URLs with locale
|
||||
path('', include('links.urls')),
|
||||
]
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": "v1",
|
||||
"name_for_human": "GoLinks",
|
||||
"name_for_model": "golinks",
|
||||
"description_for_human": "Manage short links, bookmarked pages, image collections, file uploads, and blog posts on your self-hosted GoLinks server.",
|
||||
"description_for_model": "GoLinks is a self-hosted link and content management API. Use it to: bookmark URLs (server auto-extracts title/description/screenshot), create Markdown blog posts with tags, manage image collections with bulk upload, upload and share files via public token URLs, serve random images at any dimensions from a personal library, and import external images for self-hosting. All list endpoints are paginated with page/page_size params. No authentication required.",
|
||||
"auth": {
|
||||
"type": "none"
|
||||
},
|
||||
"api": {
|
||||
"type": "openapi",
|
||||
"url": "/static/openapi.yaml",
|
||||
"is_user_authenticated": false
|
||||
},
|
||||
"logo_url": "/static/images/logo.png",
|
||||
"contact_email": "",
|
||||
"legal_info_url": ""
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
# GoLinks API
|
||||
|
||||
> GoLinks is a self-hosted link and content management system. It lets you create short links, bookmark pages with auto-extracted metadata, manage image collections, upload files, write Markdown blog posts, and serve random images from a personal library.
|
||||
|
||||
## What you can do with this API
|
||||
|
||||
- **Bookmark pages** (`/api/pages`) — POST a URL and the server auto-fetches the title, description and screenshot in the background
|
||||
- **Write blog posts** (`/api/posts`) — Create Markdown posts with tag categorisation
|
||||
- **Manage image collections** (`/api/collections`) — Group images into named albums; upload multiple images at once
|
||||
- **Upload & share files** (`/api/files`) — Upload any file, make it public with a shareable token URL, set expiry dates
|
||||
- **Random image endpoint** (`/api/images/random/{width}/{height}/`) — Returns a random image from the server's library at any size; add `?fit=crop` to crop to exact dimensions
|
||||
- **Import external images** (`/import/images/{url-without-scheme}`) — Reference an external image URL; the server downloads and self-hosts it in the background
|
||||
|
||||
## API reference
|
||||
|
||||
- Full OpenAPI 3.0.3 spec: /static/openapi.yaml
|
||||
- Interactive docs: /ui/api-docs/
|
||||
|
||||
## Key patterns
|
||||
|
||||
### Embedding images in Markdown
|
||||
```markdown
|
||||

|
||||

|
||||
```
|
||||
|
||||
### File sharing workflow
|
||||
1. Upload a file: `POST /api/files` (multipart/form-data, field: `files`)
|
||||
2. Make it public: `POST /api/files/{id}/toggle-public` → get `public_url`
|
||||
3. Share the URL: `/public/files/{token}/` — no authentication required
|
||||
|
||||
### Pagination
|
||||
All list endpoints accept `?page=` (1-based) and `?page_size=`. Responses are enveloped:
|
||||
```json
|
||||
{ "count": 42, "next": "...", "previous": null, "results": [...] }
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
No authentication is currently required.
|
||||
|
||||
## Operations quick reference
|
||||
|
||||
| operationId | Method | Path | Description |
|
||||
|---|---|---|---|
|
||||
| listPages | GET | /api/pages | List bookmarked pages |
|
||||
| createPage | POST | /api/pages | Bookmark a new URL |
|
||||
| listPosts | GET | /api/posts | List blog posts |
|
||||
| createPost | POST | /api/posts | Create a blog post |
|
||||
| listCollections | GET | /api/collections | List image collections |
|
||||
| createCollection | POST | /api/collections | Create a collection |
|
||||
| deleteCollection | DELETE | /api/collections/{id} | Delete a collection |
|
||||
| uploadImagesToCollection | POST | /api/collections/{id}/upload_images | Upload images |
|
||||
| deleteImage | DELETE | /api/images/{id} | Delete an image |
|
||||
| listFiles | GET | /api/files | List uploaded files |
|
||||
| uploadFiles | POST | /api/files | Upload files |
|
||||
| getFile | GET | /api/files/{id} | Get file metadata |
|
||||
| deleteFile | DELETE | /api/files/{id} | Delete a file |
|
||||
| downloadFile | GET | /api/files/{id}/download | Download/view file |
|
||||
| toggleFilePublic | POST | /api/files/{id}/toggle-public | Toggle public sharing |
|
||||
| setFileExpiry | POST | /api/files/{id}/set-expiry | Set expiry date |
|
||||
| getPublicFile | GET | /public/files/{token}/ | Access public file |
|
||||
| getRandomImage | GET | /api/images/random/ | Random image (default size) |
|
||||
| getRandomImageSized | GET | /api/images/random/{w}/{h}/ | Random image at W×H |
|
||||
| importExternalImage | GET | /import/images/{url} | Import & cache external image |
|
||||
+135
-22
@@ -1,18 +1,80 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: GoLinks API
|
||||
description: API documentation for GoLinks service
|
||||
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: 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/pages:
|
||||
get:
|
||||
operationId: listPages
|
||||
tags: [Pages]
|
||||
summary: List all pages
|
||||
description: Retrieve a paginated list of all pages
|
||||
description: Retrieve a paginated list of all bookmarked pages.
|
||||
parameters:
|
||||
- in: query
|
||||
name: page
|
||||
@@ -33,8 +95,13 @@ paths:
|
||||
$ref: '#/components/schemas/PageList'
|
||||
|
||||
post:
|
||||
operationId: createPage
|
||||
tags: [Pages]
|
||||
summary: Create a new page
|
||||
description: Create a new page with the provided data
|
||||
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:
|
||||
@@ -51,8 +118,10 @@ paths:
|
||||
|
||||
/api/posts:
|
||||
get:
|
||||
operationId: listPosts
|
||||
tags: [Posts]
|
||||
summary: List all posts
|
||||
description: Retrieve a paginated list of all posts
|
||||
description: Retrieve a paginated list of all Markdown blog posts.
|
||||
parameters:
|
||||
- in: query
|
||||
name: page
|
||||
@@ -73,8 +142,10 @@ paths:
|
||||
$ref: '#/components/schemas/PostList'
|
||||
|
||||
post:
|
||||
operationId: createPost
|
||||
tags: [Posts]
|
||||
summary: Create a new post
|
||||
description: Create a new post with the provided data
|
||||
description: Create a Markdown blog post. Pass tag slugs in the `tags` array to categorise it.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -91,8 +162,10 @@ paths:
|
||||
|
||||
/api/collections:
|
||||
get:
|
||||
operationId: listCollections
|
||||
tags: [Collections]
|
||||
summary: List all collections
|
||||
description: Retrieve a paginated list of all image collections
|
||||
description: Retrieve a paginated list of all image collections.
|
||||
parameters:
|
||||
- in: query
|
||||
name: page
|
||||
@@ -113,8 +186,10 @@ paths:
|
||||
$ref: '#/components/schemas/CollectionList'
|
||||
|
||||
post:
|
||||
operationId: createCollection
|
||||
tags: [Collections]
|
||||
summary: Create a new collection
|
||||
description: Create a new image collection
|
||||
description: Create a new named image collection.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -131,8 +206,10 @@ paths:
|
||||
|
||||
/api/collections/{collection_id}:
|
||||
delete:
|
||||
operationId: deleteCollection
|
||||
tags: [Collections]
|
||||
summary: Delete a collection
|
||||
description: Delete a collection and all its images
|
||||
description: Permanently delete a collection and all its images.
|
||||
parameters:
|
||||
- in: path
|
||||
name: collection_id
|
||||
@@ -151,8 +228,12 @@ paths:
|
||||
|
||||
/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 with optional descriptions
|
||||
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
|
||||
@@ -203,8 +284,10 @@ paths:
|
||||
|
||||
/api/images/{image_id}:
|
||||
delete:
|
||||
operationId: deleteImage
|
||||
tags: [Images]
|
||||
summary: Delete an image
|
||||
description: Delete a specific image from a collection
|
||||
description: Permanently delete a single image from its collection.
|
||||
parameters:
|
||||
- in: path
|
||||
name: image_id
|
||||
@@ -223,8 +306,10 @@ paths:
|
||||
|
||||
/api/files:
|
||||
get:
|
||||
operationId: listFiles
|
||||
tags: [Files]
|
||||
summary: List all uploaded files
|
||||
description: Retrieve a paginated list of all uploaded files
|
||||
description: Retrieve a paginated list of all uploaded files.
|
||||
parameters:
|
||||
- in: query
|
||||
name: page
|
||||
@@ -240,8 +325,12 @@ paths:
|
||||
$ref: '#/components/schemas/FileList'
|
||||
|
||||
post:
|
||||
operationId: uploadFiles
|
||||
tags: [Files]
|
||||
summary: Upload one or more files
|
||||
description: Upload one or multiple files. Files are stored in FILE_UPLOADS_FOLDER on the server.
|
||||
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:
|
||||
@@ -271,7 +360,10 @@ paths:
|
||||
|
||||
/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
|
||||
@@ -290,8 +382,10 @@ paths:
|
||||
description: File not found
|
||||
|
||||
delete:
|
||||
operationId: deleteFile
|
||||
tags: [Files]
|
||||
summary: Delete a file
|
||||
description: Deletes the file record and removes it from disk
|
||||
description: Permanently delete the file record and remove it from disk.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
@@ -307,8 +401,12 @@ paths:
|
||||
|
||||
/api/files/{id}/download:
|
||||
get:
|
||||
operationId: downloadFile
|
||||
tags: [Files]
|
||||
summary: Download or view a file
|
||||
description: Serves the file content. Images are served inline; other files as attachments.
|
||||
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
|
||||
@@ -324,8 +422,14 @@ paths:
|
||||
|
||||
/api/files/{id}/toggle-public:
|
||||
post:
|
||||
operationId: toggleFilePublic
|
||||
tags: [Files]
|
||||
summary: Toggle public/private visibility
|
||||
description: Makes a private file public (generating a public token) or makes a public file private immediately.
|
||||
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
|
||||
@@ -353,7 +457,12 @@ paths:
|
||||
|
||||
/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
|
||||
@@ -383,8 +492,12 @@ paths:
|
||||
|
||||
/public/files/{token}/:
|
||||
get:
|
||||
operationId: getPublicFile
|
||||
tags: [Files]
|
||||
summary: Access a public file by token
|
||||
description: Serves a publicly shared file. Returns 404 if the file is private or the link has expired.
|
||||
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
|
||||
@@ -399,6 +512,8 @@ paths:
|
||||
|
||||
/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
|
||||
@@ -406,8 +521,6 @@ paths:
|
||||
|
||||
**Cache busting:** Add a `?v={timestamp}` query parameter to prevent browsers from
|
||||
caching repeated calls (the server ignores this parameter).
|
||||
tags:
|
||||
- Images
|
||||
parameters:
|
||||
- in: query
|
||||
name: fit
|
||||
@@ -454,6 +567,8 @@ paths:
|
||||
|
||||
/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.
|
||||
@@ -466,8 +581,6 @@ paths:
|
||||
```
|
||||

|
||||
```
|
||||
tags:
|
||||
- Images
|
||||
parameters:
|
||||
- in: path
|
||||
name: width
|
||||
@@ -531,6 +644,8 @@ paths:
|
||||
|
||||
/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.
|
||||
@@ -554,8 +669,6 @@ paths:
|
||||
```
|
||||

|
||||
```
|
||||
tags:
|
||||
- Files
|
||||
parameters:
|
||||
- in: path
|
||||
name: image_url
|
||||
|
||||
Reference in New Issue
Block a user