openapi: 3.0.3 info: title: SJW FILKOM API Specification version: 1.0.0 contact: name: I Putu Natha Kusuma servers: - url: https://api.sjw.nathakusuma.com/v1 description: Production server - url: http://localhost:8080/v1 description: Local server tags: - name: auth description: Authentication & Authorization - name: hopes description: Hope Corner - name: whispers description: Whisper Wall - name: admin description: Admin only endpoints components: securitySchemes: JwtAuth: type: http description: Authorization and authentication based on JSON Web Token (JWT) scheme: bearer bearerFormat: JWT schemas: ApiResponse: type: object properties: message: type: string description: The message of the response data: type: object description: The response data (if any) HopeUser: type: object properties: id: type: string format: uuid description: The UUID of the hope example: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: type: string description: The content of the hope example: This is a hope created_at: type: string format: date-time description: The timestamp when the hope was created in RFC3339 format example: 2006-01-02T15:04:05+07:00 HopeAdmin: allOf: - $ref: '#/components/schemas/HopeUser' - type: object properties: is_approved: type: boolean description: Approval status of the hope example: true updated_at: type: string format: date-time description: The timestamp when the hope was last updated in RFC3339 format example: 2006-02-03T16:05:06+07:00 WhisperUser: allOf: - $ref: '#/components/schemas/HopeUser' WhisperAdmin: allOf: - $ref: '#/components/schemas/HopeAdmin' - type: object properties: is_public: type: boolean description: Visibility status of the whisper example: true User: type: object properties: nim: type: string description: The NIM of the user example: "235150201111000" email: type: string description: The UB email of the user example: natha@student.ub.ac.id full_name: type: string description: The full name of the user example: Natha Kusuma role: type: string description: The role of the user example: admin angkatan: type: integer description: The year of the user's enrollment example: "2023" program_studi: type: string description: The study program of the user example: Teknik Informatika profile_picture: type: string description: The URL of the user's profile picture example: https://siakad.ub.ac.id/dirfoto/foto/foto_2023/235150201111000.jpg parameters: IdPath: name: id in: path description: The UUID of the resource required: true example: 3fa85f64-5717-4562-b3fc-2c963f66afa6 schema: type: string format: uuid CreatedAtPivot: name: created_at_pivot in: query description: The timestamp of the pivot resource in RFC3339 format. required: false example: 2006-01-02T15:04:05+07:00 schema: type: string format: date-time IdPivot: name: id_pivot in: query description: The UUID of the pivot resource. required: false example: 4fa85f64-5717-4562-b3fc-2c963f66afa7 schema: type: string format: uuid Direction: name: direction in: query description: The direction of the fetch. required: false example: next schema: type: string enum: - prev - next Limit: name: limit in: query description: The maximum number of resource to return required: true example: 10 schema: type: integer format: int32 responses: Timeout: description: Request timeout content: application/json: schema: $ref: '#/components/schemas/ApiResponse' example: message: Request timed out data: {} RateLimitExceeded: description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/ApiResponse' example: message: Rate limit exceeded. Please try again later. data: {} InvalidRequestBody: description: Invalid request body content: application/json: schema: $ref: '#/components/schemas/ApiResponse' InvalidCredentials: description: Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ApiResponse' example: message: Invalid username or password data: {} NotFilkomStudent: description: User is not a FILKOM student content: application/json: schema: $ref: '#/components/schemas/ApiResponse' example: message: only for FILKOM students data: fakultas: Fakultas Ilmu Sosial dan Ilmu Politik InternalServerError: description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ApiResponse' HopeCreated: description: Successfully created a new hope content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: type: object properties: id: type: string format: uuid description: The UUID of the created hope example: message: hope created data: id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 HopesRetrieved: description: Successfully retrieved hopes content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/HopeUser' example: message: hopes retrieved data: - id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a hope created_at: 2006-01-02T15:04:05+07:00 - id: abcdef12-3456-7890-abcd-ef1234567890 content: This is another hope created_at: 2004-01-01T14:03:04+07:00 requestBodies: LoginRequest: description: Login request body required: true content: application/json: schema: type: object properties: username: type: string description: Can be either NIM or email password: type: string description: The password of the user required: - username - password examples: withNIM: summary: NIM as username value: username: "235150201111000" password: very-secure-password withEmail: summary: Email as username value: username: natha@student.ub.ac.id password: very-secure-password HopeRequest: description: Create hope request body required: true content: application/json: schema: type: object properties: content: type: string description: The content of the hope required: - content example: content: This is a new hope WhisperRequest: description: Create whisper request body required: true content: application/json: schema: type: object properties: content: type: string description: The content of the whisper is_public: type: boolean description: The visibility status of the whisper required: - content - is_public example: content: This is a new whisper is_public: true paths: /auth/login: post: tags: - auth summary: Login to the system (for admins) requestBody: $ref: '#/components/requestBodies/LoginRequest' responses: 200: description: Successfully logged in content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: allOf: - type: string description: The JWT token - $ref: '#/components/schemas/User' example: message: successfully logged in data: token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMzUxNTAyMDExMTEwMDAiLCJlbWFpbCI6Im5hdGhhQHN0dWRlbnQudWIuYWMuaWQiLCJmdWxsX25hbWUiOiJOYXRoYSBLdXN1bWEiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE1MTYyMzkwMjJ9.0ee45LPBN67SU0XPt-rNLAqLQwJiyVogGw7bu9aOi-Y nim: "235150201111000" email: natha@student.ub.ac.id full_name: Natha Kusuma role: admin angkatan: "2023" program_studi: Teknik Informatika profile_picture: https://siakad.ub.ac.id/dirfoto/foto/foto_2023/235150201111000.jpg 400: $ref: '#/components/responses/InvalidRequestBody' 401: $ref: '#/components/responses/InvalidCredentials' 403: $ref: '#/components/responses/NotFilkomStudent' 429: description: Too many login attempts content: application/json: schema: $ref: '#/components/schemas/ApiResponse' example: message: Too many login attempts. Please try again in 5 minutes. 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /hopes: post: tags: - hopes summary: Create a new hope requestBody: $ref: '#/components/requestBodies/HopeRequest' responses: 201: $ref: '#/components/responses/HopeCreated' 400: $ref: '#/components/responses/InvalidRequestBody' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' get: tags: - hopes summary: Retrieve a list of approved hopes description: |- - Implements lazy load. - It will return only approved hopes. - The result will be sorted by the creation timestamp from latest to oldest. - If either `created_at_pivot`, `id_pivot` or `direction` is present, then all of them must be present. parameters: - $ref: '#/components/parameters/CreatedAtPivot' - $ref: '#/components/parameters/IdPivot' - $ref: '#/components/parameters/Direction' - $ref: '#/components/parameters/Limit' responses: 200: $ref: '#/components/responses/HopesRetrieved' 400: $ref: '#/components/responses/InvalidRequestBody' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /hopes/{id}: get: tags: - hopes summary: Retrieve a specific hope by its ID description: It will return only approved hopes. parameters: - $ref: '#/components/parameters/IdPath' responses: 200: description: Successfully retrieved the hope content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: $ref: '#/components/schemas/HopeUser' example: message: hope retrieved data: id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a hope created_at: 2006-01-02T15:04:05+07:00 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Hope not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /admin/hopes: get: tags: - admin - hopes summary: Retrieve a list of hopes as an admin description: It will return all hopes, including unapproved ones. parameters: - $ref: '#/components/parameters/CreatedAtPivot' - $ref: '#/components/parameters/IdPivot' - $ref: '#/components/parameters/Direction' - $ref: '#/components/parameters/Limit' responses: 200: description: Successfully retrieved hopes content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/HopeAdmin' example: message: hopes retrieved data: - id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a hope is_approved: true created_at: 2006-01-02T15:04:05+07:00 updated_at: 2006-02-02T15:04:05+07:00 - id: abcdef12-3456-7890-abcd-ef1234567890 content: This is another hope is_approved: true created_at: 2004-01-01T14:03:04+07:00 updated_at: 2004-02-01T14:03:04+07:00 - id: 12345678-90ab-cdef-1234-567890abcdef content: This is an unapproved hope is_approved: false created_at: 2002-02-02T13:02:03+07:00 updated_at: 2002-03-02T13:02:03+07:00 400: $ref: '#/components/responses/InvalidRequestBody' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /admin/hopes/{id}: get: tags: - admin - hopes summary: Retrieve a specific hope by its ID as an admin parameters: - $ref: '#/components/parameters/IdPath' responses: 200: description: Successfully retrieved the hope content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: $ref: '#/components/schemas/HopeAdmin' example: message: hope retrieved data: id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a hope is_approved: true created_at: 2006-01-02T15:04:05+07:00 updated_at: 2006-01-02T15:04:05+07:00 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Hope not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' patch: tags: - admin - hopes summary: Update a specific hope by its ID as an admin parameters: - $ref: '#/components/parameters/IdPath' requestBody: required: true content: application/json: schema: type: object properties: content: type: string description: The updated content of the hope is_approved: type: boolean description: The updated approval status of the hope example: content: This is an updated hope is_approved: true responses: 200: description: Successfully updated the hope content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Hope not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' delete: tags: - admin - hopes summary: Delete a specific hope by its ID as an admin parameters: - $ref: '#/components/parameters/IdPath' responses: 200: description: Successfully deleted the hope content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Hope not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /whispers: post: tags: - whispers summary: Create a new whisper requestBody: $ref: '#/components/requestBodies/WhisperRequest' responses: 201: description: Successfully created a new whisper content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: type: object properties: id: type: string format: uuid description: The UUID of the created whisper example: message: whisper created data: id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 400: $ref: '#/components/responses/InvalidRequestBody' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' get: tags: - whispers summary: Retrieve a list of approved whispers description: |- - Implements lazy load. - It will return only approved whispers. - The result will be sorted by the creation timestamp from latest to oldest. - If either `created_at_pivot`, `id_pivot` or `direction` is present, then all of them must be present. parameters: - $ref: '#/components/parameters/CreatedAtPivot' - $ref: '#/components/parameters/IdPivot' - $ref: '#/components/parameters/Direction' - $ref: '#/components/parameters/Limit' responses: 200: description: Successfully retrieved whispers content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/WhisperUser' example: message: whispers retrieved data: - id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a whisper created_at: 2006-01-02T15:04:05+07:00 - id: abcdef12-3456-7890-abcd-ef1234567890 content: This is another whisper created_at: 2004-01-01T14:03:04+07:00 400: $ref: '#/components/responses/InvalidRequestBody' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /whispers/{id}: get: tags: - whispers summary: Retrieve a specific whisper by its ID description: It will return only approved whispers. parameters: - $ref: '#/components/parameters/IdPath' responses: 200: description: Successfully retrieved the whisper content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: $ref: '#/components/schemas/WhisperUser' example: message: whisper retrieved data: id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a whisper created_at: 2006-01-02T15:04:05+07:00 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Whisper not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /admin/whispers: get: tags: - admin - whispers summary: Retrieve a list of whispers as an admin description: It will return all whispers, including unapproved ones. parameters: - $ref: '#/components/parameters/CreatedAtPivot' - $ref: '#/components/parameters/IdPivot' - $ref: '#/components/parameters/Direction' - $ref: '#/components/parameters/Limit' responses: 200: description: Successfully retrieved whispers content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/WhisperAdmin' example: message: whispers retrieved data: - id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a whisper is_approved: true created_at: 2006-01-02T15:04:05+07:00 updated_at: 2006-02-02T15:04:05+07:00 - id: abcdef12-3456-7890-abcd-ef1234567890 content: This is another whisper is_approved: true created_at: 2004-01-01T14:03:04+07:00 updated_at: 2004-02-01T14:03:04+07:00 - id: 12345678-90ab-cdef-1234-567890abcdef content: This is an unapproved whisper is_approved: false created_at: 2002-02-02T13:02:03+07:00 updated_at: 2002-03-02T13:02:03+07:00 400: $ref: '#/components/responses/InvalidRequestBody' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' /admin/whispers/{id}: get: tags: - admin - whispers summary: Retrieve a specific whisper by its ID as an admin parameters: - $ref: '#/components/parameters/IdPath' responses: 200: description: Successfully retrieved the whisper content: application/json: schema: allOf: - $ref: '#/components/schemas/ApiResponse' - type: object properties: data: $ref: '#/components/schemas/WhisperAdmin' example: message: whisper retrieved data: id: 3fa85f64-5717-4562-b3fc-2c963f66afa6 content: This is a whisper is_approved: true created_at: 2006-01-02T15:04:05+07:00 updated_at: 2006-01-02T15:04:05+07:00 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Whisper not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' patch: tags: - admin - whispers summary: Update a specific whisper by its ID as an admin parameters: - $ref: '#/components/parameters/IdPath' requestBody: required: true content: application/json: schema: type: object properties: content: type: string description: The updated content of the whisper is_approved: type: boolean description: The updated approval status of the whisper example: content: This is an updated whisper is_approved: true responses: 200: description: Successfully updated the whisper content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Whisper not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout' delete: tags: - admin - whispers summary: Delete a specific whisper by its ID as an admin parameters: - $ref: '#/components/parameters/IdPath' responses: 200: description: Successfully deleted the whisper content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 400: $ref: '#/components/responses/InvalidRequestBody' 404: description: Whisper not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse' 429: $ref: '#/components/responses/RateLimitExceeded' 500: $ref: '#/components/responses/InternalServerError' 504: $ref: '#/components/responses/Timeout'