Opinion Poll RESTful API Server Exercise

The API is meant to be used for an opinion poll application. Users can rate questions on a scale from 0 to 10. The server should store the ratings and calculate the average rating for each question.

Your task is to create a RESTful API server using Express.js. Briefly summarized, the server should:

  • Authenticate users Iris and Max using bcrypt hashes stored in the users file.
  • Serve questions and accept ratings based on predefined data in JSON files.
  • Keep track of user ratings and calculate average scores.

Your Task

Create an Express REST API Server:

  • Set up a basic Express server that listens for incoming HTTP requests.
  • Implement routes for the endpoints (listed below) with appropriate HTTP methods and responses.

Implement Authentication:

  • Create a login mechanism that checks user credentials against the data/users.json file.
  • Use JWT (JSON Web Tokens) to secure the endpoints.

Work with JSON Files:

  • Use the predefined functions read and write from src/tools/json-files.js to read and write data to/from the JSON files.
  • Calling write('filename.json') with a filename that does not exist will create a new file.

Implement API Endpoints:

  • Implement API endpoints to authenticate, retrieve questions, start polls, and provide ratings for a poll.

Validate User Input:

  • Use JOI to validate user input, ensuring that submitted data follows the correct format.

Prove Endpoint Works Correctly with API Tests:

  • Use jest and supertest to write tests, proving your code works correctly.

API Endpoint Descriptions

POST /authenticate

  • Accepts the username and password via "HTTP Basic" authentication scheme.
  • On successful authentication, returns a JSON Web Token (JWT), which clients will use to access API endpoints subsequently.
  • If authentication fails, returns a 401 Unauthorized status with a relevant message.
  • Authorization: All users (authenticated or not) can access this endpoint.

GET /questions

  • Retrieve the properties id and question of all questions stored in data/questions.json.
  • Authorization: All users (authenticated or not) can access this endpoint.

GET /questions/{questionId}

  • Retrieve the properties id and question for a specific question by its UUID.
  • If the questionId does not exist, respond with a 404 Not Found HTTP status code.
  • Authorization: All users (authenticated or not) can access this endpoint.

POST /polls

  • Create a new poll and store it with the following schema:
{
    "id": "3d13ee89-f02b-4783-bb0e-c2d441a62b4b", // UUID
    "userName": "Iris", // The user's name
    "createdAt": 1715003838, // Current timestamp
    "responses": {} // Empty hash object for now
}
  • Request body: empty (all data is generated by the server).
  • Response body: the ID of the newly created poll (pollId).
  • Authorization: Only authenticated users can access this endpoint.

PUT /polls/{pollId}/responses

  • Submit a rating to specific questions within a poll.
  • Request body: JSON object containing the questionId and the submitted rating (integer between 0 and 10). Example:
{ "544db309-40cf-4dd8-8662-c10ed3502a5d" : 7 }
  • Updates the specified poll in the polls.json file. Example after above submission:
{
    "id": "3d13ee89-f02b-4783-bb0e-c2d441a62b4b", // UUID of the poll
    "userName": "Iris", // The user's name
    "createdAt": 1715003838, // Timestamp
    "responses": {
      "544db309-40cf-4dd8-8662-c10ed3502a5d": 7 // <questionId>: <rating>
    }
}
  • Authorization: Authenticated users can POST to this endpoint only if the referenced poll is owned by them.

GET /questions/{questionId}/rating

  • Retrieve the average rating for a specific question, taking into account all submitted polls.
  • If the questionId does not exist, respond with a 404 Not Found HTTP status code.
  • Authorization: All users (authenticated or not) can access this endpoint.
{
    "average": 7.5 // The average rating for the question
}

Additional Guidelines:

Form Validation:

  • Use JOI to validate user input, ensuring that submitted ratings follow the correct format and are within the 0 to 10 range.

Error Handling:

  • Return meaningful error messages and HTTP status codes for invalid or unauthorized requests.

Testing:

  • Create API tests to ensure all API endpoints work correctly.

Fixtures / Prepared Content and User Data

Questions

The questions are stored as an array in the file data/questions.json and have the following data structure:

  • id (uuid): Unique identifier for a question
  • question (string): Actual question text

Users

The users file (data/users.json) contains two users:

  • Name: Iris, Password: 123
  • Name: Max, Password: 123

Use Iris and Max for authentication. The passwords are stored as cryptographic hashes, created with the bcrypt algorithm. When verifying the password, please pay attention to comparing hashes, not the plain password with the stored hash.