Currently working on an Express Gateway that handles call for an RESTAPI and a GraphQL microservices. The GraphQL pipeline works fine, but the pipeline for the RESTAPI is what I'm struggling with.
I made a simple CRUD functionality RESTAPI that can create, read, update and delelete books and authors. They have multiple routes to do this, like: http://localhost:4001/books/add.
The problem is that I dont really understand how to translate these routes or paths in tho the express gateway so I can reach them via the gateway.
This is my current code, config.yml:
http:
port: 8080
admin:
port: 9876
host: localhost
apiEndpoints:
restapi:
host: localhost
paths: '/rp'
graphql:
host: localhost
paths: '/gql'
serviceEndpoints:
restapi:
url: 'http://localhost:4001/'
graphql:
url: 'http://localhost:4000'
policies:
- proxy
pipelines:
restapi:
apiEndpoints:
- restapi
policies:
- proxy:
- action:
serviceEndpoint: restapi
changeOrigin: true
ignorePath: false
prependPath: true
stripPath: true
graphql:
apiEndpoints:
- graphql
policies:
- proxy:
- action:
serviceEndpoint: graphql
changeOrigin: true
This is the restapi book code:
const express = require('express');
const mongoose = require('mongoose');
const book = require('../models/book');
const { findById } = require('../models/book');
const router = express.Router();
const Book = require('../models/book');
//read all books
router.get('/', async (req, res) =>{
try{
const AllBooks = await Book.find();
res.json(AllBooks);
}catch(err){
res.json({message:err});
}
})
//create book
router.post('/add', async (req, res) => {
var NewBook = new Book({
title: req.body.title,
pages: req.body.pages
})
try{
const SavedBook = await NewBook.save();
res.json(SavedBook);
}catch(err){
res.json({message: err})
}
})
//read book
router.get('/:BookId', async (req, res) => {
try{
const ReadBook = await Book.findById(req.params.BookId);
res.json(ReadBook);
}catch(err){
res.json({message: err});
}
})
//update book
router.patch('/update/:BookId', async (req, res) => {
try{
const updatedBook = await Book.updateOne({_id: req.params.BookId},
{$set: {title: req.body.title, pages: req.body.pages}});
res.json(updatedBook);
}catch(err){
res.json({message: err});
}
})
//delete book
router.delete('/delete/:BookId', async (req, res) => {
try{
const DelBook = await Book.findById(req.params.BookId);
DelBook.delete();
res.send(DelBook + " Deleted");
}catch(err){
res.json({message: err});
}
})
module.exports = router;
Now when I call: http://localhost:4001/rp, it return "restapi" just like i told to do it so. But when I call: http://localhost:4001/rp/books, it returns a "CANNOT GET", which is logical cause I didnt define this path. First I thought the express gateway would understand this automaticly.
Do i have to hardcode all the paths?
I hope somebody can explain this to me, since express gateway does not have an example like my case. :)
I found the solution.
I was confused with the definitions between an apiEndpoint and a serviceEndpoint.
The answer is: yes you have to hardcode all the paths in, but this will only be under "apiEndpoints".
It will look like this:
apiEndpoints:
restapi:
host: localhost
paths:
- '/books'
- '/books/add'
- '/authors'
- '/authors/...'
serviceEndpoints:
restapi:
url: 'http://localhost:4001'
So in summary, only one service with multiple api endpoints, which sound pretty logic.
I think a con is that when there are a lot of services this config file will become a big mess of endpoints.