Your task is to implement simple CRUD API using in-memory database underneath.
- Task can be implemented on Javascript or Typescript
- Only
nodemon
,dotenv
,cross-env
,typescript
,ts-node
,ts-node-dev
,eslint
and its plugins,webpack-cli
,webpack
and its plugins,prettier
,uuid
,@types/*
as well as libraries used for testing are allowed - Use 18 LTS version of Node.js
- Prefer asynchronous API whenever possible
- Implemented endpoint
api/users
:- GET
api/users
is used to get all persons- Server should answer with
status code
200 and all users records
- Server should answer with
- GET
api/users/{userId}
- Server should answer with
status code
200 and record withid === userId
if it exists - Server should answer with
status code
400 and corresponding message ifuserId
is invalid (notuuid
) - Server should answer with
status code
404 and corresponding message if record withid === userId
doesn't exist
- Server should answer with
- POST
api/users
is used to create record about new user and store it in database- Server should answer with
status code
201 and newly created record - Server should answer with
status code
400 and corresponding message if requestbody
does not contain required fields
- Server should answer with
- PUT
api/users/{userId}
is used to update existing user- Server should answer with
status code
200 and updated record - Server should answer with
status code
400 and corresponding message ifuserId
is invalid (notuuid
) - Server should answer with
status code
404 and corresponding message if record withid === userId
doesn't exist
- Server should answer with
- DELETE
api/users/{userId}
is used to delete existing user from database- Server should answer with
status code
204 if the record is found and deleted - Server should answer with
status code
400 and corresponding message ifuserId
is invalid (notuuid
) - Server should answer with
status code
404 and corresponding message if record withid === userId
doesn't exist
- Server should answer with
- GET
- Users are stored as
objects
that have following properties:id
— unique identifier (string
,uuid
) generated on server sideusername
— user's name (string
, required)age
— user's age (number
, required)hobbies
— user's hobbies (array
ofstrings
or emptyarray
, required)
- Requests to non-existing endpoints (e.g.
some-non/existing/resource
) should be handled (server should answer withstatus code
404 and corresponding human-friendly message) - Errors on the server side that occur during the processing of a request should be handled and processed correctly (server should answer with
status code
500 and corresponding human-friendly message) - Value of
port
on which application is running should be stored in.env
file - There should be 2 modes of running application (development and production):
- The application is run in development mode using
nodemon
orts-node-dev
(there is anpm
scriptstart:dev
) - The application is run in production mode (there is a
npm
scriptstart:prod
that starts the build process and then runs the bundled file)
- The application is run in development mode using
- There could be some tests for API (not less than 3 scenarios). Example of test scenario:
- Get all records with a
GET
api/users
request (an empty array is expected) - A new object is created by a
POST
api/users
request (a response containing newly created record is expected) - With a
GET
api/user/{userId}
request, we try to get the created record by itsid
(the created record is expected) - We try to update the created record with a
PUT
api/users/{userId}
request (a response is expected containing an updated object with the sameid
) - With a
DELETE
api/users/{userId}
request, we delete the created object byid
(confirmation of successful deletion is expected) - With a
GET
api/users/{userId}
request, we are trying to get a deleted object byid
(expected answer is that there is no such object)
- Get all records with a
- There could be implemented horizontal scaling for application, there should be
npm
scriptstart:multi
that starts multiple instances of your application using the Node.jsCluster
API (equal to the number of available parallelism - 1 on the host machine, each listening on port PORT + n) with a load balancer that distributes requests across them (using Round-robin algorithm). For example: available parallelism is 4,PORT
is 4000. On runnpm run start:multi
it works following way
- On
localhost:4000/api
load balancer is listening for requests - On
localhost:4001/api
,localhost:4002/api
,localhost:4003/api
workers are listening for requests from load balancer - When user sends request to
localhost:4000/api
, load balancer sends this request tolocalhost:4001/api
, next user request is sent tolocalhost:4002/api
and so on. - After sending request to
localhost:4003/api
load balancer starts from the first worker again (sends request tolocalhost:4001/api
) - State of db should be consistent between different workers, for example:
- First
POST
request addressed tolocalhost:4001/api
creates user - Second
GET
request addressed tolocalhost:4002/api
should return created user - Third
DELETE
request addressed tolocalhost:4003/api
deletes created user - Fourth
GET
request addressed tolocalhost:4001/api
should return 404 status code for created user
- First