如何在rest api调用中构造json并使其同步

Posted

技术标签:

【中文标题】如何在rest api调用中构造json并使其同步【英文标题】:how to structure json in rest api call and make it synchronous 【发布时间】:2020-03-06 23:09:26 【问题描述】:

我正在尝试使用 nodejs restapi 构建一个 json 响应,但即使该函数尚未执行,我的响应总是会提前发送。

我尝试等待承诺没有任何效果并发送错误..

//这是我想要的json结构

[
    
        "user_id": "2",
        "user_name": "Mehedi Hasan",
        "permissions": [
            
                "table_name": "questionbank",
                "permission_create": "true",
                "permission_update": "true",
                "permission_delete": "true"
            ,
            
                "table_name": "questionbankquestions",
                "permission_create": "true",
                "permission_update": "true",
                "permission_delete": "true"
            ,
            
                "table_name": "subjects",
                "permission_create": "false",
                "permission_update": "true",
                "permission_delete": "false"
            ,
            
                "table_name": "subjectquestions",
                "permission_create": "true",
                "permission_update": "true",
                "permission_delete": "true"
            ,
            
                "table_name": "modeltests",
                "permission_create": "true",
                "permission_update": "true",
                "permission_delete": "true"
            ,
            
                "table_name": "modeltestquestions",
                "permission_create": "true",
                "permission_update": "true",
                "permission_delete": "true"
            
        ]
    ,

............................

]

//这是我尝试过的

function getAllUser(done) 
  var sql = "SELECT users.id, users.username FROM users";
  db.query(sql, [], function(err, rows, fields) 
    if (err) throw err;
    done(rows);
  );


/*--------------------------Check user permission --------------------------*/
router.get("/adminpermissions", function(req, res) 
  var sql =
    "SELECT table_name, permission_create, permission_update, permission_delete FROM permissions " +
    "WHERE user_id = ?";

  finalArray = [];
  jsonFormat = [];
  permissionArray = [];

  getAllUser(function(user) 
    for (var i = 0; i < user.length; i++) 
      userId = user[i].id;
      userName = user[i].username;

      db.query(sql, [userId], function(err, rows, fields) 
        if (err) 
          res.status(500).send( error: "Something failed!" );
        
        console.log(rows);
        permissionArray[i] = rows;
        var data = 
          user_id: userId,
          user_name: userName,
          permission: permissionArray[i]
        ;
        jsonFormat.push(data);
      );     
    

    res.json(jsonFormat);

  );
);

我总是得到 [] 数组作为响应.. 虽然我知道即使循环尚未完成但正在发送响应的问题,但不知道如何解决.. 尝试用 promise 等待但结果是这样许多错误消息..

【问题讨论】:

这能回答你的问题吗? How do I return the response from an asynchronous call? 它很有用,但在我的情况下,如果我将 async 放在函数 getAllUser() 之前,我无法在 router.get()... 中使用 await,因为在 router.get... 之前不能把 async 放在那里.. 没有 async 就不能使用 await .. 您的问题在于 db.query,而不是路由。 不明白..我如何等待 for 循环结束..? 每个 db.query 调用都是异步的。您不能神奇地将其转换为同步。您必须等待所有的承诺(每个 db.query 一个),然后发送您的响应。如果您不能使用 async/await,那么您必须使用 Promises.all 和 .then 延续。 【参考方案1】:

您可以使用 async/await 来解决此问题。你可以这样做:-

router.get("/adminpermissions", function(req, res) 
var sql =
"SELECT table_name, permission_create, permission_update, permission_delete FROM 
 permissions " +
"WHERE user_id = ?";

finalArray = [];
jsonFormat = [];
permissionArray = [];

getAllUser(async function(user) 
for (var i = 0; i < user.length; i++) 
  userId = user[i].id;
  userName = user[i].username;
  sql =  "SELECT table_name, permission_create, permission_update, permission_delete 
  FROM permissions WHERE user_id = "+  userId;

  try 
  let result = await db.query(sql)
  permissionArray[i] = result[0];
    var data = 
      user_id: userId,
      user_name: userName,
      permission: permissionArray[i]
    ;
    jsonFormat.push(data);     
 catch(err) 
    res.status(500).send( error: "Something failed!" );



res.json(jsonFormat);

); );

【讨论】:

虽然我已经通过另一种方式解决了问题,但您描述的方式需要在两部分进行少量修改。首先,sql需要放入不同的函数,否则它只是多次返回相同的对象(user.length)。第二个问题是,在填充所有数据对象之前发送响应,因此只有用户列表。所以我必须在发送响应之前检查数据长度,否则它只是返回没有权限的用户信息。无论如何谢谢你..【参考方案2】:

这就是我所做的,效果很好

/*------------------------ Get Permissions of All User -----------------------------*/
function getAllUser(done) 
  var sql = "SELECT users.id, users.username FROM users";
  db.query(sql, [], function(err, rows, fields) 
    if (err) throw err;
    done(rows);
  );


function getPermission(user_id, user_name,profile_image, done) 
  var sql =
    "SELECT table_name, permission_create, permission_update, permission_delete FROM permissions " +
    "WHERE user_id =?";
  db.query(sql, [user_id], function(err, rows, fields) 
    if (err) throw err;
    done(user_id, user_name, profile_image, rows);
  );


router.get("/allpermissions", function(req, res) 
  var i = 0;
  var data = [];
  getAllUser(function(user) 
    for (i = 0; i < user.length; i++) 
      getPermission(user[i].id, user[i].username,user[i].profile_image, function(
        userId,
        userName,
        profileImage,
        rows
      ) 
        data.push(
          user_id: userId,
          user_name: userName,
          profile_image: profileImage,
          permissions: rows
        );
        if (data.length == user.length) 
          res.json(data);
        
        //console.log(data);
      );
    
  );
);
/*------------------------ ***************************** ---------------------------*/

【讨论】:

以上是关于如何在rest api调用中构造json并使其同步的主要内容,如果未能解决你的问题,请参考以下文章

如何使用REST API将文件存储卷安装到azure容器实例

Laravel REST API - 无限循环

如何使用 HttpClient 将带有 JSON 的 DELETE 发送到 REST API

如何在 fastAPI 中为 <input type="file"> 定义一个 REST 端点(并使其与 Angular 一起使用)?

从 JSON 数组 API 请求中获取值

dojo.store.Observable、JSON REST 和 queryEngine