RESTAPI方法的复合键
我正在为以下用例寻找RESTful API设计的最佳实践: 域对象车辆:RESTAPI方法的复合键,api,rest,Api,Rest,我正在为以下用例寻找RESTful API设计的最佳实践: 域对象车辆: class Vehicle { private String vehicleType; private String colour; private String transmission; private String yearOfIssue; } 一个示例对象: Vehicle = {vehicleType : 'Car', colour : 'Red', transmission :
class Vehicle {
private String vehicleType;
private String colour;
private String transmission;
private String yearOfIssue;
}
一个示例对象:
Vehicle = {vehicleType : 'Car', colour : 'Red', transmission : 'Automatic', yearOfIssue : '2008'};
在此域模型中,没有单个字段唯一标识符(例如vehicleId),而是对象的所有字段一起构成主键(此约束在数据库层中)
我们无法灵活地更改此域模型以添加单个字段唯一标识符
所以我的问题如下-如果我想在这个域对象上添加一个简单的RESTAPI,它提供创建、更新、删除和获取车辆的简单功能,那么这些方法的路径端点的最佳实践是什么
根据上面的示例,如果域模型具有单个字段唯一标识符vehicleId,那么我可以想象以下端点:
GET /vehicles/:vehicleId
PUT /vehicles/:vehicleId
DELETE /vehicles/:vehicleId
我不知道复合键存在类似的模式,如:
GET /vehicles/:vehicleTypecolourtransmissionyearOfIssue
GET /vehicles/CarRedAutomatic2008
似乎不正确
如果您对本用例遵循的良好模式有任何建议,我们将不胜感激
谢谢根据通用REST标准,每个端点都公开一个资源,客户端可以使用http谓词处理它们。在本例中,您的资源是车辆,客户机使用GET从服务器获取数据。理想情况下,每个资源都应该使用唯一(单个)密钥进行唯一标识 但是您的资源(车辆)没有单一值唯一密钥,并且无法在系统中更改!在这种情况下,您仍然可以使用所有必需的参数进行GET调用,以标识资源,就像任何其他标准http调用一样,如
GET /vehicles?type=Car&color=Red&transmission=Automatic&manufactureYear=2008
您正在使用的技术/平台,如果允许为您的方法创建自定义路由,您可以创建自定义路由,如
new route("/vehicles/{type}/{color}/{transmission}/{manufactureYear}")
并将您的服务呼叫为
GET /vehicles/Car/Red/Automatic/2008
这样做的好处是,uri变短了。但另一方面[1]对于这种类型的所有方法/资源,您必须创建自定义路由,[2]除非您了解特定的方法和路由,否则此uri没有多大意义。要实现RESTful,您需要创建一个唯一的标识符来扩展类
class Vehicle {
public int vechicleId { get; set; }
public string vehicleType { get; set; }
public string colour { get; set; }
public string transmission { get; set; }
public string yearOfIssue { get; set; }
}
然后您可以使用HTTP:Get访问它。但是,您可能无法访问内部唯一标识符,尤其是在对数据库进行种子设定或更新时。我遇到过类似的问题,为了使用REST动词,我将包括一个外部标识符,以便于人类和外部系统访问记录:
class Vehicle {
public int vechicleId { get; set; }
public string externalId { get; set; }
public string vehicleType { get; set; }
public string colour { get; set; }
public string transmission { get; set; }
public string yearOfIssue { get; set; }
}
然后这个动词看起来像:
HTTP:获取。您不必解析URI,因为所有数据都应该在消息体中,您只需要确保字符串唯一地标识车辆
[HttpPut("externalId/{externalId}")]
public IActionResult PutVehicle([FromRoute] string externalId, [FromBody] JObject jObject)
{
// See if the record exists already.
var oldVehicle = (from v in vehicles
where vehicle.ExternalId == externalId
select v).FirstOrDefault();
if (oldVehicle != null)
{
<insert new vehicle>
}
else
{
<update old vehicle>
}
[HttpPut(“externalId/{externalId}”)]
public IActionResult PutVehicle([FromRoute]字符串外部ID,[FromBody]作业对象作业对象)
{
//查看记录是否已经存在。
var oldVehicle=(来自车辆中的v
其中vehicle.ExternalId==ExternalId
选择v).FirstOrDefault();
如果(旧车辆!=空)
{
}
其他的
{
}
在ASP.NET Core中,我通常表示这样的复合键:
POST/vehicles/(汽车:红色:自动:2008)
或
POST/vehicles/(汽车|红色|自动| 2008)
框架可以按照指定的顺序将这些参数映射到操作参数
[HttpPut("vehicles/({car}:{color}:{trans}:{year})")]
public async Task<IActionResult> Add(
string car, string color, string trans, int year, [FromBody] Vehicle request)
{
await Task.CompletedTask;
return Ok();
}
[HttpPut(“车辆/({car}:{color}:{trans}:{year})])
公共异步任务添加(
字符串车,字符串颜色,字符串变速器,整数年,[FromBody]车辆请求)
{
等待任务。完成任务;
返回Ok();
}
请求示例:PUT/vehicles/(福特:Ranger:100%正品:2000)
使用path比使用params来指定密钥更好,因为它可以与任何动词一起使用。例如,您可以使用
POST/vehicles/Car/Red/Automatic/2008
@JohnHenckel进行更新。根据,查询参数是URL的一部分,因此您也应该能够发布到它们。参见我想看到更大的问题已解决:OP的任务是否可以使用REST完成,或者它只是一个标准的HTTP Get?我想如果没有一个唯一的标识符,它就不是REST。@DonaldAirey看到了我的答案,类似于一个唯一标识符。这是一个弱解决方案,因为它假定数据不包含任何特殊字符。例如,someo请插入一辆变速器为“100%正版”的汽车,然后ASP.NET将抛出一个异常。它不允许在路径中使用特殊字符。@JohnHenckel此答案专门针对ASP.NET Core
(如上所述),并且该框架允许使用特殊字符。请参阅添加到答案中的屏幕截图。