lorem_ipsum/docs/backend_endpoints.md
2026-05-23 16:17:57 +02:00

11 KiB

API Specification

This document describes the REST API endpoints for user creation, score submission, and leaderboard access.

Authentification

The password for an account must exclusivly be generated by the backend server and the user is never allowed to change or recover it. If they loose the password, they loose access to the account. This is done, in order to avoid any legal issues or bad consequences for the user as the authentification is never encrypted. (This is a design choice, because the focus of the project is not authentification, but frontend desgin.)

Authentification is done via the headers, that send username and password as plain strings.

Authentication Headers (required)

  • X-Username
  • X-Password

Base URL

/api

1. User

GET

Endpoint

GET /user

Description Authorizes on the server with the header, and returns 201 if successfull or 401 if unauthorized.

Response Status: 201 if authentificated successfully, Status: 401 if authentification failed

POST

Endpoint

POST /user

Request Body

{
  "username": "string"
}

Description Creates a new user with the given username. The backend generates a password automatically (or sets it to "1234"). Does not require authentification.

Response (UserDTO)

{
  "name": "string",
  "password": "string"
}

Error Response (ErrorDTO)

If a user with that name already exists, it should return a 400.

{
  "status": 400,
  "message": "Nutzer mit Name {username} existiert bereits."
}

DELETE

Endpoint

DELETE /user

Description Deletes the user and all the scores submitted by them. The user to delete should be the one who authentificates themselfs in the header.

Response

{
  "message": "User {username} existiert nicht mehr.",
}

GET all users

Endpoint

GET /users

Description Returns all existing users so the frontend can show a list of possible challenge recipients. Requires authentication.

Authentication Headers (required)

  • X-Username
  • X-Password

Response (List<UserListItemDTO>)

[
  {
    "username": "string"
  }
]

Alternative response shape accepted by the frontend:

[
  {
    "name": "string"
  }
]

Status Codes

  • 200 if users were loaded successfully
  • 401 if authentication failed

2. Score

GET

Endpoint

GET /score/{username}

Description Returns all score entries for the specified user. Does not require authentification.

Response List<ScoreDTO>

[
  {
    "username": "string",
    "score": 0,
    "time": 0,
    "text": "string",
    "userWrittenText": "string",
    "place": 0,
  }
]

POST

Endpoint

POST /score

Request Body

{
  "score": 0,
  "time": 0,
  "text": "string",
  "userWrittenText": "string"
}

Description Submits a new score entry for a user. The score is a float (the higher, the better). If two scores are the same, the entity with the lower time is better. If time is also the same, the first entity submitted is better. In race-conditions, we don't care.

Response (ScoreDTO) The response should return the created object. It should give the place, the score lands on.

{
  "username": "string",
  "id": 0,
  "score": 0,
  "time": 0,
  "text": "string",
  "userWrittenText": "string",
  "place": 0,
}

DELETE

Endpoint

DELETE /score/{id}

Description Deletes a score with the given id. Only the user that submitted the score can delete it. If the score does not exist, the response should return successfully, if the user is authenticated. Otherwise, it should return a 401.

Response

{
  "message": "Score mit Id {Id} existiert nicht mehr.",
}

3. Get Leaderboard

Endpoint

GET /leaderboard?offset={offset}&limit={limit}

Query Parameters - offset (number): Starting position - limit (number): Number of results to return

Description Returns leaderboard entries ordered by: 1. Score (descending) 2. Time (ascending) 3. Date of submition (ascending). Does not require authentification.

Response (List<ScoreDTO>) Returns a list of the same objects submitted via /submitScore.

[
  {
    "username": "string",
    "id": 0,
    "score": 0,
    "time": 0,
    "text": "string",
    "userWrittenText": "string",
    "place": 0,
  }
]

4. Messages / Challenges

Messages are used for user-to-user challenges. A challenge is just a message with type: "challenge". All message endpoints require authentication via the existing headers.

Authentication Headers (required)

  • X-Username
  • X-Password

GET messages

Endpoint

GET /messages

Description Returns all messages relevant for the authenticated user. The response should include received messages and may also include sent messages, so the frontend can show a complete conversation history. The frontend uses this endpoint on page load and polls it regularly to turn the navbar item "Nachrichten" red when unread messages exist.

Response (List<MessageDTO>)

[
  {
    "id": 0,
    "sender": "string",
    "recipient": "string",
      "type": "challenge",
      "text": "string",
      "read": false,
      "createdAt": "2026-05-23T15:42:00",
      "challenge": null
    },
    {
      "id": 1,
      "sender": "System",
      "recipient": "string",
      "type": "challenge-result",
      "text": "Daniela gewinnt gegen Florin mit 18 zu 14 Punkten.",
      "read": false,
      "createdAt": "2026-05-23T15:48:00",
      "challenge": {
        "id": 5,
        "challenger": "Florin",
        "opponent": "Daniela",
        "challengerScore": 14,
        "opponentScore": 18,
        "winner": "Daniela"
      }
    }
]

Status Codes

  • 200 if messages were loaded successfully
  • 401 if authentication failed

POST message

Endpoint

POST /messages

Description Creates a new message from the authenticated user to another existing user. The sender must be taken from the authentication headers, not from the request body.

Request Body (CreateMessageDTO)

{
  "recipient": "string",
  "type": "challenge",
  "text": "string"
}

Response (MessageDTO)

{
  "id": 0,
  "sender": "string",
  "recipient": "string",
  "type": "challenge",
  "text": "string",
  "read": false,
  "createdAt": "2026-05-23T15:42:00"
}

Status Codes

  • 201 if the message was created successfully
  • 400 if recipient, type, or text is missing or invalid
  • 401 if authentication failed
  • 404 if the recipient user does not exist

PATCH single message as read

Endpoint

PATCH /messages/{id}/read

Description Marks one received message as read. Only the recipient of the message is allowed to mark it as read.

Response (MessageDTO)

{
  "id": 0,
  "sender": "string",
  "recipient": "string",
  "type": "challenge",
  "text": "string",
  "read": true,
  "createdAt": "2026-05-23T15:42:00"
}

Status Codes

  • 200 if the message was marked as read
  • 401 if authentication failed
  • 403 if the authenticated user is not the recipient
  • 404 if the message does not exist

PATCH all messages as read

Endpoint

PATCH /messages/read

Description Marks all received messages of the authenticated user as read. This endpoint is optional, but recommended. If it is not implemented, the frontend can call PATCH /messages/{id}/read for each unread message.

Response

{
  "message": "Alle Nachrichten wurden als gelesen markiert."
}

Status Codes

  • 200 if all received messages were marked as read
  • 401 if authentication failed

5. Challenges

Challenges are competitive rounds between two users. The challenged user's current reference result is sent back when the challenge is created. The challenger then plays a round. When the round is completed, the backend compares both scores and creates result messages for both users.

All challenge endpoints require authentication via the existing headers.

Authentication Headers (required)

  • X-Username
  • X-Password

POST challenge

Endpoint

POST /challenges

Description Creates a challenge from the authenticated user against another user. The backend should determine the opponent's reference result, ideally the opponent's best score from /score/{opponent}. The response is used by the frontend to start the challenger into the game with the opponent score visible.

Request Body (CreateChallengeDTO)

{
  "opponent": "string",
  "text": "Ich fordere dich zu einer Lorem-Ipsum-Challenge heraus!"
}

Response (ChallengeDTO)

{
  "id": 0,
  "challenger": "string",
  "opponent": "string",
  "opponentScore": 18,
  "opponentScoreId": 42,
  "status": "open",
  "createdAt": "2026-05-23T15:42:00"
}

Backend behavior

  • The sender/challenger must be taken from the authentication headers.
  • opponentScore should be the opponent's best available score.
  • If the opponent has no score yet, return opponentScore: 0 or reject with 409. Returning 0 is easier for the frontend.
  • The backend may also create an informational message for the opponent that they were challenged.

Status Codes

  • 201 if the challenge was created successfully
  • 400 if opponent is missing or invalid
  • 401 if authentication failed
  • 404 if the opponent user does not exist
  • 409 optional, if the opponent has no score and the backend does not want to use 0

POST complete challenge

Endpoint

POST /challenges/{id}/complete

Description Completes an open challenge with the authenticated user's played result. The backend compares challenger and opponent scores and creates a challenge-result message for both users.

Request Body (CompleteChallengeDTO)

{
  "score": 14,
  "time": 15,
  "text": "string",
  "userWrittenText": "string"
}

Response (ChallengeResultDTO)

{
  "id": 0,
  "challenger": "Florin",
  "opponent": "Daniela",
  "challengerScore": 14,
  "opponentScore": 18,
  "winner": "Daniela",
  "status": "completed",
  "completedAt": "2026-05-23T15:48:00",
  "messages": [
    {
      "id": 10,
      "recipient": "Florin",
      "type": "challenge-result"
    },
    {
      "id": 11,
      "recipient": "Daniela",
      "type": "challenge-result"
    }
  ]
}

For a draw, winner can be null or "draw".

Backend behavior

  • Only the original challenger should be allowed to complete the challenge.
  • The backend should persist the challenger's new result or link to the already persisted score if /score is called separately.
  • After comparing the scores, the backend must create one unread result message for the challenger and one unread result message for the opponent.
  • The result message should have type: "challenge-result" and include the nested challenge result object shown in GET /messages, so the frontend can render the winner/loser graphic.

Status Codes

  • 200 if the challenge was completed successfully
  • 400 if score data is missing or invalid
  • 401 if authentication failed
  • 403 if the authenticated user is not allowed to complete the challenge
  • 404 if the challenge does not exist
  • 409 if the challenge was already completed