From b2e5d70d80152ad819203bada30f7d4723fab9e8 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 3 Aug 2024 12:40:50 +0300 Subject: [PATCH 1/6] POST `/users` success response is 201, not 200 --- openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 80097fb..51bf494 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -812,7 +812,7 @@ paths: requestBody: $ref: "#/components/requestBodies/User" responses: - 200: + 201: description: The created user content: application/json: From 0d1b956409be0e9f8fb7eaddfe1cb579c5286d94 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 3 Aug 2024 12:41:32 +0300 Subject: [PATCH 2/6] In addition to POST, also throw 409 in put & patch when username taken --- src/resource/User.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/resource/User.ts b/src/resource/User.ts index d0483d8..ff8204d 100644 --- a/src/resource/User.ts +++ b/src/resource/User.ts @@ -208,6 +208,9 @@ namespace User { const scopes = this.extract.scopes(req.body); const disabled = this.extract.disabled(req.body); + if (!this.library.repositories.users.usernameAvailable(username)) + return new ErrorResponse(409, `The username "${username}" is already taken.`); + user.username = username; user.password = password; user.scopes = scopes; @@ -222,7 +225,11 @@ namespace User { if (user === null) return User.Controller.notFound(); this.validateBodyType(req.body); - if ("username" in req.body) user.username = this.extract.username(req.body); + if ("username" in req.body) { + user.username = this.extract.username(req.body); + if (!this.library.repositories.users.usernameAvailable(user.username)) + return new ErrorResponse(409, `The username "${user.username}" is already taken.`); + } if ("password" in req.body) user.password = await this.extract.password(req.body); if ("scopes" in req.body) user.scopes = this.extract.scopes(req.body); if ("disabled" in req.body) user.disabled = this.extract.disabled(req.body); From fd8a1fca7bd51081aef62b2da3dc264e486d0932 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 3 Aug 2024 12:41:44 +0300 Subject: [PATCH 3/6] document users write 409 & 422 --- openapi.yaml | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 51bf494..3f1bac5 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -822,6 +822,25 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 409: + description: Username already in use + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + error: + type: object + properties: + fields: + type: object + properties: + username: + type: string + 422: + $ref: "#/components/responses/ValidationError" delete: tags: [Users] summary: Delete All Users @@ -927,6 +946,25 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 409: + description: Username already in use + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + error: + type: object + properties: + fields: + type: object + properties: + username: + type: string + 422: + $ref: "#/components/responses/ValidationError" patch: tags: [Users] summary: Update User @@ -967,6 +1005,25 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 409: + description: Username already in use + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorResponse" + - type: object + properties: + error: + type: object + properties: + fields: + type: object + properties: + username: + type: string + 422: + $ref: "#/components/responses/ValidationError" /tokens: get: From affc4b5687382cec9325c51440d3e3ffaf8d111c Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 3 Aug 2024 13:30:03 +0300 Subject: [PATCH 4/6] document 422 responses for token write operations --- openapi.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 3f1bac5..8a43352 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1153,6 +1153,8 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 422: + $ref: "#/components/responses/ValidationError" delete: tags: [Tokens] summary: Delete All Tokens @@ -1285,6 +1287,8 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 422: + $ref: "#/components/responses/ValidationError" patch: tags: [Tokens] summary: Update Token @@ -1333,6 +1337,8 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 422: + $ref: "#/components/responses/ValidationError" /playlists: get: From 0e227c31c12b617bd1318274b671001e4ddba01f Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 3 Aug 2024 13:39:45 +0300 Subject: [PATCH 5/6] use 502 Bad Gateway instead of 503 Service Unavailable for proxy errors --- openapi.yaml | 2 +- src/response/ProxyResponse.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 8a43352..b05af02 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -389,7 +389,7 @@ paths: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 503: + 502: description: Failed to proxy the artist's external image content: application/json: diff --git a/src/response/ProxyResponse.ts b/src/response/ProxyResponse.ts index d7f9a3e..684fa7a 100644 --- a/src/response/ProxyResponse.ts +++ b/src/response/ProxyResponse.ts @@ -33,6 +33,6 @@ export default class ProxyResponse extends ApiResponse { } private proxyError(res: Response) { - return new ErrorResponse(503, `Failed to proxy URL "${this.url}": got ${res.status} ${res.headers.get("content-type") ?? "(no content-type)"}`); + return new ErrorResponse(502, `Failed to proxy URL "${this.url}": got ${res.status} ${res.headers.get("content-type") ?? "(no content-type)"}`); } } From 4d89578fabf41efc610a29d24cb8029acc081c78 Mon Sep 17 00:00:00 2001 From: Zefir Kirilov Date: Sat, 3 Aug 2024 13:40:06 +0300 Subject: [PATCH 6/6] order OpenAPI response status codes in ascending order --- openapi.yaml | 172 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 71 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index b05af02..c2f3c95 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -241,16 +241,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Artist" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested artist could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" /artists/{id}/albums: get: @@ -306,6 +306,12 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 404: + description: The requested artist could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" /artists/{id}/tracks: get: @@ -361,6 +367,12 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 404: + description: The requested artist could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" /artists/{id}/image: get: @@ -383,8 +395,12 @@ paths: description: The actual image binary of this artist, proxied from the artist's external image URL. content: image/*: {} + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: - description: The artist does not have an associated image + description: The requested artist could not be found or the artist does not have an associated image content: application/json: schema: @@ -395,10 +411,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" /albums: get: @@ -472,16 +484,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Album" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested album could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" /albums/{id}/tracks: get: @@ -538,6 +550,12 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 404: + description: The requested album could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" /albums/{id}/image: get: @@ -561,16 +579,16 @@ paths: description: The actual image binary for this album content: image/*: {} + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: - description: The album does not have an associated image + description: The requested album could not be found or the album does not have an associated image content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" /tracks: get: @@ -663,16 +681,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Track" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested track could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" /tracks/{id}/audio: get: @@ -720,6 +738,12 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 404: + description: The requested track could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" /tracks/{id}/image: get: @@ -743,16 +767,16 @@ paths: description: The actual image binary for this track content: image/*: {} + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: - description: The track does not have an associated image + description: The requested track could not be found or the track does not have an associated image content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" /users: get: @@ -880,16 +904,16 @@ paths: application/json: schema: $ref: "#/components/schemas/User" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested user could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" delete: tags: [Users] summary: Delete User @@ -912,6 +936,12 @@ paths: $ref: "#/components/responses/Unauthorised" 403: $ref: "#/components/responses/Forbidden" + 404: + description: The requested user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" put: tags: [Users] summary: Replace User @@ -936,16 +966,16 @@ paths: application/json: schema: $ref: "#/components/schemas/User" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested user could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" 409: description: Username already in use content: @@ -995,16 +1025,16 @@ paths: application/json: schema: $ref: "#/components/schemas/User" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested user could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" 409: description: Username already in use content: @@ -1197,16 +1227,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Token" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested token could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" delete: tags: [Tokens] summary: Delete Token @@ -1227,16 +1257,16 @@ paths: responses: 204: description: The requested token was deleted successfully + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested token could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" put: tags: [Tokens] summary: Replace Token @@ -1277,16 +1307,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Token" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested token could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" 422: $ref: "#/components/responses/ValidationError" patch: @@ -1327,16 +1357,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Token" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: The requested token could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" 422: $ref: "#/components/responses/ValidationError" @@ -1494,16 +1524,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Playlist" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: Playlist not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" delete: tags: [Playlists] summary: Delete Playlist @@ -1522,16 +1552,16 @@ paths: responses: 204: description: Playlist deleted successfully + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: Playlist not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" put: tags: [Playlists] summary: Replace Playlist @@ -1564,16 +1594,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Playlist" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: Playlist not found, or some of the requested tracks could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" 422: $ref: "#/components/responses/ValidationError" patch: @@ -1603,16 +1633,16 @@ paths: application/json: schema: $ref: "#/components/schemas/Playlist" + 401: + $ref: "#/components/responses/Unauthorised" + 403: + $ref: "#/components/responses/Forbidden" 404: description: Playlist not found, or some of the requested tracks could not be found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - 401: - $ref: "#/components/responses/Unauthorised" - 403: - $ref: "#/components/responses/Forbidden" 422: $ref: "#/components/responses/ValidationError"