This is a backend tech test for a company who would likely rather not appear on Google. Rhymes with Wrinkle.
This document contains instructions for running the app locally, and a discussion of the development process.
After cloning the repo, install dependencies:
npm install
The app is built with Prisma as an ORM. Prisma requires a DATABASE_URL
value in the environment, and migrations to set up the database tables.
# copy the example environment values to the real deal
cp .env.example .env
# run migrations
npx prisma migrate dev
Optionally, the database can be seeded with some rows once Prisma has been set up.
# optional
npx ts-node script.ts
If successful, a list of objects representing the created rows will be logged to the console.
Finally the app can be run in dev mode:
npm run dev
Run tests:
npm test
The /bruno
folder contains queries which can be opened with Bruno (similar to Postman, Insomnia...).
- Install Bruno (
brew install bruno
works) - From the top-left
...
menu select "Open Collection" and navigate to this repo's/bruno
folder. Open the whole folder. - Each tab contains a query.
- Run a query with the → right arrow button to the right of the window.
There are two endpoints:
Expects a JSON body, for example:
{
"name": "Alan",
"email": "alan@hireme.io",
"password": "Hunter22",
"type": "TEACHER"
}
Possible values for type
are:
"TEACHER"
"STUDENT"
"PARENT"
"PRIVATE_TUTOR"
On success the API responds with status code 201
and the created object (omitting the password for security).
If fields are missing or invalid the API responds with status code 422
and error messages.
IDs are sequential numbers starting from 1 and are not reassigned if deleted.
Responds with status code 200
and the user object if found (omitting the password for security).
If the ID is not found, responds with a 404
status code and no body.
The app is a bare Express app, roughly following an MVC architecture, with Prisma as an ORM.
My Node API framework of choice is normally Nest.js, but it felt like overkill for this project.
The User model (/src/models/User.ts
) is just a couple of functions to encapsulate Prisma operations. Input validation is handled here with Zod, including the password requirements detailed in the brief. This file could easily have been a class but again, it felt like overkill for the requirements. If the User required full CRUD functionality the model would have been a class.
The UserController (/src/controllers/UserController.ts
) defines the endpoint URLs, delegates to the User model for DB operations and sends the appropriate HTTP responses.
The UserController tests (/src/controllers/UserController.test.ts
) use Supertest to test the API endpoints with a mocked Prisma instance. Valid inputs and responses are tested, with the password requirements tested for appropriate failures.
The only limitation of Prisma here was that it does not support enum data types for SQLite, only for PostgreSQL and MS SQL Server (related issue). An enum is technically the right choice for the user.type
field, but since it is not possible here the data type had to be a String
with the validation happening in the application layer. It's not optimal but it works.