NodeJS Rest API - 调用外部 API 的正确位置在哪里

Posted

技术标签:

【中文标题】NodeJS Rest API - 调用外部 API 的正确位置在哪里【英文标题】:NodeJS Rest API - where is the right place to call external API 【发布时间】:2022-01-21 16:25:15 【问题描述】: 我在 Node.JS 中编写 Rest API,它使用 mysql 数据库但也使用外部 API,我需要在其中获取一些数据。

我正在使用 Express 和“路由器、中间件、控制器、模型”架构,但我不确定调用外部 API 的正确解决方案是什么。在每个请求中,我都会发送外部 API 所需的令牌。我展示了我现在所拥有的并尝试描述我目前所面临的问题(请阅读代码中的 cmets。)

(另外,如果你有一些文章或教程描述了如何在使用路由器、中间件、控制器、模型架构的节点中正确编写 Rest API,请告诉我)

这是主要的 index.js

const express = require("express");
const dotenv = require('dotenv');
const cors = require("cors");
const HttpException = require('./utils/HttpException.utils');
const errorMiddleware = require('./middleware/error.middleware');
const userRouter = require('./routes/user.route');
const axios = require("axios");

// Init express
const app = express();
// Init environment
dotenv.config();
// parse requests of content-type: application/json
// parses incoming requests with JSON payloads
app.use(express.json());
// enabling cors for all requests by using cors middleware
app.use(cors());
// Enable pre-flight
app.options("*", cors());

const port = Number(process.env.PORT || 3331);

app.use(`/api/v1/users`, userRouter);

// This is an solution that works but I thinks is and nasty way how to do it
// You can see here how I need to call external API
app.get('/api/v1/test',  (req, res, next) => 
    const token = req.headers.token;
    
    const respond = await axios.get(EXTERNAL_API_ENDPOINT, 
        headers: 
            cookie: `token=$token`
        
    );
);

// 404 error
app.all('*', (req, res, next) => 
    const err = new HttpException(404, 'Endpoint Not Found');
    next(err);
);

// Error middleware
app.use(errorMiddleware);

// starting the server
app.listen(port, () =>
    console.log(`Server running on port $port!`));


module.exports = app;

user.route.js

const express = require('express');
const router = express.Router();
const userModel = require('../models/user.model');
const awaitHandlerFactory = require('../middleware/awaitHandlerFactory.middleware');

router.get('/currentUser', awaitHandlerFactory(userModel.getCurrentUser));

router.get('/logout');
module.exports = router;

我还有一个 Auth 中间件来检查令牌验证,我需要调用外部 API 来验证用户。

Auth.middleware.js

const HttpException = require('../utils/HttpException.utils');
const UserModel = require('../models/user.model');
const dotenv = require('dotenv');
dotenv.config();

const auth = (roles) => 
    return async function (req, res, next) 
        try 
            const token = req.headers.token;

            if (!token) 
                throw new HttpException(401, 'Access denied. No credentials sent!');
            

            /* here I need call the external API and think that I should call it from 
               UserModal?, but I can't because Modal doesn't have req (should I sent it 
               in function parmas? like this?)*/

            const user = await UserModel.getCurrentUser(token, params);

            if (!user) 
                throw new HttpException(401, 'Authentication failed!');
            

            if(!user.active || user.active !== 'Y')
                throw new HttpException(401, `User $user.userName is not active!`);
            

            // if the user role don't have the permission to do this action.
            // the user will get this error
            if (roles.length && !roles.includes(user.role)) 
                throw new HttpException(401, 'Unauthorized');
            

            // if the user has permissions
            req.currentUser = user;
            next();

         catch (e) 
            e.status = 401;
            next(e);
        
    


module.exports = auth;

我不确定如何处理这个问题。我必须提供令牌和一些数据来调用外部 API。我不确定,如果我应该调用模型或通过控制器(或中间件?)来做。 我应该在哪里以及如何做,为什么?谢谢!

【问题讨论】:

【参考方案1】:

在我看来还不错。真的取决于是否需要每次请求都进行 API 调用。假设用户向您的 API 发出请求,然后向外部 API 发出请求以验证该用户,您将需要来自每个请求的身份验证令牌。

不过,您可以更好地组织代码。例如:

?api

┣ ?控制器

┃ ┗ ?test.js

┣ ?服务

┃ ┗ ?EXTERNAL_API_ENDPOINT.js

┗ ?index.js

api/services/EXTERNAL_API_ENDPOINT.js

const axios = require("axios");

async function getService(token) 
    return axios.get(EXTERNAL_API_ENDPOINT, 
        headers:  cookie: `token=$token` 
    );

module.exports = getService;

api/controllers/test.js

const getService = require("../services/EXTERNAL_API_ENDPOINT");

async function test(req, res, next) 
    const token = req.headers.token;
    const respond = await getService(token)

module.exports = test;

api/index.js

const test = require("./controllers/test");

app.get('/api/v1/test',  test);

【讨论】:

以上是关于NodeJS Rest API - 调用外部 API 的正确位置在哪里的主要内容,如果未能解决你的问题,请参考以下文章

使用nodejs和rest api调用和express进行异步处理-序列错误

Express 和 Nodejs:调用外部 API 的最佳方式

Magento 使用 OAuth 通过 REST API 到 NodeJS

在节点中创建 REST API 时,如何将来自对外部网站的请求的 http 响应流式传输到原始 api 调用?

使用 Express 和 NodeJS 构建 REST API 的最佳实践

使用 Tibco BW Vers6 调用外部 API