代码之家  ›  专栏  ›  技术社区  ›  j10

如何在DB查询中区分403和404

  •  1
  • j10  · 技术社区  · 7 年前

    我正在开发REST API。尝试访问资源时:我们希望给出403(禁止)或404(未找到)错误。我们的桌子是:

    CREATE TABLE `Action` (
          `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
          `created_By_Id` int(10) unsigned NOT NULL,
          `name` varchar(60) NOT NULL,
          `updated_action_at` datetime(3) DEFAULT NULL,
          `created_At` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
          `notes` varchar(400) DEFAULT NULL,
           PRIMARY KEY (`id`),
           KEY `action_empId_fk` (`created_By_Id`),
           CONSTRAINT `action_empId_fk` FOREIGN KEY (`created_By_Id`)
           REFERENCES `Employee` (`id`) ON DELETE CASCADE,
           ) ENGINE=InnoDB AUTO_INCREMENT=502004 DEFAULT CHARSET=latin1
    
    
    CREATE TABLE `ActionAssignedTo` (
        `action_Id` int(10) unsigned DEFAULT NULL,
        `assignee_Id` int(10) unsigned DEFAULT NULL,
         KEY `actionassignedto_emp_id_foreign` (`emp_Id`),
         KEY `actionassignedto_action_id_foreign` (`action_Id`),
         CONSTRAINT `ActionAssignedTo_ibfk_1` FOREIGN KEY (`assignee_Id`) 
         REFERENCES `Employee` (`id`) ON DELETE CASCADE,
         CONSTRAINT `ActionAssignedTo_ibfk_2` FOREIGN KEY (`action_Id`) 
         REFERENCES `Action` (`id`) ON DELETE CASCADE
         ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    
    CREATE TABLE `Employee` (
        `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
        `vendor_Id` int(10) unsigned DEFAULT NULL,
        `name` varchar(40) NOT NULL,
        `mobile_Number` varchar(15) NOT NULL,
        `active` tinyint(1) DEFAULT '1',
        `updated_At` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        `created_At` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (`id`),
        KEY `employee_vendor_id_foreign` (`vendor_Id`),
        CONSTRAINT `employee_vendor_id_foreign` FOREIGN KEY (`vendor_Id`)
        REFERENCES `Vendor` (`vendor_Id`)
        ) ENGINE=InnoDB AUTO_INCREMENT=511 DEFAULT CHARSET=latin1
    

    我们正在运行一个查询,以获取id为9、供应商id为1的创建者员工执行的id为17的操作,该员工已创建该操作,以便可以查看该操作(业务规则)。可以将操作分配给多个员工。

    select     Action.name,  
               group_concat(AssigneeNameTable.name) as assignedTo, 
               group_concat(AssigneeNameTable.id) as assignedToId, 
               ActionAssignedTo.action_Id as actionId
    from       Action
    inner join Employee
    on         Action.created_By_Id = Employee.id
    and        Employee.vendor_Id = 1 
    inner join ActionAssignedTo 
    on         Action.id = ActionAssignedTo.action_Id 
    and        ActionAssignedTo.action_Id = 17 
    inner join Employee as AssigneeNameTable 
    on         ActionAssignedTo.assignee_Id = AssigneeNameTable.Id 
    where      Action.created_By_Id = 9 
    and        Action.deleted_at is null 
    group by   Action.id 
    limit       2
    

    现在,假设操作在DB中根本不存在-->在这种情况下,上述查询返回空的结果集

    the problem is we can not differentiate the query return empty set because 
    
    1. either the action with id:17 did not exist(404- Not Found) 
    
    2. or the business rule failed (as in the person requested the action was not    
    at all related to the action(403 - Forbidden).
    

    我能想到的解决方案之一是: 首先运行一个小查询,如:

    select * from Action where id = 17
    

    如果此查询返回一个空集,则表示该操作在数据库中不存在。

    在此之后,我运行更大的查询

    结果集的不同组合(数组中的数字表示返回的记录):

    Small Query | Big Query  | Interpretation
    ---------------------------------------
    [0]         | [0]        | Resource Not Found(404)
    [1]         | [0]        | Forbidden (403)
    

    如果小查询返回0结果-->我们可以直接发送404错误;否则,我们将执行大查询。

    1 回复  |  直到 7 年前
        1
  •  1
  •   j10    7 年前

    我按照朋友的建议使用了左外连接的概念。请在下面查找新查询:

    select      *
    from
    
    (select     id
     from       Action
     where      id = 17) AS act1
    
    left Outer Join
    
    (select    Action.name,  
               group_concat(AssigneeNameTable.name) as assignedTo, 
               group_concat(AssigneeNameTable.id) as assignedToId, 
               ActionAssignedTo.action_Id as actionId
    from       Action
    inner join Employee
    on         Action.created_By_Id = Employee.id
    and        Employee.vendor_Id = 1 
    inner join ActionAssignedTo 
    on         Action.id = ActionAssignedTo.action_Id 
    and        ActionAssignedTo.action_Id = 17 
    inner join Employee as AssigneeNameTable 
    on         ActionAssignedTo.assignee_Id = AssigneeNameTable.Id 
    where      Action.created_By_Id = 9 
    and        Action.deleted_at is null 
    group by   Action.id 
    limit      2) AS act2
    
    on          act1.id = act2.actionId
    

    概念很简单

    • 如果输出不包含结果-->找不到对象(404)

    • 如果输出包含 id 字段,但不包含第二个子查询中的任何单个字段,这意味着该实体存在于数据库中,但业务规则不允许,因此被禁止(403)。