Skip to content

sirtobsi/dps-expressjs-challenge

 
 

Repository files navigation

Find the task description in the end of the README.md file

DPS Backend Coding Challenge (Documentation)

This is my submission to the DPS Backend Coding Challenge. Enjoy and feel free to reach out to me if you have any questions.

Getting Started

  1. Install dependencies using npm install
  2. Copy the .env.example file to .env and leave the DATABASE_URL as it is
  3. Generate the models for the api using npm run api:gen
  4. Generate the Prisma client (ORM) using npm run prisma:gen
  5. Run the application using npm run dev

The application is now running on http://localhost:8080. You can access the API documentation on http://localhost:8080/api-specs. If you want to send requests to the backend, use the following token in the Authorization header:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXNzd29yZCI6IlBhc3N3b3JkMTIzIn0.RDGxHLrPkPThUU9QepQqnm-qInz5GyhRC92Z_g1TOYc

Technologies

I added some tools/technologies to the project to make it more robust and maintainable. Here is a list of the technologies used in the project:

  • Logging: Winston
  • ORM: Prisma
  • API Documentation: Swagger (incl. autogenerated API client & models)
  • Authentication: JWT
  • Validation: zod

API Documentation

The API documentation is available at http://localhost:8080/api-specs. You can also find the API documentation in the api folder (here).

The endpoints expect UUID strings for the projectId and reportId parameters. Not complying with this will result in a 400 Bad Request response. When creating a project or a report, the id field is not required. The id field is generated by the database and returned in the response.

Default

  • Get Hello World!
    • GET /

Projects

  • Get all projects
    • GET /projects
  • Create a project
    • POST /projects
  • Get a project
    • GET /projects/{projectId}
  • Update a project
    • PUT /projects/{projectId}
  • Delete a project
    • DELETE /projects/{projectId}
  • Get all reports of a project
    • GET /projects/{projectId}/reports
  • Create a report for a project
    • POST /projects/{projectId}/reports
  • Get a report of a project
    • GET /projects/{projectId}/reports/{reportId}
  • Update a report of a project
    • PUT /projects/{projectId}/reports/{reportId}
  • Delete a report of a project
    • DELETE /projects/{projectId}/reports/{reportId}

Reports

  • Get all reports where the given query word occurs at least 3 times
    • GET /reports?query={query}

Environment Variables

Please copy the environment variables provided in the .env.example file to a new .env file. The DATABASE_URL variable is already set up for you.

Database

I decided not to use the initally provided database schema, as it did not enforce any constraints. Instead, I created a new schema using Prisma. The schema can be found in the prisma folder (here). The database is stored in the db folder (here).

The schema itself follows the specification from the task description.

erDiagram
    ProjectDao {
        String id PK
        String name
        String description
    }
    ReportDao {
        String id PK
        String text
        String projectId FK
    }
    ProjectDao ||--o{ ReportDao : "reports"
Loading
  • PK indicates a primary key.
  • FK indicates a foreign key.
  • there is a one-to-many relationship between ProjectDao and ReportDao.

Project Structure

.
├── README.md                               | this file
├── api                                     | folder containing the API documentation        
│   ├── generated
│   │   ├── core
│   │   ├── index.ts
│   │   ├── models                          | generated models
│   │   └── services
│   └── src
│       └── api-spec.yaml                   | API documentation using swagger
├── db                                      | database folder
│   ├── db-tobi.sqlite3                     | database file (used in this project)
│   ├── db-tobi.sqlite3-journal
│   └── db.sqlite3
├── images                                  | images used in the README.md
│   └── database_schema.png
├── package-lock.json
├── package.json                            | npm package file with dependencies & scripts
├── prisma                                  | prisma folder for the ORM
│   ├── migrations
│   │   ├── 20240714183344_init
│   │   └── migration_lock.toml
│   └── schema.prisma                       | prisma schema file
├── src
│   ├── controllers                         | controllers for the API
│   │   ├── projectController.ts
│   │   └── reportController.ts
│   ├── index.ts                            | main application file
│   ├── middleware                          | middleware for the API
│   │   ├── auth                            | authentication middleware
│   │   ├── errorhandler                    | error handling middleware
│   │   └── logger                          | logging middleware
│   ├── routes                              | routes for the API
│   │   ├── projectReportRouter.ts
│   │   ├── projectRouter.ts
│   │   └── reportRouter.ts
│   └── services                            | services for the API
│       ├── converters                      | converters for the API converting between DAOs and DTOs
│       ├── db.service.ts                   | NOT USED
│       ├── projectService.ts
│       ├── reportService.ts
│       └── validators                      | validators for data received from the API
└── tsconfig.json

Disclaimer

The structure and the codebase of this project is based on other projects I did in private repositories or university projects. I decided to use an ORM to handle database operations. As software engineers we should not try to reinvent the wheel - instead, we should use off-the-shelf components where possible to guarantee the best quality and maintainability of the codebase while also delivering at a high pace.

For the database, I redefined the schema to enforce FK and unique constraints. This puts some of the responsibility on the database to ensure data integrity - the OS community that implemented the database was probably much more successful in covering all the edge-cases, that I would have forgotten.

DPS Backend Coding Challenge

Overview

This repository contains a very basic web application based on Typescript and Express.js. Main application file is index.ts. Node and npm are required.

Environment Setup

Ensure you have Node.js (v14.x or later) and npm (v6.x or later) installed.
To set up and run the application, execute the following commands:

npm install
npm run dev

The application will then be accessible at http://localhost:3000.

Project Context

You will develop a backend system for managing data about a company's projects and their associated reports. Each project may have multiple reports linked to it, though having reports is not mandatory. Start your implementation using the provided SQLite database(db/db.sqlite3).

Refer to the database schema provided for understanding the data structure 👇

Database schema

NOTE: You can use (db.service.ts) to handle SQL queries to the database.

Challenge Tasks

  • Fork this project: Start by forking this repository
  • REST API Development: Design and implement a RESTful API to create, read, update, and delete projects and their reports.
  • Special API Endpoint: Create an API endpoint that retrieves all reports where the same word appears at least three times.
  • Optional: Secure all API routes with a hardcoded authentication token ("Password123").
  • Submission: After completing the challenge, email us the URL of your GitHub repository.
  • Further information:
    • If there is anything unclear regarding requirements, contact us by replying to our email.
    • Use small commits, we want to see your progress towards the solution.
    • Code clean and follow the best practices.


Happy coding!

About

DPS Coding challenge based on Express.js and Typescript

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 100.0%