- Git
- Node JS >= 16.15
- MongoDb Driver
- MongoDb Server.
- ExpressJS
- Redis
- JWT Token
- Docker and Docker Compose
- Ajv and AJv Plugins
- Uuid
- Docker and Docker Compose
- [Winston]https://www.npmjs.com/package/winston)
- Postman
Please check the file env.example
and change to .env
there are 2 .env
files, and both are required.
- one in root folder to define server needs
- one in
./apps/user-api
to setup the API
NODE_ENV = development
APP_PORT = 3000
APP_ISSUER = gitbub.com/mrbontor
....
This mini microservice is developed using Docker and Docker Compose, Hint:
- If you are going to use your existing MongoDb and Redis, please change the configuration in
./.env
and./apps/user-api/.env
(i expects the env files has been renamed) - If you are using MongoAtlas or other Mongo Cloud, please set variable
MONGO_LOCAL
to true in./apps/user-api/.env
Running service using Docker
and Docker-Compose
# start
$ docker-compose up
# stop
$ docker-compose down
# remove
$ docker-compose down -v
#login to the container by container name base on docker-compose.yml
$ docker exec -it [`container-name`] sh
#logging the container
$ docker logs -f `container-name`
Running for existing MongoDB and Redis
# enter to the user-api
$ cd apps/user-api
# install dependencies
$ npm install
# run app
$ npm start
# or
$ node index.js
No unit tests, cant finish all of them with only 2 days.
For this service, i only provide Postman File, The file already includes Environtment, Documentation and Test cases for every endpoint.
Please follow Postman Doc Import Api for better information
below is the output and test case from the postman file json
User(s) must be authenticated before accessing any API.
The AUTH API
will return accessToken
, refreshToken
and DID
API
has provided Cookies
for clients with expiration time
.
To change the lifetime
, look in the .env
file. Expiration time is used to handle JWT Token
and Cookie
expiration
Notes:
accessToken
will be returned in response bodyrefreshToken
will be returned asCookie
with nameRTOKEN
deviceId
is the device identifier and will be returned as aCookie
with nameDID
User login using method POST with paramatersusername
and password.
Endpoint:
Method: POST
Type: RAW
URL: {{local}}/v1/auth/login
Body:
{
"accountNumber": 12345671,
"password": "Superadmin123!"
}
More example Requests/Responses:
Body:
{
"accountNumber": 12345671,
"password": "Superadmin123!"
}
{
"status": true,
"message": "Success",
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJOYW1lIjoic3VwZXJhZG1pbiIsImFjY291bnROdW1iZXIiOjEyMzQ1NjcxLCJpZGVudGl0eU51bWJlciI6MTIzNDU2Nzg5ODc2NTQzMX0sImlhdCI6MTY3NTU4NTIyOSwiZXhwIjoxNzExNTg4ODI5LCJhdWQiOiJnaXRidWIuY29tL21yYm9udG9yIiwiaXNzIjoiZ2l0YnViLmNvbS9tcmJvbnRvciJ9.QC0dGYt6Rd3Nou3jc8gD9i-Bmseg26Pg0Y02gNFwIGw"
}
}
Status Code: 200
Body:
{
"accountNumber": 12345678,
"password": "Superadmin123!"
}
{
"status": false,
"message": "Un Authorized!"
}
Status Code: 401
Register user use JSON
payload to create a user
fields:
- userName,
required
- accountNumber,
required
- emailAddress,
required
- identityNumber,
required
- password,
required
Endpoint:
Method: POST
Type: RAW
URL: {{local}}/v1/auth/register
Body:
{
"userName": "user1",
"accountNumber": 12345672,
"emailAddress": "user1@gmail.com",
"identityNumber": 1234567898765411,
"password": "iamUser123!"
}
More example Requests/Responses:
Body:
{
"userName": "user",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": true,
"message": "Success",
"data": "63df60c87116dd7ec619891b"
}
Status Code: 200
Body:
{
"userName": "user",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": false,
"message": "The userName has been registered!"
}
Status Code: 400
Body:
{
"userName": "user1",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": false,
"message": "The emailAddress has been registered!"
}
Status Code: 400
Body:
{
"userName": "user1",
"accountNumber": 12345672,
"emailAddress": "user1@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": false,
"message": "The identityNumber has been registered!"
}
Status Code: 400
Body:
{
"userName": "user1",
"accountNumber": 12345672,
"emailAddress": "user1@gmail.com",
"identityNumber": 1234567898765411,
"password": "iamUser123!"
}
{
"status": false,
"message": "The accountNumber has been registered!"
}
Status Code: 400
Fetch new Token as a refresh token
Endpoint:
Method: GET
Type:
URL: {{local}}/v1/auth/refresh-token
More example Requests/Responses:
Body: None
{
"status": true,
"message": "Success",
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJOYW1lIjoic3VwZXJhZG1pbiIsImFjY291bnROdW1iZXIiOjEyMzQ1NjcxLCJpZGVudGl0eU51bWJlciI6MTIzNDU2Nzg5ODc2NTQzMX0sImlhdCI6MTY3NTU4NjA1MSwiZXhwIjoxNzExNTg5NjUxLCJhdWQiOiJnaXRidWIuY29tL21yYm9udG9yIiwiaXNzIjoiZ2l0YnViLmNvbS9tcmJvbnRvciJ9.6wZWjm5yqqiHdXX6Mjdmf_ZnoULI05C6FhS-HuCGZAw"
}
}
Status Code: 200
Body: None
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
User Logout and remove token, cookies etc
Endpoint:
Method: GET
Type:
URL: {{local}}/v1/auth/logout
Query params:
Key | Value | Description |
---|---|---|
allDevices | true | true or false |
More example Requests/Responses:
Query:
Key | Value | Description |
---|---|---|
allDevices | true | true or false |
Body: None
Status Code: 204
Query:
Key | Value | Description |
---|---|---|
allDevices | true | true or false |
Body: None
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
Users
directory contains all the user related APIs. For authentication these apis requrie AuthBearerToken
Create user use JSON
payload to create a user
fields:
- userName,
required
- accountNumber,
required
- emailAddress,
required
- identityNumber,
required
- password,
required
Endpoint:
Method: POST
Type: RAW
URL: {{local}}/v1/users
Body:
{
"userName": "user5",
"accountNumber": 12345675,
"emailAddress": "user5@gmail.com",
"identityNumber": 1234567898765435,
"password": "User123!"
}
More example Requests/Responses:
Body:
{
"userName": "user",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": true,
"message": "Success",
"data": "63df60c87116dd7ec619891b"
}
Status Code: 200
Body:
{
"userName": "user",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": false,
"message": "The userName has been registered!"
}
Status Code: 400
Body:
{
"userName": "user1",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": false,
"message": "The emailAddress has been registered!"
}
Status Code: 400
Body:
{
"userName": "user1",
"accountNumber": 12345672,
"emailAddress": "user1@gmail.com",
"identityNumber": 1234567898765432,
"password": "iamUser123!"
}
{
"status": false,
"message": "The identityNumber has been registered!"
}
Status Code: 400
Body:
{
"userName": "user1",
"accountNumber": 12345672,
"emailAddress": "user1@gmail.com",
"identityNumber": 1234567898765411,
"password": "iamUser123!"
}
{
"status": false,
"message": "The accountNumber has been registered!"
}
Status Code: 400
Body:
{
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431,
"password": "Superadmin123!"
}
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
Patch
password user use JSON
payload to update user password.
fields:
- password,
required
- newPassword,
required
Noted: Changing password will remove Token Bearer
Endpoint:
Method: PATCH
Type: RAW
URL: {{local}}/v1/users/password/1234567898765431
Body:
{
"password": "Superadmin123!",
"newPassword": "Superadmin123!!"
}
More example Requests/Responses:
Body:
{
"password": "Superadmin123!!",
"newPassword": "Superadmin123!"
}
Status Code: 204
Body:
{
"password": "Superadmin123!",
"newPassword": "Superadmin123!!"
}
{
"status": false,
"message": "Incorect Password"
}
Status Code: 400
Body:
{
"password": "!Haruslolos123",
"newPassword": "Haruslolos123!"
}
Unauthorized
Status Code: 401
Fetch all list users
Endpoint:
Method: GET
Type:
URL: {{local}}/v1/users
Query params:
Key | Value | Description |
---|---|---|
identityNumber | 1234567898765431 |
More example Requests/Responses:
Body: None
{
"status": true,
"message": "Success",
"data": [
{
"_id": "63df5fb20a6799aeaf22f724",
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431
},
{
"_id": "63df60c87116dd7ec619891b",
"userName": "user",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432
}
]
}
Status Code: 200
Body: None
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
Fetch User
using pagination
allowed filter/search by multiple fields
- firstName
- username
- status
can be sorted by those fields as well
sortBy
= status
sortType
= desc
or asc
Endpoint:
Method: GET
Type:
URL: {{local}}/v1/users/table
More example Requests/Responses:
Body: None
{
"status": true,
"message": "Success",
"data": {
"sort": {
"updatedAt": "ASC"
},
"page": 1,
"size": 10,
"totalRecord": 2,
"totalPage": 1,
"data": [
{
"_id": "63df5fb20a6799aeaf22f724",
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431,
"createdAt": "2023-02-05T07:50:10.417Z",
"updatedAt": "2023-02-05T07:50:10.417Z"
},
{
"_id": "63df60c87116dd7ec619891b",
"userName": "user",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"createdAt": "2023-02-05T07:54:48.310Z",
"updatedAt": "2023-02-05T07:54:48.310Z"
}
]
}
}
Status Code: 200
Query:
Key | Value | Description |
---|---|---|
sortBy | status | userName, emailAddress, identityNumber, accountNumber |
sortType | desc | asc, desc and/or 0, 1 |
search | superadmin | string |
Body: None
{
"status": true,
"message": "Success",
"data": {
"sort": {
"status": "DESC"
},
"page": 1,
"size": 10,
"totalRecord": 2,
"totalPage": 1,
"data": [
{
"_id": "63df5fb20a6799aeaf22f724",
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431,
"createdAt": "2023-02-05T07:50:10.417Z",
"updatedAt": "2023-02-05T07:50:10.417Z"
}
]
}
}
Status Code: 200
Query:
Key | Value | Description |
---|---|---|
sortBy | status | firstName, username, email, status |
sortType | desc | asc, desc and/or 0, 1 |
Body: None
{
"status": true,
"message": "Success",
"data": {
"sort": {
"status": "DESC"
},
"page": 1,
"size": 10,
"totalRecord": 2,
"totalPage": 1,
"data": [
{
"_id": "63df5fb20a6799aeaf22f724",
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431,
"createdAt": "2023-02-05T07:50:10.417Z",
"updatedAt": "2023-02-05T07:50:10.417Z"
},
{
"_id": "63df60c87116dd7ec619891b",
"userName": "user",
"accountNumber": 12345672,
"emailAddress": "user@gmail.com",
"identityNumber": 1234567898765432,
"createdAt": "2023-02-05T07:54:48.310Z",
"updatedAt": "2023-02-05T07:54:48.310Z"
}
]
}
}
Status Code: 200
Body: None
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
Fetch a single user using identityNumber
Endpoint:
Method: GET
Type:
URL: {{local}}/v1/users/1234567898765431
More example Requests/Responses:
Body: None
{
"status": true,
"message": "Success",
"data": {
"_id": "63df5fb20a6799aeaf22f724",
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431
}
}
Status Code: 200
Body: None
{
"status": true,
"message": "Success",
"data": {
"_id": "63df5fb20a6799aeaf22f724",
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431
}
}
Status Code: 200
Body: None
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
Update user use JSON
payload to update a user
Endpoint:
Method: PUT
Type: RAW
URL: {{local}}/v1/users/1234567898765431
Body:
{
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431
}
More example Requests/Responses:
Body:
{
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431
}
{
"status": true,
"message": "Success",
"data": {
"_id": "63df5fb20a6799aeaf22f724",
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431,
"infoLogin": {
"hash": "d5573c28333a6ce94d61ea62a8bda6a0a7fc252eeb77c7083774ffeeb022e5d3e35ec619b2f2d5b151cf593edcb9ba0c53ce2545bb5eabc0684c65791063bef1",
"salt": "WJ0J8ANdB6oKNx+LSuge/pAONk7DYk5y+5YuAukz3igSy2CgXJ3L/daXJNiwoisYsp+QeWyXY5ljpEF+h57T+d2m467VrR0ykCree/Fg6P67/xw7ZgF7Fajto7p0ZoGSQpPs8lwuQzjEzEL4ns0o3Dhtrc+JHR/3rCFErmgL0SE=",
"iterations": 10856
},
"createdAt": "2023-02-05T09:21:44.957Z",
"updatedAt": "2023-02-05T09:21:44.957Z",
"modified": "2023-02-05T15:49:04+07:00",
"token": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiZXlKcGRpSTZJbkZRVlhaak0yMXhhMngwV1ZBclVWZ2lMQ0psYm1OeWVYQjBaV1JFWVhSaElqb2lOMVZNVVdneFFWRlJiMWRTWkRrMFVEWTFRV2c0THpaWlRYWmpOelJ0VEhWSU5HRnZMMmxVVWs1MmVHZHNNMUZJWW1JclpXdENObkJpTlZKWGNYVmtRVTFVYjJGaVMwVkJORkpKYkhZdmF6QklWbU5rTVhGTGJtVlJPV3hXYzBaVmFUUXdXU0lzSW1GMWRHZ2lPaUp6ZEVKRWNrcFNSM3BHWm10MFZtSjJSRGN3V1dSQlBUMGlmUT09IiwiaWF0IjoxNjc1NTg2OTQ0LCJleHAiOjE3NjE5ODY5NDQsImF1ZCI6ImdpdGJ1Yi5jb20vbXJib250b3IiLCJpc3MiOiJnaXRidWIuY29tL21yYm9udG9yIn0.cY-I6EY9LAkPoj9zufJADF-T3a_HvJ5Q4KoMmhn3l5U",
"ipAddress": "::1",
"userAgent": "PostmanRuntime/7.30.0",
"deviceId": "8e4535bd-cd47-4d15-85cf-8c0552a778f4",
"updateAt": "2023-02-05T15:49:04+07:00"
}
]
}
}
Status Code: 200
Body:
{
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com",
"identityNumber": 1234567898765431,
"password": "Superadmin123!"
}
{
"status": false,
"message": "Validation Error!",
"errors": [
{
"param": "password",
"key": "additionalProperties",
"message": "must NOT have additional properties"
}
]
}
Status Code: 400
Body:
{
"userName": "superadmin",
"accountNumber": 12345671,
"emailAddress": "superadmin@gmail.com"
}
{
"status": false,
"message": "Validation Error!",
"errors": [
{
"param": "identityNumber",
"key": "required",
"message": "Identity number is required!"
}
]
}
Status Code: 400
Body: None
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
Delete a single user using idUser
Only Admin can perform this API
Endpoint:
Method: DELETE
Type:
URL: {{local}}/v1/users/1234567898765435
More example Requests/Responses:
Body: None
Status Code: 204
Body: None
{
"status": false,
"message": "Token Invalid"
}
Status Code: 401
To ensure this service online, the client can request to this API first than continue main API
Endpoint:
Method: GET
Type:
URL: localhost:3000
More example Requests/Responses:
Body: None
{
"uptime": 326.873812918,
"message": "OK",
"timestamp": 1675584608234
}
Status Code: 200