express-gateway | A microservices API Gateway built on top of Express.js | REST library
kandi X-RAY | express-gateway Summary
Support
Quality
Security
License
Reuse
- Configures the pipeline
- Normalizes the gateway config .
- Authenticate a token
- Bootstrapping config .
- Authenticate A OAuth2 API request .
- register a schema
- Authenticate a local access token .
- replace all env variables in a string
- Validates the updated properties of the credential details .
- Creates a condition middleware middleware
express-gateway Key Features
express-gateway Examples and Code Snippets
Trending Discussions on express-gateway
Trending Discussions on express-gateway
QUESTION
I want to add parameters to my express gateway,
I followed official documentation. So my pipeline like that:
- name: shop
apiEndpoints:
- shop
policies:
- proxy:
- action:
serviceEndpoint: shopsrv
changeOrigin: true
- request-transformer:
- action:
body:
add:
hello: "'world'"
headers:
add:
r-test: "'header value'"
When I send request to express-gateway/shop service, gateway working without any errors.
But when I logging request header and request body from shop service
req.body :
{}
-----------------
req.headers :
{
connection: 'upgrade',
host: 'ec2-54-245-43-241.us-west-2.compute.amazonaws.com',
'accept-encoding': 'gzip, deflate, br',
'postman-token': '031920ee-c3e9-4b2f-9464-2e2c1edb3c41',
accept: '*/*',
'user-agent': 'PostmanRuntime/7.28.4',
'eg-request-id': '0hPlQg2jp7ar700zvniG2P'
}
Why I cannot add any parameters to request? Where is the problem? Please help!
ANSWER
Answered 2022-Jan-12 at 12:55The documentation for the proxy policy states that the proxy policy must come last; you need to reorder your pipeline to conform to this:
- name: shop
apiEndpoints:
- shop
policies:
- request-transformer:
- action:
body:
add:
hello: "'world'"
headers:
add:
r-test: "'header value'"
- proxy:
- action:
serviceEndpoint: shopsrv
changeOrigin: true
QUESTION
I've been trying to do a NodeJS Microservices Architecture using Docker.
I currently have 2 services : Auth API et Users CRUD API. Now my goal is to setup a Gateway using Express-Gateway.
I followed many tutorials on the web to try to set it up but whenever I try to make a request to the gateway (acting like a proxy) it sends a 502 bad gateway response..
My docker-compose.yml :
networks:
goodfood:
driver: bridge
services:
gateway:
container_name: gateway
image: 'node:17-alpine'
# env_file:
# - ./gateway/.env
working_dir: /usr/src/app
volumes:
- './gateway:/usr/src/app'
command: npm run dev
ports:
- '8080:8080'
networks:
- goodfood
auth:
container_name: auth
image: 'node:17-alpine'
# env_file:
# - ./auth/.env
working_dir: /usr/src/app
volumes:
- './auth:/usr/src/app'
command: npm run dev
ports:
- '3002:3000'
networks:
- goodfood
users:
container_name: users
image: 'node:17-alpine'
env_file:
- ./users/api/.env
working_dir: /usr/src/app
volumes:
- './users/api:/usr/src/app'
command: npm run dev
ports:
- '3001:3000'
networks:
- goodfood
depends_on:
- users-db
users-db:
container_name: users-db
image: postgres
restart: always
env_file:
- ./users/db/.env
volumes:
- './users/db/data:/var/lib/postgresql/data'
- './users/db/scripts/init.sql:/docker-entrypoint-initdb.d/init.sql'
ports:
- '5432:5432'
networks:
- goodfood
users-adminer:
container_name: users-adminer
restart: unless-stopped
image: adminer
ports:
- '8181:8080'
networks:
- goodfood
depends_on:
- users-db
And my gateway.config.yml :
http:
port: 8080
admin:
port: 9876
host: localhost
apiEndpoints:
users:
path: ['/users', '/users/*']
auth:
path: ['/auth', '/auth/*']
serviceEndpoints:
users:
url: 'http://users:3001'
auth:
url: 'http://auth:3002'
policies:
- log
- proxy
# - jwt
# - request-transformer
pipelines:
authPipeline:
apiEndpoints:
- auth
policies:
- log:
action:
message: 'auth ${req.method}'
- proxy:
- action:
serviceEndpoint: auth
changeOrigin: true
usersPipeline:
apiEndpoints:
- users
policies:
- log:
action:
message: 'users ${req.method}'
- proxy:
- action:
serviceEndpoint: users
changeOrigin: true
# - jwt:
# action:
# secretOrPublicKey: 'goodfood'
# checkCredentialExistence: false
# - request-transformer:
# action:
# body:
# add:
# user: req.user
If you need further details there's a github repo : https://github.com/KIVTVN/goodfood/tree/master
ANSWER
Answered 2021-Dec-10 at 19:41The problem lies in your gateway-config.xml file. It is not referring correctly to the ports defined in docker-compose.xml.
The docker-compose.xml ports command is HOST:CONTAINER, so what the host refers to as 3001 for the users container, is port 3000 within the Docker. Express Gateway is running in Docker, so the service endpoints need to refer to the ports as they appear to other containers (they are distinguished by internal hostname as defined in the docker-compose.xml file rather than by port at this level):
serviceEndpoints:
users:
url: http://users:3000
auth:
url: http://auth:3000
If you want to hit these URLs from outside Docker, you'll need to specify the port (3001, 3002, etc).
QUESTION
I'm using Express Gateway
to proxy my microservices. I'm hitting the gateway from my react
app with Axios
. However, the call gets restricted by the CORS Policy
. I have enabled CORS in the express gateway and also on my authentication service. I followed the official documentation to enable the CORS from this link for Express Gateway and this link for authentication service(Express App). Here is how I have the code.
Express Gateway config.yml
policies:
- log
- proxy
- jwt
- rate-limit
- request-transformer
- cors
pipelines:
authPipeline:
apiEndpoints:
- auth
policies:
-
cors:
-
action:
origin: '*'
methods: 'HEAD,PUT,PATCH,POST,DELETE'
allowedHeaders: ['Content-Type', 'Authorization']
-
log:
action:
message: 'auth ${req.method}'
-
proxy:
action:
serviceEndpoint: di
Authentication Service app.js
const cors = require('cors');
// Enabling CORS
const corsOptions = {
origin: '*',
methods: ['POST', 'GET', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}
app.use(cors(corsOptions));
The Headers I get back from the server when I try with Insomnia (a client like Postman) can be seen in the below picture.
I get this error in the browser console.
Access to XMLHttpRequest at 'http://127.0.0.1:8080/api/v1/users/login' from
origin 'http://localhost:3000' has been blocked by CORS policy: Response to
preflight request doesnt pass access control check: No 'Access-Control-
Allow-Origin' header is present on the requested resource.
I'm not sure what I'm missing. Please let me know if you need anything else, I'd be quick to provide. Each and every attempt that tries to explain what's wrong with my case is really appreciated.
EDIT: Adding the API call snippet
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const body = JSON.stringify({ email, password });
const res = await axios.post('http://127.0.0.1:8080/api/v1/users/login', body, config);
ANSWER
Answered 2021-Mar-28 at 12:31Your "methods" definition is incorrect. It needs to be in the form of a YAML array:
methods: [ "HEAD", "PUT", "PATCH", "POST", "DELETE" ]
Or
methods:
- "HEAD"
- "PUT"
- "PATCH"
- "POST"
- "DELETE"
Or
methods:
- HEAD
- PUT
- PATCH
- POST
- DELETE
Everything else looks okay, although you may want to add "origin" to the list of allowedHeaders.
Update I have done some further testing on this, using this mini express server, then run the API gateway and server on Docker (with appropriate hostname changes in gateway.config.yml), and everything works as I expect with testing via curl from localhost and also from the browser.
var express = require('express')
var app = express()
// Enabling CORS
const cors = require('cors');
const corsOptions = {
origin: '*',
methods: ['POST', 'GET', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}
app.use(cors(corsOptions));
function addPath(path) {
app.use(path, function(req, res, next) {
const response = `Hello from ${req.method} ${path}`;
console.log(response);
res.send(response);
});
}
addPath('/api/v1/users/*');
addPath('/api/v1/*');
const port = 5000;
app.listen(port, function () {
console.log(`Example app listening on port ${port}`)
})
The only other thing I can suggest is to add another log message before the cors policy entry in gateway.config.yml like this:
- log: action: message: "incoming (auth): ${req.method} ${req.path} requesting IP: ${req.ip} origin ${req.headers.origin}"
and check the value of origin. If it is not undefined, try adding the following response-transformer before the proxy policy (adding response-transformer to the list of available policies, of course). I have had to do this once or twice but I forget the circumstances where it was necessary, so this is a shot in the dark.
- response-transformer:
- condition:
name: expression
expression: 'typeof req.headers.origin !== "undefined" && req.headers.origin === "http://localhost"'
action:
headers:
add:
access-control-allow-origin: '"http://localhost"'
QUESTION
Im trying to configure api-gateway for my micro service study. I created a pod as a auth-depl and auth-src service for this pod. Also I have another pod&service as links-depl and links-serv. And I want to make a api-gateway for. these services.
The output for "kubeectl get pods":
NAME READY STATUS RESTARTS AGE
api-gateway-depl-88b4c8b77-zdgjw 1/1 Running 0 10m
auth-depl-7cb78c4dcf-wxrwd 1/1 Running 0 10m
links-depl-69d749955d-5xf9b 1/1 Running 0 6m3s
The output for "kubectl get services":
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api-gateway-srv NodePort 10.98.213.62 8080:30623/TCP 12m
auth-srv ClusterIP 10.98.214.62 3000/TCP 12m
kubernetes ClusterIP 10.96.0.1 443/TCP 25h
links-srv ClusterIP 10.99.37.46 3001/TCP 12m
And my express-gateway config file like that:
http:
port: 8080
admin:
port: 9876
host: localhost
apiEndpoints:
api:
host: localhost
paths: '/ip'
user:
host: localhost
paths: '/user/signup'
serviceEndpoints:
httpbin:
url: 'https://httpbin.org'
usersrv:
url: 'http://auth-srv:3000/user/signup'
policies:
- basic-auth
- cors
- expression
- key-auth
- log
- oauth2
- proxy
- rate-limit
pipelines:
default:
apiEndpoints:
- api
policies:
- proxy:
- action:
serviceEndpoint: httpbin
changeOrigin: true
I just tried to reach auth service with api-gateway, but I cannot do this. For this, I send this request:
POST http://localhost:30623/user/signup
and I get "Cannot POST /user/signup error
but when I send a request to GET http://localhost:30624/ip
I can receive the response.
How can I configure this gateway.config.yaml file for solving my issue.
ANSWER
Answered 2021-Feb-20 at 11:12In Express Gateway, you need to have a pipeline defined for each of your ApiEndpoints. You have a pipeline which maps the (outside-facing) "api" endpoint to the service endpoint "httpbin", but you are missing one to map the "user" endpoint to your signup endpoint.
You need to add a pipeline for this to your "pipelines" section:
pipelines:
# Existing "default" pipeline
user:
apiEndpoints:
- user
policies:
- proxy:
- action:
serviceEndpoint: usersrv
changeOrigin: true
QUESTION
I'm trying to modify a graphql query variable using express-gateway
.
The code on the gateway is as below,
const axios = require("axios");
const jsonParser = require("express").json();
const { PassThrough } = require("stream");
module.exports = {
name: 'gql-transform',
schema: {
... // removed for brevity sakes
},
policy: (actionParams) => {
return (req, res, next) => {
req.egContext.requestStream = new PassThrough();
req.pipe(req.egContext.requestStream);
return jsonParser(req, res, () => {
req.body = JSON.stringify({
...req.body,
variables: {
...req.body.variables,
clientID: '1234'
}
});
console.log(req.body); // "clientID": "1234" is logged in the body.variables successfully here
return next();
});
};
}
};
Now, when I hit the request from POSTMAN, the request goes through and returns a 200OK only when I include clientID
, otherwise, it throws as error
"message": "Variable "$clientID" of required type "ID!" was not provided."
Any idea what could be going wrong here?
ANSWER
Answered 2021-Feb-16 at 12:18The only way I could get this working was by using node-fetch
and then making a fetch
request to the graphql-sever from my middleware instead of doing a return next()
and following the middleware chain.
My setup is something like the following,
Client (vue.js w/ apollo-client) ---> Gateway (express-gateway) ---> Graphql (apollo-server) ---> Backend REST API (*)
When my client makes a graphql request to my gateway, I've modified my middleware to do the following (as opposed to what's in the question),
const jsonParser = require("express").json();
const fetch = require('node-fetch');
module.exports = {
name: 'gql-transform',
schema: {
... // removed for brevity sakes
},
policy: () => {
return (req, res) => {
jsonParser(req, res, async () => {
try {
const response = await fetch(`${host}/graphql`, {...}) // removed config from fetch for brevity
res.send(response);
} catch (error) {
res.send({ error });
}
});
};
}
};
QUESTION
I have currently configured express-gateway to communicate with a service on my backend exposed on a unique port on my machine and it's working fine. The gateway serves as a proxy to the services and currently does some security checks and jwt authentication. Then, only authorized request (through jwt validation) gets sent to services as configured. However, I'm concerned that if I don't put some sort of authentication on my service, then anyone who knows the port (or URL) my service runs on can directly access it and bypass the gateway directly. I'm looking for a way I can set up a sort of auth between the gateway and the service (maybe through keys) so that only the gateway can communicate with the services and not any other client. I currently can't find anything in the docs specifically for that. Also, if there's something wrong with my architecture, I'd appreciate it if you could point it out. Thank you.
ANSWER
Answered 2020-Oct-15 at 11:23The path between Express Gateway and your back end should be on a private, encrypted network so there is no way for anyone to bypass the gateway.
With this architecture, you don’t need to authenticate on the server side, and if you use Express Gateway scopes, you don’t even need to check whether the user is authorized to perform the requested action.
QUESTION
I am using a Redis DB to use an Express-Gateway on Heroku. I would like to know how to set Redis credentials as a unique URL-param, instead of using separated vars.
Right now, Express Gateway reads credentials from the file system.config.yml
, where credentials structure is
# Core
db:
redis:
host: [host]
port: [port]
namespace: [namespace]
password: [password]
Unfortunately, Redis on Heroku automatically sets credentials as a .ENV var, in the form of URL:
REDIS_URL = "redis://h:[psw]@[host]:[port]"
How can I make Express-Gateway reads credentials from .ENV instead of system.config.yml
? Or, how can I make system.config.yml
reads from .ENV the whole URL?
Even worst, credentials are not permanent, and are changed periodically without alert. So, how can I make Express-Gateway connect to Redis on Heroku?
Thank you
ANSWER
Answered 2020-Aug-28 at 13:43Express Gateway's configuration files support environment variables — check that out and you should be good to go!
QUESTION
I'm creating an express JS microservices architecture and I'm using express-gateway as an API gateway.
I can expose my services and endpoints through the express gateway , one of the services (Books) has 2 roles (admin, user) with 2 different login startegies (the admin uses JWT and the user uses Firebase auth).
I succeeded in security the admin endpoint /v1/admin with the JWT provided with express-gateway, now I want to create a policy / plugin (I didn't understand the difference) to involve my CheckIfAuthenticatedFirebase Middleware to secure my user endpoint /v1/user.
So I need some help to understand if I must create a plugin or a policy and the steps to do it.
Here is my gateway.config.yml :
http:
port: 8080
admin:
port: 9876
host: localhost
apiEndpoints:
bookAdmin:
path: '/v1/admin*'
bookUser:
path: '/v1/user*'
serviceEndpoints:
book:
url: 'http://localhost:5000'
policies:
- cors
- log
- proxy
- jwt
- request-transformer
pipelines:
bookAdminPipeline:
apiEndpoints:
- bookAdmin
policies:
-
cors:
action:
origin: '*'
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE'
-
jwt:
action:
secretOrPublicKey: 'JWTKey'
checkCredentialExistence: false
-
proxy:
action:
serviceEndpoint: book
bookUserPipeline:
apiEndpoints:
- bookUser
policies:
-
cors:
action:
origin: '*'
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE'
-
proxy:
action:
serviceEndpoint: book
Here is my firebase-middleware.js :
var admin = require('../authentication/firebase');
getAuthToken = (req, res, next) => {
if (
req.headers.authorization &&
req.headers.authorization.split(' ')[0] === 'Bearer'
) {
req.authToken = req.headers.authorization.split(' ')[1];
} else {
req.authToken = null;
}
next();
};
checkIfAuthenticated = (req, res, next) => {
getAuthToken(req, res, async () => {
try {
const { authToken } = req;
const userInfo = await admin
.auth()
.verifyIdToken(authToken);
req.authId = userInfo.uid;
return next();
} catch (e) {
return res
.status(401)
.send({ error: 'You are not authorized to make this request' });
}
});
};
module.exports = checkIfAuthenticated
Thanks a lot
ANSWER
Answered 2020-Jun-03 at 22:21You have to create a policy and invoke it via plugin.
- Make a folder in your plugins directory, let's say folder name is auth.
- inside that auth folder, create a folder policies and a file manifest.js
- create a file auth.js inside policies folder.
- inside manifest.js write this piece of code
module.exports = {
version: '1.2.0',
init: function (pluginContext) {
let policy = require('./policies/auth')
pluginContext.registerPolicy(policy)
},
policies:['auth'], // this is for CLI to automatically add to "policies" whitelist in gateway.config
schema: { // This is for CLI to ask about params 'eg plugin configure customer-auth'
"$id":"https://express-gateway.io/schemas/plugins/blacklist.json"
}
}
- Your auth.js file should look like this
module.exports = {
name: 'auth',
schema: {
$id: 'http://express-gateway.io/schemas/policies/example-policy.json',
type: 'object',
properties: {
baseUrl: {
type: 'string',
format: 'url',
default: ''
}
}
},
policy: (actionParams) => {
const that = this;
return (req, res, next) => {
// your custom logic
};
}
};
Now you just have to put the manifest path in the system.config.yml
plugins:
auth:
package: "../../../plugins/auth/manifest.js"
And last step will be declaring this policy in the gateway.config.yml file in the policies section
policies:
- basic-auth
- cors
- expression
- request-transformer
- key-auth
- log
- oauth2
- proxy
- rate-limit
- auth
Now you can easily use it like any other policy. :)
QUESTION
I'm deploying a microservices nodejs express application to GKE, I successfully deployed the services (one as Ingress service with static IP @ and one as NodePort service which will not be exposed to Internet).
Now I'm trying to deploy the api gateway which is an express-gateway application, I deployed it in first time as a LoadBalancer service and it's working , here is my service code :
apiVersion: v1
kind: Service
metadata:
name: express-gateway-balancer
spec:
selector:
app: express-gateway
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 8080
Now I must transform the trafic to HTTPS to be able to call the API endpoints front my react frontend application which is running with HTTPS, so I did a research and the way is to expose the api gateway application as an Ingress not LoadBalancer.
So I did the changes (the same I did with the rest of my deployments)and created a static IP @ "gateway-ip" to expose it via Ingress :
Here is my service.yaml file :
apiVersion: v1
kind: Service
metadata:
name: express-gateway-service
spec:
selector:
app: express-gateway
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 8080
My Ingress.yaml file :
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: gateway-service-ingress
annotations:
kubernetes.io/ingress.global-static-ip-name: "gateway-ip"
spec:
backend:
serviceName: express-gateway-service
servicePort: 80
Here is my deployment file :
apiVersion: apps/v1
kind: Deployment
metadata:
name: express-gateway
labels:
app: express-gateway
spec:
selector:
matchLabels:
app: express-gateway
replicas: 3
template:
metadata:
labels:
app: express-gateway
spec:
containers:
- name: express-gateway
image: gcr.io/PROJECT_ID/apigatewayservice:v1
ports:
- name: gateway
containerPort: 8080
- name: admin
containerPort: 9876
ANSWER
Answered 2020-Jun-01 at 22:35Do you have a default endpoint of all your scheduled pods? I mean "/" ? Ingress does the health check readiness prob inbuilt that checks if "/" is reachable or not. If not, it will declare it as unhealthy. Hope this helps.
QUESTION
I have deployed my express-gateway on Heroku, using env variables in this way in the gateway.config.yml
file:
http:
port: ${PORT:-8080}
host: ${HOST:-localhost}
https:
port: ${PORT:-8080}
host: ${HOST:-localhost}
apiEndpoints:
....
Anyway Heroku keeps giving this error:
[EG:gateway] gateway http server listening on :::8080
State changed from starting to crashed
Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
I have used the notation ${ENV_VAR_NAME:-DEFAULT}
according to official documentation. Why Heroku tries to bind the 8080?
ANSWER
Answered 2020-Jan-30 at 13:22You should not make listen both the http and the https server on the same port, otherwise it's going to fail.
Heroku provides its own router handling the SSL termination for you, so you can just remove the whole https
section.
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
Vulnerabilities
No vulnerabilities reported
Install express-gateway
Support
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
Find more librariesExplore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits
Save this library and start creating your kit
Share this Page