Update API schema and deployment guidance
This commit is contained in:
1 parent
0cf29e0e06
commit
8cd0d5ca89
2 files changed
+10
-12
No files matched your search
@@ -42,7 +42,9 @@ npm run build
|
|||||||
NODE_ENV=production node .output/server/index.mjs
|
NODE_ENV=production node .output/server/index.mjs
|
||||||
```
|
```
|
||||||
|
|
||||||
The server listens on port `3000` by default; Nitro also honors `PORT`/`NITRO_PORT` and `HOST`/`NITRO_HOST`. A reverse proxy may terminate TLS and forward requests to this server.
|
The server listens on port `3000` by default; Nitro also honors `PORT`/`NITRO_PORT` and `HOST`/`NITRO_HOST`. A reverse proxy may terminate TLS and forward requests to this server. When using cookie authentication, configure a trusted proxy to preserve the public `Host` and overwrite `X-Forwarded-Proto`; the server uses these values to validate same-origin mutation requests.
|
||||||
|
|
||||||
|
The health check endpoint is `GET /api/health` and returns `{ "status": "ok" }`.
|
||||||
|
|
||||||
The upload directory must be writable and persist across deployments/restarts, and all Nuxt instances serving the same library must see the same files. Static/serverless deployments without persistent writable storage are not suitable for the current upload and media routes. Install `ffmpeg` and `ffprobe` on the host and make them available on `PATH`; audio uploads are processed after they are received. Configure an ingress or reverse-proxy request size limit appropriate for audio uploads.
|
The upload directory must be writable and persist across deployments/restarts, and all Nuxt instances serving the same library must see the same files. Static/serverless deployments without persistent writable storage are not suitable for the current upload and media routes. Install `ffmpeg` and `ffprobe` on the host and make them available on `PATH`; audio uploads are processed after they are received. Configure an ingress or reverse-proxy request size limit appropriate for audio uploads.
|
||||||
|
|
||||||
|
|||||||
+7
-11
@@ -14,6 +14,7 @@ type ApiOperation = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const operations: ApiOperation[] = [
|
const operations: ApiOperation[] = [
|
||||||
|
{ method: "get", path: "/health", tag: "Health", summary: "Health check", response: "Health" },
|
||||||
{ method: "post", path: "/auth/register", tag: "Auth", summary: "Register a user", body: "json", response: "EmptyObject", status: 201 },
|
{ method: "post", path: "/auth/register", tag: "Auth", summary: "Register a user", body: "json", response: "EmptyObject", status: 201 },
|
||||||
{ method: "post", path: "/auth/signin", tag: "Auth", summary: "Sign in", body: "json", response: "EmptyObject" },
|
{ method: "post", path: "/auth/signin", tag: "Auth", summary: "Sign in", body: "json", response: "EmptyObject" },
|
||||||
{ method: "post", path: "/auth/session", tag: "Auth", summary: "Create a session", body: "json", response: "Session", status: 201 },
|
{ method: "post", path: "/auth/session", tag: "Auth", summary: "Create a session", body: "json", response: "Session", status: 201 },
|
||||||
@@ -119,10 +120,13 @@ function operationSpec(operation: ApiOperation) {
|
|||||||
? {
|
? {
|
||||||
401: jsonResponse(
|
401: jsonResponse(
|
||||||
"Authentication required",
|
"Authentication required",
|
||||||
ref(operation.auth || operation.admin ? "UnauthorizedError" : "Error"),
|
ref("Error"),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
...((operation.method === "post" && operation.path.startsWith("/auth/")) || ((operation.auth || operation.admin) && operation.method !== "get")
|
||||||
|
? { 403: jsonResponse("Invalid request origin", ref("Error")) }
|
||||||
|
: {}),
|
||||||
...(operation.path === "/user/tracks" || (operation.path.startsWith("/admin/") && (operation.method === "patch" || operation.method === "delete"))
|
...(operation.path === "/user/tracks" || (operation.path.startsWith("/admin/") && (operation.method === "patch" || operation.method === "delete"))
|
||||||
? { 404: jsonResponse("Resource not found", ref("NotFound")) }
|
? { 404: jsonResponse("Resource not found", ref("NotFound")) }
|
||||||
: {}),
|
: {}),
|
||||||
@@ -166,7 +170,7 @@ export const openApiDocument = {
|
|||||||
openapi: "3.1.0",
|
openapi: "3.1.0",
|
||||||
info: { title: "MusicBackend", version: "v2" },
|
info: { title: "MusicBackend", version: "v2" },
|
||||||
servers: [{ url: "/api", description: "Nuxt API routes" }],
|
servers: [{ url: "/api", description: "Nuxt API routes" }],
|
||||||
tags: ["Auth", "Artist", "Album", "Genre", "Track", "All", "Search", "User", "Admin"].map((name) => ({ name })),
|
tags: ["Health", "Auth", "Artist", "Album", "Genre", "Track", "All", "Search", "User", "Admin"].map((name) => ({ name })),
|
||||||
paths,
|
paths,
|
||||||
components: {
|
components: {
|
||||||
securitySchemes: {
|
securitySchemes: {
|
||||||
@@ -175,15 +179,7 @@ export const openApiDocument = {
|
|||||||
},
|
},
|
||||||
schemas: {
|
schemas: {
|
||||||
Error: { type: "object", required: ["message"], properties: { message: { type: "string" } } },
|
Error: { type: "object", required: ["message"], properties: { message: { type: "string" } } },
|
||||||
UnauthorizedError: {
|
Health: { type: "object", required: ["status"], properties: { status: { type: "string", const: "ok" } } },
|
||||||
type: "object",
|
|
||||||
required: ["statusCode", "statusMessage", "data"],
|
|
||||||
properties: {
|
|
||||||
statusCode: { type: "integer", enum: [401] },
|
|
||||||
statusMessage: { type: "string", enum: ["Unauthorized"] },
|
|
||||||
data: ref("Error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InvalidRequest: { oneOf: [ref("Error"), ref("H3Error")] },
|
InvalidRequest: { oneOf: [ref("Error"), ref("H3Error")] },
|
||||||
H3Error: {
|
H3Error: {
|
||||||
type: "object",
|
type: "object",
|
||||||
|
|||||||
Reference in new issue
Block a user