API gateway for build with adonisjs this is of making life easy for microservices and nodejs enthusiast.
The stack
- Adonis framework
- TypeScript language
-
Clone the project from github.
git clone https://github.com/baridibaridi-com/adonis-api-gateway.git
-
Run npm install command to install all dependencies.
npm install
-
Create a
.env
file and paste in the the following contents in the created.env
file.PORT=3333 HOST=0.0.0.0 NODE_ENV=development APP_KEY= DRIVE_DISK=local # Database connection # ~~~ DB_CONNECTION=pg PG_HOST=localhost PG_PORT=5432 PG_USER= PG_PASSWORD= PG_DB_NAME=
-
Craate APP_KEY by running this command
node ace key:generate
-
Create database connection to postgreSQL by filling out
database user
,password
anddatabase name
in the.env
file. -
Perform database migration to create database schema in postgreSQL database.
node ace migration:run
-
Migrate initial data to the database required to run and test the API.
node ace db:seed
-
Serve the API. Run the following command.
node ace serve --watch
you must define your microservices urls in the endpoints.json
file which is located on the roor directory of the project.
{
/**
*
* Version for the endpoints file currently its at verision 1 so please v1 as the default valie
* default value "v1"
*
*/
"version": "v1",
/**
*
* The "authors" key is the array of object containg author name , email and phone
* mandatory filed are "name", "email", "phone"
*
*/
"authors": [
{ "name": "Michael Omakei", "email": "[email protected]", "phone": "+255625933171" } // authors name
],
/**
* The "endpoint" key contains the list of all backend services
* the service object must have "endpoint" key which contain the endpoint which the
* public will use to access the backend service
* The "backend" key contain the object which defiends array of hosts, url_pattern and timeout for calling
* that backend service(s)
*
*/
"endpoints": [
{
"endpoint": "/customers",
"backend": [
{
"host": ["http://127.0.0.1:3332"],
"url_pattern": "/",
"timeout": 2000
}
]
},
{
"endpoint": "/activation-codes",
"backend": [
{
"host": ["http://127.0.0.1:3330"],
"url_pattern": "/",
"timeout": 2000
}
]
}
]
}
You can use this endpoint to register user who want to access backend services
const response = await axios.post('http://127.0.0.1:3333/api-gateway/users/register').form({
username: 'omakei',
email: '[email protected]',
password: 'secret',
country: 'TZ',
roles: [{ id: 1 }, { id: 2 }, { id: 3 }],
permissions: [{ id: 1 }, { id: 2 }, { id: 3 }],
})
//Respose stracture
{
message: 'user created successful.',
status: true,
payload: {
username: 'omakei',
email: '[email protected]',
country: 'TZ',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id: 1,
},
}
You can use this endpoint to status of the user who want to access backend services
const response = await axios.get('http://127.0.0.1:3333/api-gateway/users/change-user-status/2')
// response stracture
{
message: 'user status updated successful.',
status: true,
payload: {
username: user.username,
country: null,
is_active: false,
remember_me_token: null,
email: '[email protected]',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id: 2,
},
}
You can use this endpoint to update user who want to access backend services
const response = await axios.put('http://127.0.0.1:3333/api-gateway/users/update/2').form({
username: 'omakei',
email: '[email protected]',
password: 'secret',
country: 'TZ',
roles: [{ id: 1 }, { id: 2 }, { id: 3 }],
permissions: [{ id: 1 }, { id: 2 }, { id: 3 }],
})
//response stracture
{
message: 'user updated successful.',
status: true,
payload: {
username: 'omakei',
email: '[email protected]',
country: 'TZ',
is_active: true,
remember_me_token: null,
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id: 2,
},
}
You can use this endpoint to delete user who want to access backend services
const response = await axios.delete('http://127.0.0.1:3333/api-gateway/users/delete/2').form({
username: 'omakei',
email: '[email protected]',
password: 'secret',
country: 'TZ',
roles: [{ id: 1 }, { id: 2 }, { id: 3 }],
permissions: [{ id: 1 }, { id: 2 }, { id: 3 }],
})
//response stracture
{
message: 'user deleted successful.',
status: true,
payload: {
username: 'omakei',
email: '[email protected]',
country: 'TZ',
is_active: true,
remember_me_token: null,
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id: 2,
},
}
You can use this endpoint to login the user who want to access backend services
const response = await axios.post('http://127.0.0.1:3333/login').form({ email: '[email protected]', password: 'secret' })
//response stracture
{
message: 'authenticated',
status: true,
payload: {
type: 'bearer',
token: eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI,
refreshToken: '8028ff82a5e4770fe5bfb2a3aa10323f0597ef70c8925577d6e7ff94b209493f',
expires_at: '2022-08-20 11:11:11',
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to refresh token of the user who want to access backend services
const response = await axios.post('http://127.0.0.1:3333/refresh')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
.form({ refresh_token: '8028ff82a5e4770fe5bfb2a3aa10323f0597ef70c8925577d6e7ff94b209493f' })
//response stracture
{
message: 'authenticated',
status: true,
payload: {
type: 'bearer',
token: eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI,
refreshToken: '8028ff82a5e4770fe5bfb2a3aa10323f0597ef70c8925577d6e7ff94b209493f',
expires_at: '2022-08-20 11:11:11',
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can send request to backend services base on the endpoint defined on endpoints.json
file
for each backend request must contain a x-bbtz-url
which defines the uri at microservice side to call
For example if i want to call customers microservice's address url
and get the response as defined at this microservice.
const response = await axios.get('http://127.0.0.1:3333/customers')
.header('x-bbtz-url', '/address')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
//response stracture
{
contact: { phone: '+25562593171', address: 'Kilimanjaro Moshi' },
}
//error response stracture
{
message: 'No x-bbtz-url header was passed.',
status: false,
errors: [
{ rule: 'check header', field: 'header', message: 'No x-bbtz-url header was passed.' },
],
}
//or if jwt is wrong
{ message: 'Authentication failed.' }
You can use this endpoint to logout the user who want to access backend services
const response2 = await axios
.get('http://127.0.0.1:3333/me')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
//response stracture
{
message: 'fetched successful.',
status: true,
payload: {
user: {
id: user.id,
username: user.username,
email: user.email,
is_active: true,
roles: [
{
id: 1,
name: 'admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
},
{
id: 1,
name: 'admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
}
],
permissions: [
{
id: 1,
name: 'cs_team.create',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
},
{
id: 1,
name: 'cs_team.read',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
}
],
},
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to logout the user who want to access backend services
const response2 = await axios
.post('http://127.0.0.1:3333/logout')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
.form({ refresh_token: '8028ff82a5e4770fe5bfb2a3aa10323f0597ef70c8925577d6e7ff94b209493f' })
//response stracture
{
message: 'logout successful',
status: true,
payload: {
type: null,
token: null,
refreshToken: null,
expires_at: null,
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to list role
const response2 = await axios
.get('http://127.0.0.1:3333/api-gateway/roles/index')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
//response stracture
{
message: 'fetched successful.',
status: true,
payload: [
{
id: 1,
name: 'admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
},
{
id: 1,
name: 'admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
}
],
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to list permissions
const response2 = await axios
.get('http://127.0.0.1:3333/api-gateway/roles/permissions')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
//response stracture
{
message: 'fetched successful.',
status: true,
payload: [
{
id: 1,
name: 'cs_team.create',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
},
{
id: 1,
name: 'cs_team.read',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11'
}
]
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to create role
const response2 = await axios
.post('http://127.0.0.1:3333/api-gateway/roles/store')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
.form({ name: 'admin', description: 'admin', permissions: [{ id: 1 }, { id: 2 }, { id: 3 }] })
//response stracture
{
message: 'fetched successful.',
status: true,
payload: {
name: 'admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id:1,
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to update role
const response2 = await axios
.put('http://127.0.0.1:3333/api-gateway/roles/update/1')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
.form({ name: 'omakei is admin', description: 'admin', permissions: [{ id: 1 }, { id: 2 }, { id: 3 }] })
//response stracture
{
message: 'updated successful.',
status: true,
payload: {
name: 'omakei is admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id:1,
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to show role
const response2 = await axios
.get('http://127.0.0.1:3333/api-gateway/roles/show/1')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
//response stracture
{
message: 'fetched successful.',
status: true,
payload: {
name: 'omakei is admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id:1,
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
You can use this endpoint to show role
const response2 = await axios
.delete('http://127.0.0.1:3333/api-gateway/roles/delete/1')
.header('Authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXIiOnsiaWQiOjEsInVzZXJuYW1lIjoiTWljaGFlbCBPbWFrxfSwiaWF0IjoxNjYyMTE3MDEzLCJleHAiOjE2NjIxMjA2MTN9.zWDXeGqUK3DroLXt3wUuh_ISNw14b12M9nrzh_jDnbxA4MlQDln0Dv5k6rpyIz045X4cD8dVp9LqxudkdMwgFKdhI')
//response stracture
{
message: 'deleted successful.',
status: true,
payload: {
name: 'omakei is admin',
description: 'admin',
created_at: '2022-08-20 11:11:11',
updated_at: '2022-08-20 11:11:11',
id:1,
},
}
//Error response stracture
{
message: 'Invalid credentials',
status: false,
errors: [
{
message: 'Invalid credentials',
field: 'Authentication',
rule: 'Authentication',
},
],
}
node ace test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.