tobok-sitanggang-betest

Simple microservice with NodeJs, Express , MongoDB and Redis

Requirements

Settings & Configuring

App config

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
....

Database config

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

Deployment && Testing

Deployment

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

Testing

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

Endpoints


AUTH

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 body
  • refreshToken will be returned as Cookie with name RTOKEN
  • deviceId is the device identifier and will be returned as a Cookie with name DID

1. LOGIN

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:

I. Example Request: Success

Body:

{
    "accountNumber": 12345671,
    "password": "Superadmin123!"
}

I. Example Response: Success

{
    "status": true,
    "message": "Success",
    "data": {
        "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJOYW1lIjoic3VwZXJhZG1pbiIsImFjY291bnROdW1iZXIiOjEyMzQ1NjcxLCJpZGVudGl0eU51bWJlciI6MTIzNDU2Nzg5ODc2NTQzMX0sImlhdCI6MTY3NTU4NTIyOSwiZXhwIjoxNzExNTg4ODI5LCJhdWQiOiJnaXRidWIuY29tL21yYm9udG9yIiwiaXNzIjoiZ2l0YnViLmNvbS9tcmJvbnRvciJ9.QC0dGYt6Rd3Nou3jc8gD9i-Bmseg26Pg0Y02gNFwIGw"
    }
}

Status Code: 200


II. Example Request: Un Authorized / wrong credential

Body:

{
    "accountNumber": 12345678,
    "password": "Superadmin123!"
}

II. Example Response: Un Authorized / wrong credential

{
    "status": false,
    "message": "Un Authorized!"
}

Status Code: 401


2. SIGNUP

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:

I. Example Request: Success

Body:

{
    "userName": "user",
    "accountNumber": 12345672,
    "emailAddress": "user@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

I. Example Response: Success

{
    "status": true,
    "message": "Success",
    "data": "63df60c87116dd7ec619891b"
}

Status Code: 200


II. Example Request: Err username exists

Body:

{
    "userName": "user",
    "accountNumber": 12345672,
    "emailAddress": "user@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

II. Example Response: Err username exists

{
    "status": false,
    "message": "The userName has been registered!"
}

Status Code: 400


III. Example Request: Err email exist

Body:

{
    "userName": "user1",
    "accountNumber": 12345672,
    "emailAddress": "user@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

III. Example Response: Err email exist

{
    "status": false,
    "message": "The emailAddress has been registered!"
}

Status Code: 400


IV. Example Request: Err identityNumber exist

Body:

{
    "userName": "user1",
    "accountNumber": 12345672,
    "emailAddress": "user1@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

IV. Example Response: Err identityNumber exist

{
    "status": false,
    "message": "The identityNumber has been registered!"
}

Status Code: 400


V. Example Request: Err accountNumber exist

Body:

{
    "userName": "user1",
    "accountNumber": 12345672,
    "emailAddress": "user1@gmail.com",
    "identityNumber": 1234567898765411,
    "password": "iamUser123!"
}

V. Example Response: Err accountNumber exist

{
    "status": false,
    "message": "The accountNumber has been registered!"
}

Status Code: 400


3. REFRESH

Fetch new Token as a refresh token

Endpoint:

Method: GET
Type: 
URL: {{local}}/v1/auth/refresh-token

More example Requests/Responses:

I. Example Request: Success

Body: None

I. Example Response: Success

{
    "status": true,
    "message": "Success",
    "data": {
        "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJOYW1lIjoic3VwZXJhZG1pbiIsImFjY291bnROdW1iZXIiOjEyMzQ1NjcxLCJpZGVudGl0eU51bWJlciI6MTIzNDU2Nzg5ODc2NTQzMX0sImlhdCI6MTY3NTU4NjA1MSwiZXhwIjoxNzExNTg5NjUxLCJhdWQiOiJnaXRidWIuY29tL21yYm9udG9yIiwiaXNzIjoiZ2l0YnViLmNvbS9tcmJvbnRvciJ9.6wZWjm5yqqiHdXX6Mjdmf_ZnoULI05C6FhS-HuCGZAw"
    }
}

Status Code: 200


II. Example Request: Un Authorized

Body: None

II. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


4. LOGOUT

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:

I. Example Request: Sucesss

Query:

Key Value Description
allDevices true true or false

Body: None

Status Code: 204


II. Example Request: Un Authorized

Query:

Key Value Description
allDevices true true or false

Body: None

II. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


USER

Users directory contains all the user related APIs. For authentication these apis requrie AuthBearerToken

1. CREATE

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:

I. Example Request: Success

Body:

{
    "userName": "user",
    "accountNumber": 12345672,
    "emailAddress": "user@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

I. Example Response: Success

{
    "status": true,
    "message": "Success",
    "data": "63df60c87116dd7ec619891b"
}

Status Code: 200


II. Example Request: Err username exists

Body:

{
    "userName": "user",
    "accountNumber": 12345672,
    "emailAddress": "user@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

II. Example Response: Err username exists

{
    "status": false,
    "message": "The userName has been registered!"
}

Status Code: 400


III. Example Request: Err email exist Copy

Body:

{
    "userName": "user1",
    "accountNumber": 12345672,
    "emailAddress": "user@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

III. Example Response: Err email exist Copy

{
    "status": false,
    "message": "The emailAddress has been registered!"
}

Status Code: 400


IV. Example Request: Err identityNumber exist

Body:

{
    "userName": "user1",
    "accountNumber": 12345672,
    "emailAddress": "user1@gmail.com",
    "identityNumber": 1234567898765432,
    "password": "iamUser123!"
}

IV. Example Response: Err identityNumber exist

{
    "status": false,
    "message": "The identityNumber has been registered!"
}

Status Code: 400


V. Example Request: Err accountNumber exist

Body:

{
    "userName": "user1",
    "accountNumber": 12345672,
    "emailAddress": "user1@gmail.com",
    "identityNumber": 1234567898765411,
    "password": "iamUser123!"
}

V. Example Response: Err accountNumber exist

{
    "status": false,
    "message": "The accountNumber has been registered!"
}

Status Code: 400


VI. Example Request: Un Authorized

Body:

{
    "userName": "superadmin",
    "accountNumber": 12345671,
    "emailAddress": "superadmin@gmail.com",
    "identityNumber": 1234567898765431,
    "password": "Superadmin123!"
}

VI. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


2. UPDATE CREDENTIAL

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:

I. Example Request: Success

Body:

{
    "password": "Superadmin123!!",
    "newPassword": "Superadmin123!"
}

Status Code: 204


II. Example Request: Incorrect Password

Body:

{
    "password": "Superadmin123!",
    "newPassword": "Superadmin123!!"
}

II. Example Response: Incorrect Password

{
    "status": false,
    "message": "Incorect Password"
}

Status Code: 400


III. Example Request: Un Authorized, password has changed

Body:

{
    "password": "!Haruslolos123",
    "newPassword": "Haruslolos123!"
}

III. Example Response: Un Authorized, password has changed

Unauthorized

Status Code: 401


3. GET ALL

Fetch all list users

Endpoint:

Method: GET
Type: 
URL: {{local}}/v1/users

Query params:

Key Value Description
identityNumber 1234567898765431

More example Requests/Responses:

I. Example Request: Success

Body: None

I. Example Response: Success

{
    "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


II. Example Request: Un Authorized

Body: None

II. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


4. GET TABLE

Fetch User using pagination

allowed filter/search by multiple fields

  • firstName
  • username
  • email
  • 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:

I. Example Request: Success

Body: None

I. Example Response: Success

{
    "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


II. Example Request: Success with filter user

Query:

Key Value Description
sortBy status userName, emailAddress, identityNumber, accountNumber
sortType desc asc, desc and/or 0, 1
search superadmin string

Body: None

II. Example Response: Success with filter user

{
    "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


III. Example Request: Success with sort

Query:

Key Value Description
sortBy status firstName, username, email, status
sortType desc asc, desc and/or 0, 1

Body: None

III. Example Response: Success with sort

{
    "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


IV. Example Request: Un Authorized

Body: None

IV. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


5. GET ONE

Fetch a single user using identityNumber

Endpoint:

Method: GET
Type: 
URL: {{local}}/v1/users/1234567898765431

More example Requests/Responses:

I. Example Request: Success without cache

Body: None

I. Example Response: Success without cache

{
    "status": true,
    "message": "Success",
    "data": {
        "_id": "63df5fb20a6799aeaf22f724",
        "userName": "superadmin",
        "accountNumber": 12345671,
        "emailAddress": "superadmin@gmail.com",
        "identityNumber": 1234567898765431
    }
}

Status Code: 200


II. Example Request: Success with cache

Body: None

II. Example Response: Success with cache

{
    "status": true,
    "message": "Success",
    "data": {
        "_id": "63df5fb20a6799aeaf22f724",
        "userName": "superadmin",
        "accountNumber": 12345671,
        "emailAddress": "superadmin@gmail.com",
        "identityNumber": 1234567898765431
    }
}

Status Code: 200


III. Example Request: Un Authorized

Body: None

III. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


6. PUT

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:

I. Example Request: Success

Body:

{
    "userName": "superadmin",
    "accountNumber": 12345671,
    "emailAddress": "superadmin@gmail.com",
    "identityNumber": 1234567898765431
}

I. Example Response: Success

{
    "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


II. Example Request: Err Validation additionalProperties

Body:

{
    "userName": "superadmin",
    "accountNumber": 12345671,
    "emailAddress": "superadmin@gmail.com",
    "identityNumber": 1234567898765431,
    "password": "Superadmin123!"
}

II. Example Response: Err Validation additionalProperties

{
    "status": false,
    "message": "Validation Error!",
    "errors": [
        {
            "param": "password",
            "key": "additionalProperties",
            "message": "must NOT have additional properties"
        }
    ]
}

Status Code: 400


III. Example Request: Err Valdation required field(s)

Body:

{
    "userName": "superadmin",
    "accountNumber": 12345671,
    "emailAddress": "superadmin@gmail.com"
}

III. Example Response: Err Valdation required field(s)

{
    "status": false,
    "message": "Validation Error!",
    "errors": [
        {
            "param": "identityNumber",
            "key": "required",
            "message": "Identity number is required!"
        }
    ]
}

Status Code: 400


IV. Example Request: Un Authorized

Body: None

IV. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


7. DELETE

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:

I. Example Request: Success

Body: None

Status Code: 204


II. Example Request: Un Authorized

Body: None

II. Example Response: Un Authorized

{
    "status": false,
    "message": "Token Invalid"
}

Status Code: 401


Ungrouped

1. HEALTH CHECK

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:

I. Example Request: Service Online

Body: None

I. Example Response: Service Online

{
    "uptime": 326.873812918,
    "message": "OK",
    "timestamp": 1675584608234
}

Status Code: 200



Back to top