Компонентный ключ для методов API REST
Я ищу лучшие практики в дизайне API RESTful для следующего использования:
Объект объекта домена:
class Vehicle {
private String vehicleType;
private String colour;
private String transmission;
private String yearOfIssue;
}
Пример объекта:
Vehicle = {vehicleType : 'Car', colour : 'Red', transmission : 'Automatic', yearOfIssue : '2008'};
В этой модели домена нет единого уникального идентификатора поля (например, vehicleId), но все поля объекта вместе образуют первичный ключ (это ограничение присутствует в слое базы данных).
У нас нет гибкости для изменения этой модели домена, чтобы добавить уникальный уникальный идентификатор поля.
Итак, мой вопрос следующий: если я хочу добавить простой REST API поверх этого объекта домена, который обеспечивает простую функциональность для CREATE, UPDATE, DELETE и GET Vehicles, то что лучше всего подходит для конечных точек PATH для этих методы?
Следуя приведенному выше примеру, если модель домена должна иметь уникальный идентификатор транспортного средства с идентификатором поля, тогда я могу представить следующие конечные точки:
GET /vehicles/:vehicleId
PUT /vehicles/:vehicleId
DELETE /vehicles/:vehicleId
Мне не известно о шаблоне, который аналогичен этому для составных клавиш:
GET /vehicles/:vehicleTypecolourtransmissionyearOfIssue
GET /vehicles/CarRedAutomatic2008
кажется неправильным.
Приветствуются любые советы по хорошему шаблону для этого случая использования.
Спасибо
Ответы
Ответ 1
В соответствии с общими стандартами 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] этот ури не имеет особого смысла, если вы не знаете о конкретном методе и маршруте.
Ответ 2
Чтобы быть 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: Получить http://mysite/vehicles/3842. Однако у вас может не быть доступа к внутреннему уникальному идентификатору, особенно при посеве или обновлении базы данных. Я столкнулся с подобными проблемами, и для использования глаголов 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: Получить http://mysite/vehicles/externalId/sedanbluemanual2015. Вам не нужно анализировать 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>
}
Ответ 3
В ядре ASP.NET я обычно представляю составной ключ следующим образом:
POST/vehicles/(car:red:automatic:2008)
или же
POST/vehicles/(car|red|automatic|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();
}
Пример запроса: PUT/vehicles/(Ford:Ranger:100% genuine:2000)
![enter image description here]()