From 85d20e034a94a6b56a163a7173ba6045f7201c46 Mon Sep 17 00:00:00 2001 From: Kilian Hofmann Date: Tue, 23 Jul 2024 01:12:05 +0200 Subject: [PATCH] Better Errors --- exam/api/Login/Login.php | 17 +- exam/api/Logout/Logout.php | 2 + exam/api/Post/Post.php | 39 +-- exam/api/Posts/Posts.php | 26 ++ exam/api/Register/Register.php | 23 +- exam/api/User/User.php | 31 +- exam/api/Users/Users.php | 3 + exam/api/docs/api.yaml | 543 ++++++++++++++++------------- exam/api/docs/index.html | 116 +++--- exam/classes/ApiError/ApiError.php | 61 ++++ exam/classes/Auth/AdminAuth.php | 6 +- exam/classes/Auth/Auth.php | 4 +- exam/classes/Auth/OptAuth.php | 2 +- exam/classes/Models/Post/Post.php | 9 +- exam/classes/Models/User/User.php | 33 +- exam/classes/Response/Response.php | 7 + exam/routes/routes.php | 7 +- exam/utils/helpers.php | 28 +- 18 files changed, 567 insertions(+), 390 deletions(-) create mode 100644 exam/classes/ApiError/ApiError.php diff --git a/exam/api/Login/Login.php b/exam/api/Login/Login.php index 70e979b..fdcd279 100644 --- a/exam/api/Login/Login.php +++ b/exam/api/Login/Login.php @@ -4,6 +4,7 @@ namespace Api\Login; use Exception; use Khofmann\Api\Api; +use Khofmann\ApiError\ApiError; use Khofmann\Input\Input; use Khofmann\Response\Response; use Khofmann\Models\User\User; @@ -12,21 +13,27 @@ class Login extends Api { public function post(): void { + // Fetch all required inputs. + // Throw 400 error if a required one is missing. + $missing = []; $email = Input::post("email"); - if (empty($email)) throw new Exception("Missing email", 400); $password = Input::post("password"); - if (empty($password)) throw new Exception("Missing password", 400); + if (empty($email)) array_push($missing, "email"); + if (empty($password)) array_push($missing, "password"); + if (count($missing) > 0) throw ApiError::missingField($missing); + // Try and log in user. + // Throw errors according to situation. try { Response::json(User::logIn($email, $password)); } catch (Exception $err) { switch ($err->getMessage()) { case "Failed": - throw new Exception("Login failed", 500); + throw ApiError::failed("Login failed"); case "NotFound": - throw new Exception("User not found", 404); + throw ApiError::notFound("user"); case "Invalid": - throw new Exception("Invalid username or password", 401); + throw ApiError::unauthorized("Invalid username or password"); default: throw $err; } diff --git a/exam/api/Logout/Logout.php b/exam/api/Logout/Logout.php index 8d087f2..6b0c459 100644 --- a/exam/api/Logout/Logout.php +++ b/exam/api/Logout/Logout.php @@ -11,8 +11,10 @@ class Logout extends Api { public function post(): void { + // Get user auth token. $token = Request::token(); + // Log out. Response::json(User::getByToken($token)->logOut()); } } diff --git a/exam/api/Post/Post.php b/exam/api/Post/Post.php index dc12819..c24d23a 100644 --- a/exam/api/Post/Post.php +++ b/exam/api/Post/Post.php @@ -4,6 +4,7 @@ namespace Api\Post; use Exception; use Khofmann\Api\Api; +use Khofmann\ApiError\ApiError; use Khofmann\Input\Input; use Khofmann\Models\Post\Post as MPost; use Khofmann\Models\User\User; @@ -12,40 +13,29 @@ use Khofmann\Response\Response; class Post extends Api { - public function post(): void - { - $content = Input::patch("content"); - - $self = User::getByToken(Request::token()); - - try { - Response::json(MPost::create($self, $content)); - } catch (Exception $err) { - switch ($err->getMessage()) { - default: - throw $err; - } - } - } - public function patch($id): void { + // Fetch all inputs. $content = Input::patch("content"); + // Fetch authed user. $self = User::getByToken(Request::token()); - $post = MPost::getByID($id); - - if (!$self->getIsAdmin() && $post->getUser()->getID() !== $self->getID()) throw new Exception("Not Authorized", 401); try { - Response::json(MPost::getByID($id)->update($content)); + // Try fetch the post in question, 404 if not found. + $post = MPost::getByID($id); + + // Throw 400 if we aren't admin but trying to edit another users post. + if (!$self->getIsAdmin() && $post->getUser()->getID() !== $self->getID()) throw ApiError::unauthorized("Not allowed"); + + // Try update. + Response::json($post->update($content)); } catch (Exception $err) { switch ($err->getMessage()) { case "NotFound": - throw new Exception("Post not found", 404); - case "FailedContent": - throw new Exception("Failed to update content", 500); + throw ApiError::notFound("post"); default: + // Due to how the failed field is handled, it's ApiError is inside the models update throw $err; } } @@ -53,12 +43,13 @@ class Post extends Api public function delete($id): void { + // Try delete, 404 if post was not found. try { Response::json(MPost::getByID($id)->delete()); } catch (Exception $err) { switch ($err->getMessage()) { case "NotFound": - throw new Exception("Post not found", 404); + throw ApiError::notFound("post"); default: throw $err; } diff --git a/exam/api/Posts/Posts.php b/exam/api/Posts/Posts.php index d9a701e..b853e2b 100644 --- a/exam/api/Posts/Posts.php +++ b/exam/api/Posts/Posts.php @@ -2,9 +2,12 @@ namespace Api\Posts; +use Exception; use Khofmann\Api\Api; +use Khofmann\ApiError\ApiError; use Khofmann\Input\Input; use Khofmann\Models\Post\Post; +use Khofmann\Models\User\User; use Khofmann\Request\Request; use Khofmann\Response\Response; @@ -12,10 +15,33 @@ class Posts extends Api { public function get() { + // Fetch and constrain all parameters. $page = max(0, intval(Input::get("p", 0))); $limit = constrain(0, 30, intval(Input::get("l", 10))); $authed = Request::token() !== null; + // Return list of posts. Response::json(Post::list($page, $limit, $authed)); } + + public function post(): void + { + // Fetch all required inputs. + // Throw 400 error if a required one is missing. + $content = Input::post("content"); + if (empty($content)) throw ApiError::missingField(["content"]); + + // Get logged in user + $self = User::getByToken(Request::token()); + + // Try to create a new post for logged in user. + try { + Response::json(Post::create($self, $content)); + } catch (Exception $err) { + switch ($err->getMessage()) { + default: + throw $err; + } + } + } } diff --git a/exam/api/Register/Register.php b/exam/api/Register/Register.php index 78242cf..b57e544 100644 --- a/exam/api/Register/Register.php +++ b/exam/api/Register/Register.php @@ -4,6 +4,7 @@ namespace Api\Register; use Exception; use Khofmann\Api\Api; +use Khofmann\ApiError\ApiError; use Khofmann\Input\Input; use Khofmann\Response\Response; use Khofmann\Models\User\User; @@ -12,19 +13,26 @@ class Register extends Api { public function post(): void { + // Fetch all required inputs. + // Throw 400 error if a required one is missing. + $missing = []; $username = Input::post("username"); - if (empty($username)) throw new Exception("Missing username", 400); $email = Input::post("email"); - if (empty($email)) throw new Exception("Missing email", 400); $password = Input::post("password"); - if (empty($password)) throw new Exception("Missing password", 400); + if (empty($username)) array_push($missing, "username"); + if (empty($email)) array_push($missing, "email"); + if (empty($password)) array_push($missing, "password"); + if (count($missing) > 0) throw ApiError::missingField($missing); + // Try and create a new user, 400 if duplicate. try { Response::json(User::create($username, $email, $password)); } catch (Exception $err) { switch ($err->getMessage()) { + case "NotFound": + throw ApiError::failed("Failed to create user"); case "Duplicate": - throw new Exception("A user with this username or email already exists", 400); + throw ApiError::duplicate("user"); default: throw $err; } @@ -33,15 +41,18 @@ class Register extends Api public function patch(): void { + // Fetch all required inputs. + // Throw 400 error if a required one is missing. $code = Input::post("code"); - if (empty($code)) throw new Exception("Missing code", 400); + if (empty($code)) throw ApiError::missingField(["code"]); + // Try and confirm user, 404 if user not found. try { Response::json(User::confirm($code)); } catch (Exception $err) { switch ($err->getMessage()) { case "NotFound": - throw new Exception("User not found", 404); + throw ApiError::notFound("user"); default: throw $err; } diff --git a/exam/api/User/User.php b/exam/api/User/User.php index cd274b9..ea46085 100644 --- a/exam/api/User/User.php +++ b/exam/api/User/User.php @@ -7,18 +7,20 @@ use Khofmann\Models\User\User as MUser; use Khofmann\Input\Input; use Khofmann\Response\Response; use Khofmann\Api\Api; +use Khofmann\ApiError\ApiError; use Khofmann\Request\Request; class User extends Api { public function get($id): void { + // Try and get a user, 404 if not found. try { Response::json(MUser::getByID($id)); } catch (Exception $err) { switch ($err->getMessage()) { case "NotFound": - throw new Exception("User not found", 404); + throw ApiError::notFound("user"); default: throw $err; } @@ -27,23 +29,21 @@ class User extends Api public function patch($id): void { + // Fetch all inputs. $username = Input::patch("username"); $password = Input::patch("password"); $image = Input::file("image"); + // Try and update user. + // Throw errors according to situation. try { Response::json(MUser::getByID($id)->update($username, $password, $image)); } catch (Exception $err) { switch ($err->getMessage()) { case "NotFound": - throw new Exception("User not found", 404); - case "FailedUsername": - throw new Exception("Failed to update username", 500); - case "FailedPassword": - throw new Exception("Failed to update password", 500); - case "FailedImage": - throw new Exception("Failed to update image", 500); + throw ApiError::notFound("user"); default: + // Due to how the failed field is handled, it's ApiError is inside the models update throw $err; } } @@ -51,24 +51,22 @@ class User extends Api public function patchSelf(): void { + // Fetch all inputs. $token = Request::token(); $username = Input::patch("username"); $password = Input::patch("password"); $image = Input::file("image"); + // Try and update user. + // Throw errors according to situation. try { Response::json(MUser::getByToken($token)->update($username, $password, $image)); } catch (Exception $err) { switch ($err->getMessage()) { case "NotFound": - throw new Exception("User not found", 404); - case "FailedUsername": - throw new Exception("Failed to update username", 500); - case "FailedPassword": - throw new Exception("Failed to update password", 500); - case "FailedImage": - throw new Exception("Failed to update image", 500); + throw ApiError::notFound("user"); default: + // Due to how the failed field is handled, it's ApiError is inside the models update throw $err; } } @@ -76,12 +74,13 @@ class User extends Api public function delete($id): void { + // Try to delete user, 404 if not found. try { Response::json(MUser::getByID($id)->delete()); } catch (Exception $err) { switch ($err->getMessage()) { case "NotFound": - throw new Exception("User not found", 404); + throw ApiError::notFound("user"); default: throw $err; } diff --git a/exam/api/Users/Users.php b/exam/api/Users/Users.php index 7f49e1c..1020cb2 100644 --- a/exam/api/Users/Users.php +++ b/exam/api/Users/Users.php @@ -11,8 +11,11 @@ class Users extends Api { public function get() { + // Fetch and constrain all parameters. $page = max(0, intval(Input::get("p", 0))); $limit = constrain(0, 30, intval(Input::get("l", 10))); + + // Return list of users. Response::json(User::list($page, $limit)); } } diff --git a/exam/api/docs/api.yaml b/exam/api/docs/api.yaml index 0098514..78069fc 100644 --- a/exam/api/docs/api.yaml +++ b/exam/api/docs/api.yaml @@ -29,37 +29,42 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/MissingFieldResponse" examples: Missing fields: - value: { "message": "Missing email" } + value: + { "code": "MissingField", "fields": ["email", "password"] } 401: description: Invalid credentials. content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/UnauthorizedResponse" examples: Invalid username or password: - value: { "message": "Invalid username or password" } + value: + { + "code": "Unauthorized", + "message": "Invalid username or password", + } 404: description: User not found. content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/NotFoundResponse" examples: User not found: - value: { "message": "User not found" } + value: { "code": "NotFound", "entity": "user" } 500: description: Failed. content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/FailedResponse" examples: Failed: - value: { "message": "Login failed" } + value: { "code": "Failed", "message": "Login failed" } tags: - Login/Logout /logout: @@ -80,221 +85,6 @@ paths: value: true tags: - Login/Logout - /register: - post: - summary: Register - description: Register a new user - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/RegisterRequest" - responses: - 200: - description: Success - content: - application/json: - schema: - $ref: "#/components/schemas/UserResponse" - 400: - description: Missing fields or duplicate - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" - examples: - Missing fields: - value: { "message": "Missing email" } - Duplicate: - value: - { - "message": "A user with this username or email already exists", - } - tags: - - Register - patch: - summary: Confirm register - description: Confirm a registration - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/ConfirmRequest" - responses: - 200: - description: Success - content: - application/json: - schema: - $ref: "#/components/schemas/BooleanResponse" - examples: - Success: - value: true - 400: - description: Missing fields - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" - examples: - Missing fields: - value: { "message": "Missing code" } - 404: - description: User not found - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" - examples: - User not found: - value: { "message": "User not found" } - tags: - - Register - /users: - get: - summary: List users - description: List all users. - security: - - BasicAuth: [] - parameters: - - in: query - name: p - schema: - type: integer - minimum: 0 - default: 0 - description: Current page. - - in: query - name: l - schema: - type: integer - minimum: 0 - maximum: 30 - default: 10 - description: The number of items to return. - responses: - 200: - description: Success - content: - application/json: - schema: - $ref: "#/components/schemas/UserListResponse" - tags: - - User - /user/{id}: - get: - summary: Get user - description: Get user by ID. - security: - - BasicAuth: [isAdmin] - parameters: - - name: id - in: path - description: User ID - required: true - schema: - type: integer - format: int14 - responses: - 200: - description: Success. - content: - application/json: - schema: - $ref: "#/components/schemas/UserResponse" - 404: - description: User not found. - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" - examples: - User not found: - value: { "message": "User not found" } - tags: - - User - patch: - summary: Update user - description: - Update user with ID. Fields are updated in order username, password, image. If one fails, subsequent are not updated.
- Use special ID self to update logged in user.
- Requires logged in user to have admin permissions for any ID other than self. - security: - - BasicAuth: [] - - BasicAuth: [isAdmin] - parameters: - - name: id - in: path - description: User ID - required: true - schema: - type: integer - format: int14 - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/UserUpdateRequest" - responses: - 200: - description: Success. - content: - application/json: - schema: - $ref: "#/components/schemas/UserResponse" - 404: - description: User not found. - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" - examples: - User not found: - value: { "message": "User not found" } - 500: - description: Update failed. - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" - examples: - Failed username: - value: { "message": "Failed to update username" } - tags: - - User - delete: - summary: Delete user - description: Delete user with ID. - security: - - BasicAuth: [isAdmin] - parameters: - - name: id - in: path - description: User ID - required: true - schema: - type: integer - format: int14 - responses: - 200: - description: Success. - content: - application/json: - schema: - $ref: "#/components/schemas/UserResponse" - 404: - description: User not found. - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" - examples: - User not found: - value: { "message": "User not found" } - tags: - - User /posts: get: summary: List posts @@ -404,16 +194,16 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/MissingFieldResponse" examples: Missing fields: - value: { "message": "Missing content" } + value: { "code": "MissingField", "fields": ["content"] } tags: - Post /post/{id}: patch: summary: Update post - description: Update post with ID.
+ description: Update post with ID.
Requires logged in user to have admin permissions for posts not made by them. security: - BasicAuth: [] @@ -438,24 +228,33 @@ paths: application/json: schema: $ref: "#/components/schemas/PostResponse" + 401: + description: Not allowed. + content: + application/json: + schema: + $ref: "#/components/schemas/UnauthorizedResponse" + examples: + Not allowed: + value: { "code": "Unauthorized", "message": "Not allowed" } 404: description: Post not found. content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/NotFoundResponse" examples: - User not found: - value: { "message": "Post not found" } + Post not found: + value: { "code": "NotFound", "entity": "post" } 500: description: Update failed. content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/FailedUpdateResponse" examples: Failed: - value: { "message": "Failed to update post" } + value: { "code": "FailedUpdate", "fields": ["content"] } tags: - Post delete: @@ -483,12 +282,242 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/ErrorResponse" + $ref: "#/components/schemas/NotFoundResponse" examples: Post not found: - value: { "message": "Post not found" } + value: { "code": "NotFound", "entity": "post" } tags: - Post + /register: + post: + summary: Register + description: Register a new user. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/RegisterRequest" + responses: + 200: + description: Success. + content: + application/json: + schema: + $ref: "#/components/schemas/UserResponse" + 400: + description: Missing fields or duplicate. + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/MissingFieldResponse" + - $ref: "#/components/schemas/DuplicateResponse" + examples: + Missing fields: + value: + { + "code": "MissingField", + "fields": ["username", "email", "password"], + } + Duplicate: + value: { "code": "Duplicate", "entity": "user" } + 404: + description: Failed to create + content: + application/json: + schema: + $ref: "#/components/schemas/FailedResponse" + examples: + Failed to create: + value: + { "code": "Failed", "message": "Failed to create user" } + tags: + - Register + patch: + summary: Confirm register + description: Confirm a registration. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ConfirmRequest" + responses: + 200: + description: Success. + content: + application/json: + schema: + $ref: "#/components/schemas/UserResponse" + 400: + description: Missing fields. + content: + application/json: + schema: + $ref: "#/components/schemas/MissingFieldResponse" + examples: + Missing fields: + value: { "code": "MissingField", "fields": ["code"] } + 404: + description: User not found. + content: + application/json: + schema: + $ref: "#/components/schemas/NotFoundResponse" + examples: + User not found: + value: { "code": "NotFound", "entity": "user" } + tags: + - Register + /users: + get: + summary: List users + description: List all users. + security: + - BasicAuth: [] + parameters: + - in: query + name: p + schema: + type: integer + minimum: 0 + default: 0 + description: Current page. + - in: query + name: l + schema: + type: integer + minimum: 0 + maximum: 30 + default: 10 + description: The number of items to return. + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/UserListResponse" + tags: + - User + + /user/{id}: + get: + summary: Get user + description: Get user by ID. + security: + - BasicAuth: [isAdmin] + parameters: + - name: id + in: path + description: User ID + required: true + schema: + type: integer + format: int14 + responses: + 200: + description: Success. + content: + application/json: + schema: + $ref: "#/components/schemas/UserResponse" + 404: + description: User not found. + content: + application/json: + schema: + $ref: "#/components/schemas/NotFoundResponse" + examples: + User not found: + value: { "code": "NotFound", "entity": "user" } + tags: + - User + patch: + summary: Update user + description: Update user with ID.
+ Use special ID self to update logged in user.
+ Requires logged in user to have admin permissions for any ID other than self. + security: + - BasicAuth: [] + - BasicAuth: [isAdmin] + parameters: + - name: id + in: path + description: User ID + required: true + schema: + type: integer + format: int14 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UserUpdateRequest" + responses: + 200: + description: Success. + content: + application/json: + schema: + $ref: "#/components/schemas/UserResponse" + 404: + description: User not found. + content: + application/json: + schema: + $ref: "#/components/schemas/NotFoundResponse" + examples: + User not found: + value: { "code": "NotFound", "entity": "username" } + 500: + description: Update failed. + content: + application/json: + schema: + $ref: "#/components/schemas/FailedUpdateResponse" + examples: + Failed username: + value: + { + "code": "FailedUpdate", + "fields": ["username", "email", "password"], + } + tags: + - User + delete: + summary: Delete user + description: Delete user with ID. + security: + - BasicAuth: [isAdmin] + parameters: + - name: id + in: path + description: User ID + required: true + schema: + type: integer + format: int14 + responses: + 200: + description: Success. + content: + application/json: + schema: + $ref: "#/components/schemas/UserResponse" + 404: + description: User not found. + content: + application/json: + schema: + $ref: "#/components/schemas/NotFoundResponse" + examples: + User not found: + value: { "code": "NotFound", "entity": "user" } + tags: + - User + externalDocs: url: https://khofmann.userpage.fu-berlin.de/phpCourse/exam/api/docs/ security: [] @@ -498,6 +527,52 @@ components: schemas: BooleanResponse: type: boolean + MissingFieldResponse: + type: object + properties: + code: + type: MissingField + fields: + type: array + items: + type: string + NotFoundResponse: + type: object + properties: + code: + type: NotFound + entity: + type: string + UnauthorizedResponse: + type: object + properties: + code: + type: Unauthorized + message: + type: string + FailedResponse: + type: object + properties: + code: + type: Failed + message: + type: string + DuplicateResponse: + type: object + properties: + code: + type: Duplicate + entity: + type: string + FailedUpdateResponse: + type: object + properties: + code: + type: FailedUpdate + fields: + type: array + items: + type: string ErrorResponse: type: object properties: @@ -635,6 +710,6 @@ components: in: header tags: - name: Login/Logout + - name: Post - name: Register - name: User - - name: Post diff --git a/exam/api/docs/index.html b/exam/api/docs/index.html index 87ee3ad..87d2bc1 100644 --- a/exam/api/docs/index.html +++ b/exam/api/docs/index.html @@ -327,10 +327,10 @@ data-styled.g111[id="sc-eowDPD"]{content:"jcAXWA,"}/*!sc*/ .gsBSOU:focus{box-shadow:inset 0 2px 2px rgba(0, 0, 0, 0.45),0 2px 0 rgba(128, 128, 128, 0.25);}/*!sc*/ data-styled.g112[id="sc-iAlELC"]{content:"gsBSOU,"}/*!sc*/ .kpMtuJ{font-size:0.929em;line-height:20px;background-color:#186FAF;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/ -.eUIOSr{font-size:0.929em;line-height:20px;background-color:#bf581d;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/ .ffmPnn{font-size:0.929em;line-height:20px;background-color:#2F8132;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/ +.eUIOSr{font-size:0.929em;line-height:20px;background-color:#bf581d;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/ .ByFMv{font-size:0.929em;line-height:20px;background-color:#cc3333;color:#ffffff;padding:3px 10px;text-transform:uppercase;font-family:Montserrat,sans-serif;margin:0;}/*!sc*/ -data-styled.g113[id="sc-oeqTF"]{content:"kpMtuJ,eUIOSr,ffmPnn,ByFMv,"}/*!sc*/ +data-styled.g113[id="sc-oeqTF"]{content:"kpMtuJ,ffmPnn,eUIOSr,ByFMv,"}/*!sc*/ .bFiOkX{position:absolute;width:100%;z-index:100;background:#fafafa;color:#263238;box-sizing:border-box;box-shadow:0 0 6px rgba(0, 0, 0, 0.33);overflow:hidden;border-bottom-left-radius:4px;border-bottom-right-radius:4px;transition:all 0.25s ease;visibility:hidden;transform:translateY(-50%) scaleY(0);}/*!sc*/ data-styled.g114[id="sc-ezTrPE"]{content:"bFiOkX,"}/*!sc*/ .hdRKqQ{padding:10px;}/*!sc*/ @@ -384,7 +384,7 @@ data-styled.g137[id="sc-kvXgyf"]{content:"fBvPoH,"}/*!sc*/ -

Log out user.

Authorizations:
BasicAuth

Responses

Response samples

Content type
application/json
true

Register

Register

Register a new user

-
Request Body schema: application/json
required
username
required
string
email
required
string
password
required
string

Responses

Request samples

Content type
application/json
{
  • "username": "string",
  • "email": "string",
  • "password": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

Confirm register

Confirm a registration

-
Request Body schema: application/json
required
code
required
string <uuid4>

Responses

Request samples

Content type
application/json
{
  • "code": "string"
}

Response samples

Content type
application/json
true

User

List users

Response samples

Content type
application/json
true

Post

List posts

List all posts, return full user data if authenticated.

+
Authorizations:
NoneBasicAuth
query Parameters
p
integer >= 0
Default: 0

Current page.

+
l
integer [ 0 .. 30 ]
Default: 10

The number of items to return.

+

Responses

Response samples

Content type
application/json
Example
{
  • "pages": 0,
  • "data": [
    ]
}

New post

Create a new post.

+
Authorizations:
BasicAuth
Request Body schema: application/json
required
content
required
string

Responses

Request samples

Content type
application/json
{
  • "content": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "user": {
    },
  • "content": "string",
  • "postedAt": {
    }
}

Update post

Update post with ID.
Requires logged in user to have admin permissions for posts not made by them.

+
Authorizations:
BasicAuthBasicAuth
path Parameters
id
required
integer <int14>

Post ID

+
Request Body schema: application/json
content
string

Responses

Request samples

Content type
application/json
{
  • "content": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "user": {
    },
  • "content": "string",
  • "postedAt": {
    }
}

Delete post

Delete post with ID.

+
Authorizations:
BasicAuth
path Parameters
id
required
integer <int14>

Post ID

+

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "user": {
    },
  • "content": "string",
  • "postedAt": {
    }
}

Register

Register

Register a new user.

+
Request Body schema: application/json
required
username
required
string
email
required
string
password
required
string

Responses

Request samples

Content type
application/json
{
  • "username": "string",
  • "email": "string",
  • "password": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

Confirm register

Confirm a registration.

+
Request Body schema: application/json
required
code
required
string <uuid4>

Responses

Request samples

Content type
application/json
{
  • "code": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

User

List users

List all users.

Authorizations:
BasicAuth
query Parameters
p
integer >= 0
Default: 0

Current page.

@@ -442,7 +478,7 @@ data-styled.g137[id="sc-kvXgyf"]{content:"fBvPoH,"}/*!sc*/ " class="sc-euGpHm sc-exayXG fwfkcU jYGAQp">

The number of items to return.

Responses

Response samples

Content type
application/json
{
  • "pages": 0,
  • "data": [
    ]
}

Get user

Response samples

Content type
application/json
{
  • "pages": 0,
  • "data": [
    ]
}

Get user

Get user by ID.

Authorizations:
BasicAuth
path Parameters
id
required
integer <int14>

User ID

@@ -450,8 +486,8 @@ data-styled.g137[id="sc-kvXgyf"]{content:"fBvPoH,"}/*!sc*/ " class="sc-euGpHm sc-exayXG fwfkcU kqJXdD sc-dHrNzZ dRdjww">

Success.

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

Update user

Update user with ID. Fields are updated in order username, password, image. If one fails, subsequent are not updated.
Use special ID self to update logged in user.
Requires logged in user to have admin permissions for any ID other than self.

+

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

Update user

Update user with ID.
Use special ID self to update logged in user.
Requires logged in user to have admin permissions for any ID other than self.

Authorizations:
BasicAuthBasicAuth
path Parameters
id
required
integer <int14>

User ID

Request Body schema: application/json
username
string
password
string
image
string <binary>

Responses

Request samples

Content type
application/json
{
  • "username": "string",
  • "password": "string",
  • "image": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

Delete user

Request samples

Content type
application/json
{
  • "username": "string",
  • "password": "string",
  • "image": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

Delete user

Delete user with ID.

Authorizations:
BasicAuth
path Parameters
id
required
integer <int14>

User ID

@@ -468,41 +504,9 @@ data-styled.g137[id="sc-kvXgyf"]{content:"fBvPoH,"}/*!sc*/ " class="sc-euGpHm sc-exayXG fwfkcU kqJXdD sc-dHrNzZ dRdjww">

Success.

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}

Post

List posts

List all posts, return full user data if authenticated.

-
Authorizations:
NoneBasicAuth
query Parameters
p
integer >= 0
Default: 0

Current page.

-
l
integer [ 0 .. 30 ]
Default: 10

The number of items to return.

-

Responses

Response samples

Content type
application/json
Example
{
  • "pages": 0,
  • "data": [
    ]
}

New post

Create a new post.

-
Authorizations:
BasicAuth
Request Body schema: application/json
required
content
required
string

Responses

Request samples

Content type
application/json
{
  • "content": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "user": {
    },
  • "content": "string",
  • "postedAt": {
    }
}

Update post

Update post with ID.
Requires logged in user to have admin permissions for posts not made by them.

-
Authorizations:
BasicAuthBasicAuth
path Parameters
id
required
integer <int14>

Post ID

-
Request Body schema: application/json
content
string

Responses

Request samples

Content type
application/json
{
  • "content": "string"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "user": {
    },
  • "content": "string",
  • "postedAt": {
    }
}

Delete post

Delete post with ID.

-
Authorizations:
BasicAuth
path Parameters
id
required
integer <int14>

Post ID

-

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "user": {
    },
  • "content": "string",
  • "postedAt": {
    }
}
+

Response samples

Content type
application/json
{
  • "id": 0,
  • "username": "string",
  • "status": 0,
  • "email": "string",
  • "image": "string",
  • "isAdmin": true,
  • "memberSince": {
    },
  • "postCount": 0
}