简体   繁体   English

NodeJS RESTful API-如何正确处理“未定义”的请求变量?

[英]NodeJS RESTful API - How to handle 'undefined' request variables properly?

I am developing a RESTful API using NodeJS and Express. 我正在使用NodeJS和Express开发RESTful API。
I noticed that incoming requests sometimes lack of some expected variables, which cause the program to crash, saying it couldn't set the value of a variable, to an 'undefined' value - as no value arrived with the request. 我注意到传入的请求有时缺少一些预期的变量,这会导致程序崩溃,并说它无法将变量的值设置为'undefined'值-因为没有值随请求到达。
Example: 例:
The application is expecting variableY, but instead variableX is being sent: 该应用程序期望使用variableY,但是正在发送variableX:

 formData: { variableX: 'valueX' }

The program is expecting to receive variableY, with the following code: 该程序希望接收variableY,其代码如下:

const checkVariables = Joi.validate({ 
    variableY: req.body.variableY,
}, schema);

The application crashes with the following error: 应用程序因以下错误而崩溃:

TypeError: Cannot read property 'variableY' of undefined

I thought about a few ways to handle that, including declaration of variables upon application initiation and using them along, using try-catch . 我考虑了几种处理方法,包括在应用程序启动时声明变量,以及使用try-catch一起使用它们。
Another way will be to use if-else , if-chaining , or case-switch , but as you understood of course I am looking for the cleanest way to achieve that. 另一种方法是使用if-elseif-chainingcase-switch ,但是正如您所理解的,我当然正在寻找实现这一目标的最简洁的方法。
Any ideas? 有任何想法吗?

Thank you. 谢谢。

** EDIT ** **编辑**
Progressed and managed to achieve the result using the object only. 仅使用对象进行了开发并设法获得了结果。 Once trying to reach any of it's inner fields the error will be thrown anyway, example: 一旦尝试到达其中的任何内部字段,该错误都将被抛出,例如:
if(req.body.variableY == undefined){console.log('The expected variable is undefined');} //true

When the validation addresses a field inside the 'undefined' object: 验证处理“未定义”对象内的字段时:
if(req.body.variableY.dataId == undefined){console.log('The expected variable is undefined');} //crashes
The following error is being thrown again: 再次引发以下错误:
TypeError: Cannot read property 'variableX' of undefined

After doing some more digging around, found this Stackoverflow thread: 经过更多的挖掘之后,发现以下Stackoverflow线程:
How to check if object property exists with a variable holding the property name? 如何使用保存属性名称的变量检查对象属性是否存在?
Tried using hasOwnProperty, but the same kind of error is being thrown: 使用hasOwnProperty进行了尝试,但引发了相同类型的错误:
TypeError: Cannot read property 'hasOwnProperty' of undefined

Tried wrapping variable declaration using try-catch , still didn't work: 尝试使用try-catch包装变量声明,但仍然无法正常工作:

try{
    var variableX = req.body.variableX
    var variableXDataId = req.body.variableX.dataId
}
catch(e){
    res.status(400).send('Wrong request error: Please check your request variables and try again');
}

As this is a really basic validation that should be addressed by most of the RESTful APIs (validating that you get the expected incoming variables inside the request, so the program won't crash by having errors it can't handle - what is the common solution for such problems (expected / unexpected request validation)? 由于这是大多数RESTful API都应解决的非常基本的验证(验证您是否在请求中获得了预期的传入变量,因此该程序不会因无法处理的错误而崩溃-常见的问题解决此类问题(预期/意外请求验证)的解决方案?

Thank you. 谢谢。

You can take another approach, check req.body before you reach checkVariables : 你可以采取另一种方法,检查req.body你到达之前checkVariables

let body = req.body;

// data - your req.body
// requiredKeys - is an array of strings , [ key1, key2 ... keyN]  | string[]

     const setKeys = ( data, requiredKeys )=>{

         if( !typeof requiredKeys.length ){
            requiredKeys = [];
         }

         if(requiredKeys.length) requiredKeys.forEach( k =>{

             k = k.replace(/\+/g,'/');

             let keysList = [];

             if( /\/+/g.test(k)){
               keysList = k.split('/');
             }else{
              keysList = [k];
             }

             let [firstKey, ...rest] = keysList;

             if( typeof data[firstKey] === 'undefined' ){
               data[firstKey] = {};
             }

             if( rest.length ){

                data[firstKey] = setKeys(data[firstKey], [rest.join('/')] );

             }

         })

         return data;

      }

let checkedData= setKeys(body, ['variableT','variableP/noname/emptyObj','custom/object/does/not/exist/but/it/will/be/created/here']);

const checkVariables = Joi.validate(checkedData, schema);

UPDATE UPDATE

Below you will find an working example on how things should work during a / (let's say /usersStatus/:id ) request: 在下面,您将找到一个工作示例,说明在/ (假设/ usersStatus /:id)请求期间事情如何工作:

 const express = require('express') const app = express() const port = 3000 const setKeys = (data, requiredKeys) => { if (!typeof requiredKeys.length) { requiredKeys = []; } if (requiredKeys.length) requiredKeys.forEach(k => { k = k.replace(/\\+/g, '/'); let keysList = []; if (/\\/+/g.test(k)) { keysList = k.split('/'); } else { keysList = [k]; } let [firstKey, ...rest] = keysList; if (typeof data[firstKey] === 'undefined') { data[firstKey] = {}; } if (rest.length) { data[firstKey] = setKeys(data[firstKey], [rest.join('/')]); } }) return data; } /** * Mock some data */ const getUserData = (req, res, next) => { if (typeof req.body === 'undefined') { req.body = {}; } req.body = { variableY: { someName: 23 }, variableZ: { name: 3, type: { id: 5, typeName: 'something', tags: ['a', 'b', 'c'] } } }; console.log('Middleware 1 getUserData'); next(); } /** * 1. Setup our middleware for checking keys * "requiredKeys" is an array of strings */ const middlewareSetKeys = (requiredKeys, wrappedMiddleware) => { return (req, res, next) => { console.log('Middleware 2 middlewareSetKeys'); if (typeof req.body === "undefined") { console.log('Leaving Middleware 2 since we don\\'t have req.body'); next(); } /** * Update "req.body" with keys that we want to have available * in our next middleware */ req.body = setKeys(req.body, requiredKeys); if (typeof wrappedMiddleware === 'function') { return wrappedMiddleware.call(this, req, res, next); } else { next(); } } } /** * 2. Let's assume a "user status" situation * 2.1. We need userInfo from database * 2.2. Some info won't be retrieved, unless the user accesed some parts of the website to trigger some mechanisms that allows those fields to be exposed, therefore the lack of keys * 2.3. But we know those keys/objects, and we still want to be present so our code won't crash. */ // lets call our getUserData app.get( '/', // this path is for some userInfo getUserData, // this returns userInfo and appends it to `req.data` middlewareSetKeys([ 'userActivity/daily/jobs', // these won't exist in getUserData because the user is lazy and he didn't apply for any JOBS 'userStatus/active/two-weeks-ago', // these won't exist in getUserData because the user joined two days ago. BUT WE STILL NEED IT coz reazons. ]), // We set our desired-later-to-use keys (req, res, next) => { /** * 3. Now our req.body will have our keys * even if they didn't exist in the getUserData middleware */ console.log('Middleware 3 Your middleware'); console.log(req.body); res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(req.body, null, 2)) }) app.listen(port, () => console.log(`Example app listening on port ${port}!`)) 

you can use express validator https://www.npmjs.com/package/express-validator to validate incoming request.Then add this to your controller where a,b,c ,d are parameters you want to valaidate 您可以使用快递验证器https://www.npmjs.com/package/express-validator验证传入请求。然后将其添加到控制器中,其中a,b,c,d是您要验证的参数

 const nonEmptyFields = ['a', 'b', 'c', 'd']; nonEmptyFields.forEach(field => req.assert(field, `${field} cannot be blank`).notEmpty()); const errors = req.validationErrors(); if (errors) { return res.status(400).send(errors); } 

for validating a field inside a field you can try doing this 用于验证字段内的字段,您可以尝试执行此操作

typeof(req.body && req.body.name !== undefined)

A solution will be to set a default empty object to replace undefined at a parent level: 一个解决方案是设置一个默认的空对象,以替换父级的undefined:

// checking for body.variableX.variableZ with object destructuring ES6
const {body = {}} = request;
const {variableX = {}, variableY} = body;
const {variableZ} = variableX.variableZ;

// or prior ES6
var body = request.body || {};
var variableX = body.variableX || {};
var variableY = variableX.variableY;

// or in a statement
var variableY = request.body && request.body.variableX ? request.body.variableX.variableY : undefined;

Based on that you can create your own function like getValue(request, 'body.variableX.variableY') to return null if any parent or the end value is undefined: 基于此,您可以创建自己的函数,如getValue(request, 'body.variableX.variableY') ,如果未定义任何父项或最终值,则返回null:

// asumes the value in the path is either object or undefined
function getValue(rootObj, path = '') {
    const parts = key.split('.');
    let value = rootObj || {};
    let part;
    while ((part = parts.shift()) && value !== null) {
        value = value[part] || null;
    }
    return value;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM