Skip to content

OnePTE is a simplified version of the Quiz Assessment Platform for a language proficiency test

Notifications You must be signed in to change notification settings

yousufislam191/OnePTE

Repository files navigation

OnePTE API Documentation

Table of Contents

Introduction

OnePTE is a REST API built with Node.js and Express.js framework. It uses Sequelize as ORM to interact with MySQL database. The API is designed to manage questions and answers for a language proficiency test.

Database Design

Diagram

API Endpoints

User Endpoints

Register a new user

  • POST /api/v1/users/register

    Request Body Example (Click here)
      {
        "name": "Yousuf Islam",
        "email": "[email protected]",
        "password": "12345@qQ"
      }
    Response example
      {
        "status": 201,
        "success": true,
        "message": "User created successfully",
        "data": null
      }

    ⬆️ Back to top

Get user practice history

  • GET /api/v1/users/history?type=SST&page=1&pageSize=5

    Query Parameters
    Parameter Type Description
    type enum (optional) Filters history by question type. Possible values: SST, RO, RMMCQ.
    page string (optional) Specifies the page number for pagination. Default is 1.
    pageSize string (optional) Specifies the number of items per page. Default is 10.
    Request Headers
    Header Name Value Type Description
    Cookie string Contains accessToken and refreshToken for authentication.
    Request Example
    GET /api/v1/users/history?type=SST&page=1&pageSize=5 HTTP/1.1
    Host: your-api.com
    Cookie: accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTY5MjQwNjAyMCwiZXhwIjoxNzI0MDY5MzIwfQ.wBq6BImUXNUp5SW8ptjY8q_W6oBzzNybjFdEKcICG_A; refreshToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTcyNDA2OTAyMCwiZXhwIjoxNzI0NjczODIwfQ.XbP2M2SCo60_cCszqJKwd_zyoPH7b45aK2LQfY6ikZI
    
    Response Example
    {
      "status": 200,
      "success": true,
      "message": "User history retrieved successfully",
      "data": {
        "totalItems": 2,
        "totalPages": 1,
        "currentPage": 1,
        "user": {
          "name": "Yousuf Islam"
        },
        "history": [
          {
            "answer": {
              "id": 1,
              "answer": [0, 1, 2],
              "score": 0,
              "max_score": 3
            },
            "question": {
              "id": 6,
              "type": "RMMCQ",
              "title": "RMMCQ Two",
              "sst": null,
              "ro": null,
              "rmmcq": {
                "id": 2,
                "options": [
                  "Not for one moment did he doubt the validity...",
                  "This research seems to give some validity...",
                  "I had no reason to question the validity...",
                  "State officials questioned the validity of the report...",
                  "The clause has no legal validity..."
                ]
              }
            }
          },
          {
            "answer": {
              "id": 2,
              "answer": [0, 1, 2, 3],
              "score": 3,
              "max_score": 3
            },
            "question": {
              "id": 5,
              "type": "RO",
              "title": "RO Two",
              "sst": null,
              "ro": {
                "id": 2,
                "paragraphs": [
                  "Not for one moment did he doubt the validity...",
                  "This research seems to give some validity...",
                  "I had no reason to question the validity...",
                  "State officials questioned the validity of the report..."
                ]
              },
              "rmmcq": null
            }
          },
        ]
      }
    }
    
    

    ⬆️ Back to top

Authentication Endpoints

Login a user

  • POST /api/v1/auth/login

    Request Body Example
      {
        "email": "[email protected]",
        "password": "12345@qQ"
      }
    Response Example
    {
        "status": 200,
        "success": true,
        "message": "Successfully logged in",
        "data": {
            "id": 1
        }
    }

    ⬆️ Back to top

Logout a user

  • POST /api/v1/auth/logout

    Request Headers
    Header Name Value Type Description
    Cookie string Contains accessToken and refreshToken for authentication.
    Response Example
    {
      "status": 200,
      "success": true,
      "message": "Successfully logged out",
      "data": null
    }

    ⬆️ Back to top

Generate Refresh Token

  • POST /api/v1/auth/refresh-token

    Request Headers
    Header Name Value Type Description
    Cookie string Contains accessToken and refreshToken for authentication.
    Response Example
    {
      "status": 200,
      "success": true,
      "message": "New access token generated successfully",
      "data": null
    }

    ⬆️ Back to top

Question Endpoints

Create a new question

  • POST /api/v1/questions

    Request Headers
    Header Name Type Description
    Cookie string Contains accessToken and refreshToken for authentication.
    Content-Type string Must be multipart/form-data
    Form-Data Parameters
    Parameter Name Type Description
    audio_files file Required for SST. Audio files (multiple files allowed).
    jsonData text Required. JSON string containing the question details.

    Example for jsonData (as text):

    {
      "type": "SST",
      "title": "Title must be a string",
      "time_limit": 20,
      "speakers": ["Speaker 1", "Speaker 2"],
      "paragraphs": ["paragraphs 1", "paragraphs 2", "paragraphs 3", "paragraphs 4"],
      "passage": "Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME 'users' AND TABLE_SCHEMA = 'onepte'",
      "options": ["options 1", "options 2", "options 3", "options 4", "options 5"],
      "correct_options": [1, 2, 4]
    }
    
    
    Response Example for SST Type Question
      {
      "status": 201,
      "success": true,
      "message": "Question created successfully",
      "data": {
          "question": {
              "id": 4,
              "type": "SST",
              "title": "Title must be a string",
              "sst_id": 1,
              "updatedAt": "2024-08-20T22:27:17.826Z",
              "createdAt": "2024-08-20T22:27:17.826Z"
          },
          "details": {
              "id": 1,
              "time_limit": 20,
              "audio_files": [
                  {
                      "fileUrl": "uploads/audio/1724192835930-AvoidRafa_(cover).mp3",
                      "speaker": "Speaker 1"
                  },
                  {
                      "fileUrl": "uploads/audio/1724192836022-Music_(_no_copyright_Music_)_01.mp3",
                      "speaker": "Speaker 2"
                  }
              ],
              "updatedAt": "2024-08-20T22:27:16.084Z",
              "createdAt": "2024-08-20T22:27:16.084Z"
          }
      }
    }
    
    Response Example for RO Type Question
      {
      "status": 201,
      "success": true,
      "message": "Question created successfully",
      "data": {
          "question": {
              "id": 3,
              "type": "RO",
              "title": "Title must be a string",
              "ro_id": 1,
              "updatedAt": "2024-08-20T22:26:43.350Z",
              "createdAt": "2024-08-20T22:26:43.350Z"
          },
          "details": {
              "id": 1,
              "paragraphs": [
                  "paragraphs 1",
                  "paragraphs 2",
                  "paragraphs 3",
                  "paragraphs 4"
              ],
              "updatedAt": "2024-08-20T22:26:43.231Z",
              "createdAt": "2024-08-20T22:26:43.231Z"
          }
      }
    }
    
    Response Example for RMMCQ Type Question
      {
      "status": 201,
      "success": true,
      "message": "Question created successfully",
      "data": {
          "question": {
              "id": 2,
              "type": "RMMCQ",
              "title": "Title must be a string",
              "rmmcq_id": 2,
              "updatedAt": "2024-08-20T22:25:24.736Z",
              "createdAt": "2024-08-20T22:25:24.736Z"
          },
          "details": {
              "id": 2,
              "passage": "Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME 'users' AND TABLE_SCHEMA = 'onepte'",
              "options": [
                  "options 1",
                  "options 2",
                  "options 3",
                  "options 4",
                  "options 5"
              ],
              "correct_options": [
                  1,
                  2,
                  4
              ],
              "updatedAt": "2024-08-20T22:25:24.472Z",
              "createdAt": "2024-08-20T22:25:24.472Z"
          }
      }
    }
    

    ⬆️ Back to top

Get all questions with pagination and filtering

  • GET /api/v1/questions?page=1&pageSize=5

    Query Parameters
    Parameter Type Description
    type enum (optional) Filters questions by question type. Possible values: SST, RO, RMMCQ.
    page string (optional) Specifies the page number for pagination. Default is 1.
    pageSize string (optional) Specifies the number of items per page. Default is 10.
    Request Headers
    Header Name Value Type Description
    Cookie string Contains accessToken and refreshToken for authentication.
    Response Example
    {
      "status": 200,
      "success": true,
      "message": "Questions fetched successfully",
      "data": {
          "totalItems": 41,
          "totalPages": 5,
          "currentPage": 1,
          "data": [
              {
                  "id": 1,
                  "type": "SST",
                  "title": "SST One",
                  "sst_id": 1,
                  "ro_id": null,
                  "rmmcq_id": null,
                  "createdAt": "2024-08-15T22:23:46.000Z",
                  "updatedAt": "2024-08-15T22:23:46.000Z"
              },
              {
                  "id": 2,
                  "type": "RO",
                  "title": "RO One",
                  "sst_id": null,
                  "ro_id": 1,
                  "rmmcq_id": null,
                  "createdAt": "2024-08-15T22:24:44.000Z",
                  "updatedAt": "2024-08-15T22:24:44.000Z"
              },
              {
                  "id": 3,
                  "type": "RMMCQ",
                  "title": "RMMCQ One",
                  "sst_id": null,
                  "ro_id": null,
                  "rmmcq_id": 1,
                  "createdAt": "2024-08-15T22:25:00.000Z",
                  "updatedAt": "2024-08-15T22:25:00.000Z"
              },
              {
                  "id": 4,
                  "type": "SST",
                  "title": "SST Two",
                  "sst_id": 2,
                  "ro_id": null,
                  "rmmcq_id": null,
                  "createdAt": "2024-08-15T22:25:17.000Z",
                  "updatedAt": "2024-08-15T22:25:17.000Z"
              },
              {
                  "id": 5,
                  "type": "RO",
                  "title": "RO Two",
                  "sst_id": null,
                  "ro_id": 2,
                  "rmmcq_id": null,
                  "createdAt": "2024-08-15T22:25:26.000Z",
                  "updatedAt": "2024-08-15T22:25:26.000Z"
              },
              {
                  "id": 6,
                  "type": "RMMCQ",
                  "title": "RMMCQ Two",
                  "sst_id": null,
                  "ro_id": null,
                  "rmmcq_id": 2,
                  "createdAt": "2024-08-15T22:25:34.000Z",
                  "updatedAt": "2024-08-15T22:25:34.000Z"
              },
              {
                  "id": 7,
                  "type": "RMMCQ",
                  "title": "Fix: Use Dynamic Assignment for questionData",
                  "sst_id": null,
                  "ro_id": null,
                  "rmmcq_id": 3,
                  "createdAt": "2024-08-17T22:59:26.000Z",
                  "updatedAt": "2024-08-17T22:59:26.000Z"
              },
              {
                  "id": 8,
                  "type": "SST",
                  "title": "Fix: Use Dynamic Assignment for questionData",
                  "sst_id": 3,
                  "ro_id": null,
                  "rmmcq_id": null,
                  "createdAt": "2024-08-17T23:01:30.000Z",
                  "updatedAt": "2024-08-17T23:01:30.000Z"
              },
              {
                  "id": 9,
                  "type": "RO",
                  "title": "Fix: Use Dynamic Assignment for questionData",
                  "sst_id": null,
                  "ro_id": 3,
                  "rmmcq_id": null,
                  "createdAt": "2024-08-17T23:01:38.000Z",
                  "updatedAt": "2024-08-17T23:01:38.000Z"
              },
              {
                  "id": 10,
                  "type": "RO",
                  "title": "Fix: Use Dynamic Assignment for questionData",
                  "sst_id": null,
                  "ro_id": 4,
                  "rmmcq_id": null,
                  "createdAt": "2024-08-17T23:12:18.000Z",
                  "updatedAt": "2024-08-17T23:12:18.000Z"
              }
          ]
      }
    }
    

    ⬆️ Back to top

Get a specific question

  • GET /api/v1/questions/:id

    Query Parameters
    Parameter Type Description
    id int Question ID
    Request Headers
    Header Name Value Type Description
    Cookie string Contains accessToken and refreshToken for authentication.
    Response Example
      {
      "status": 200,
      "success": true,
      "message": "Question fetched successfully",
      "data": {
          "id": 3,
          "type": "RO",
          "title": "Title must be a string",
          "details": {
              "id": 1,
              "paragraphs": [
                  {
                      "index": 3,
                      "value": "paragraphs 4"
                  },
                  {
                      "index": 2,
                      "value": "paragraphs 3"
                  },
                  {
                      "index": 0,
                      "value": "paragraphs 1"
                  },
                  {
                      "index": 1,
                      "value": "paragraphs 2"
                  }
              ]
          }
      }
    }
    

    ⬆️ Back to top

Answer Endpoints

Create a new answer for a specific question

  • POST /api/v1/answers

    Request Headers
    Header Name Value Type Description
    Cookie string Contains accessToken and refreshToken for authentication.
    Request Body Example for RO & RMMQC Type
    {
        "questionId": 2,
        "answerData": [0, 1, 2, 3]
    }

    Note: The answerData value is the array of numbers [0, 1, 2, 3] which is the index number of the RO's paragraphs & RMMCQ's options type question.

    Request Body Example for SST Type
    {
      "questionId": 2,
      "answerData": "Return Object from Scoring Functions: Each scoring function now returns an object with score and maxScore."
    }
    
    Reesponse Example
    {
      "status": 201,
      "success": true,
      "message": "Answer submitted successfully",
      "data": null
    }
    

    ⬆️ Back to top

Run this project

Running Locally

To run the OnePTE API locally, follow these steps:

1. Clone the Repository:

First, clone the repository to your local machine using the following command:

git clone https://github.com/yousufislam191/OnePTE.git
cd OnePTE

2. Install Dependencies:

Make sure you have Node.js and npm installed on your system. Then, install the required dependencies:

npm install

3. Set Up Environment Variables:

Add the necessary environment variables in .env.development file as shown below:

SERVER_PORT = 3001
ALLOWED_ORIGINS = http://localhost:3000
NODE_ENV = development
API_PREFIX = /api/v1
APPLICATION_NAME = OnePTE

DB_HOST = localhost
DB_PORT = 3306
DB_LOGIN_NAME = root
DB_LOGIN_PASSWORD = root
DB_NAME = onepte

JWT_ACCESS_SECRET = myaccesssecret
JWT_ACCESS_EXPIRES_IN = 5m
JWT_REFRESH_SECRET = myrefreshsecret
JWT_REFRESH_EXPIRES_IN = 7d

Replace DB_LOGIN_NAME, DB_LOGIN_PASSWORD, and onepte with your MySQL credentials and database name.

4. Set Up the Database:

Ensure MySQL is running on your machine. Then, run the following command to create and migrate the database:

npm run db:migrate

This will automatically create the database and apply any migrations.

5. Start the Application:

Start the server using the following command:

npm run dev

The server should now be running at http://localhost:3001.

Running with Docker

To run this project using Docker, follow these steps:

  1. Install Docker Desktop and Git

  2. Open a terminal and Clone this github repository

    git clone https://github.com/yousufislam191/OnePTE.git
  3. Enter the cloned repository

    cd OnePTE
  4. Build and Start Containers:

    Use the provided docker-up.sh script to build the Docker images and start the containers. Run the following command:

    ./docker-up.sh

    This will execute the docker-compose.yml file, build the necessary Docker images, and start the containers in detached mode.

  5. Stop and Remove Containers:

    If you need to stop and remove the running containers, use the docker-down.sh script. Run the following command:

    ./docker-down.sh

    This will execute the docker-compose.yml file, stop and remove the running containers.

  6. Access the Application:

    Once the containers are up and running,

    • you can access the application at http://localhost:3001 in your browser or Postman.
    • you can acces the database at http://localhost:8081 in your browser through phpMyAdmin with the username: root and password: root.

Test Api's

To test api endpoint, download the Postman Collection file then import it into you postman.

About

OnePTE is a simplified version of the Quiz Assessment Platform for a language proficiency test

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published