Files
warpbox-dev/backend/libs/handlers/api_docs.go
Daniel Legt 3471e2b0cf feat(api): add API documentation and ShareX integration
- Add an API documentation page with curl and ShareX examples.
- Implement a dynamic ShareX configuration endpoint (`/api/v1/sharex/warpbox-anonymous.sxcu`) that generates a `.sxcu` file pre-configured with the instance's base URL.
- Update anonymous uploads to return a private management link (`manageUrl`) and a deletion link (`deleteUrl`) in JSON responses.
- Update README with details on Stage 3 Anonymous Integrations.
- Add styling for the new API documentation view and management details.
2026-05-29 23:44:05 +03:00

134 lines
5.2 KiB
Go

package handlers
import (
"net/http"
"warpbox.dev/backend/libs/helpers"
"warpbox.dev/backend/libs/web"
)
type apiDocsData struct {
BaseURL string
UploadURL string
HealthURL string
RequestSchemaURL string
ResponseSchemaURL string
ShareXExamplePath string
ShareXExampleURL string
ShareXDownloadURL string
ShareXFileFieldName string
}
func (a *App) APIDocs(w http.ResponseWriter, r *http.Request) {
a.renderer.Render(w, http.StatusOK, "api.html", web.PageData{
Title: "API documentation",
Description: "Curl and ShareX upload examples for Warpbox.",
Data: apiDocsData{
BaseURL: a.cfg.BaseURL,
UploadURL: a.cfg.BaseURL + "/api/v1/upload",
HealthURL: a.cfg.BaseURL + "/api/v1/health",
RequestSchemaURL: a.cfg.BaseURL + "/api/v1/schemas/upload-request.json",
ResponseSchemaURL: a.cfg.BaseURL + "/api/v1/schemas/upload-response.json",
ShareXExamplePath: "examples/sharex/warpbox-anonymous.sxcu",
ShareXExampleURL: a.cfg.BaseURL + "/api/v1/upload",
ShareXDownloadURL: a.cfg.BaseURL + "/api/v1/sharex/warpbox-anonymous.sxcu",
ShareXFileFieldName: "sharex",
},
})
}
func (a *App) ShareXAnonymousConfig(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", `attachment; filename="warpbox-anonymous.sxcu"`)
helpers.WriteJSON(w, http.StatusOK, map[string]any{
"Version": "18.0.0",
"Name": "Warpbox Anonymous Upload",
"DestinationType": "ImageUploader, TextUploader, FileUploader",
"RequestMethod": "POST",
"RequestURL": a.cfg.BaseURL + "/api/v1/upload",
"Headers": map[string]string{
"Accept": "application/json",
},
"Body": "MultipartFormData",
"FileFormName": "sharex",
"URL": "$json:boxUrl$",
"DeletionURL": "$json:manageUrl$",
})
}
func (a *App) UploadRequestSchema(w http.ResponseWriter, r *http.Request) {
helpers.WriteJSON(w, http.StatusOK, map[string]any{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": a.cfg.BaseURL + "/api/v1/schemas/upload-request.json",
"title": "Warpbox anonymous upload request",
"description": "Multipart/form-data request accepted by POST /api/v1/upload. Send one or more files using either the file or sharex field.",
"type": "object",
"properties": map[string]any{
"file": map[string]any{
"description": "One or more uploaded files. Use this field for curl and browser-style clients.",
"type": "array",
"items": map[string]any{"type": "string", "format": "binary"},
},
"sharex": map[string]any{
"description": "One or more uploaded files. Use this field for ShareX custom uploader configs.",
"type": "array",
"items": map[string]any{"type": "string", "format": "binary"},
},
"max_days": map[string]any{
"description": "Optional number of days before the box expires. Defaults to 7.",
"type": "integer",
"minimum": 1,
},
"max_downloads": map[string]any{
"description": "Optional maximum number of downloads before the box expires.",
"type": "integer",
"minimum": 1,
},
"password": map[string]any{
"description": "Optional box password.",
"type": "string",
},
"obfuscate_metadata": map[string]any{
"description": "Optional checkbox-style value. When set with a password, hides file names/counts until unlock.",
"type": "string",
"enum": []string{"on"},
},
},
"anyOf": []any{
map[string]any{"required": []string{"file"}},
map[string]any{"required": []string{"sharex"}},
},
})
}
func (a *App) UploadResponseSchema(w http.ResponseWriter, r *http.Request) {
helpers.WriteJSON(w, http.StatusOK, map[string]any{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": a.cfg.BaseURL + "/api/v1/schemas/upload-response.json",
"title": "Warpbox anonymous upload JSON response",
"description": "JSON response returned by POST /api/v1/upload when Accept: application/json is sent.",
"type": "object",
"required": []string{"boxId", "boxUrl", "zipUrl", "manageUrl", "deleteUrl", "expiresAt", "files"},
"properties": map[string]any{
"boxId": map[string]any{"type": "string"},
"boxUrl": map[string]any{"type": "string", "format": "uri"},
"zipUrl": map[string]any{"type": "string", "format": "uri"},
"manageUrl": map[string]any{"type": "string", "format": "uri", "description": "Private bearer URL for managing/deleting this upload. Returned only at upload time."},
"deleteUrl": map[string]any{"type": "string", "format": "uri", "description": "Private bearer POST URL for deleting this upload. Returned only at upload time."},
"expiresAt": map[string]any{"type": "string", "format": "date-time"},
"files": map[string]any{
"type": "array",
"items": map[string]any{
"type": "object",
"required": []string{"id", "name", "size", "url"},
"properties": map[string]any{
"id": map[string]any{"type": "string"},
"name": map[string]any{"type": "string"},
"size": map[string]any{"type": "string"},
"url": map[string]any{"type": "string", "format": "uri"},
},
},
},
},
})
}