Бывают задачи вроде таких:
Для этих и многих других задач используется RESTful API.
Но даже на собственных проектах можно увидеть, что API разных проектов отличаются друг от друга.
Попробую обобщить некоторые моменты по созданию RESTful API.
Я не утверждаю, что это неоспоримые правила построения API и всё-таки многое зависит от задачи и ситуации, но какую-то общую структуру для себя выделить можно.
Это поможет с лёгкостью разбираться в своих старых проектах, а также поможет, если будет такая необходимость, другим разработчикам не впадать в ступор при виде кода, а быстро находить нужное.
У меня есть два основных правила для RESTfull API:
Поменьше креатива. То есть делать то, что ожидается.
Быть последовательным. То есть структуры запросов, ответов, заголовков должны быть одинаковы для всего API.
Правила семантики.
Лучше использовать
get /posts
get /posts/111
post /posts
,чем
get /getAllPosts
get /getPostById/111
post /createPost
Первый пример более общий, понятный и привычный. Большинство разработчиков пользуются и привыкли именно к такому формату.
Особенно, если API для внешнего доступа. Всегда хорошо исправить баги, но эти исправления не должны менять работу API. Если всё же вносятся кардинальные изменения, то нужно подумать об обратной совместимости или хотя бы о том, чтобы заранее предупредить всех, кто пользуется этим API.
GET для получения данных
PUT/POST для внесения изменений
одинаковая структура конечных точек(формат запросов и формат ответов)
хорошие и правильные коды состояния (если запрос сформирован неправильно, то следует использовать 400 код ответа сервера, а 404 и уже тем более не 200)
использовать коды не те коды ответа. Если запрашивается список постов и он пуст, то лучше вернуть пустой список с кодом 200, а не отдать 404.
использовать GET для внесения изменений, а PUT/POST для получения данных.
не использовать сообщения об ошибках.
Несмотря на описанное в пункте 2, изменения всё равно неизбежны. Изменится бизнес, изменятся процессы, изменится то, чего хотят люди. И API придётся менять.
Перед изменениями предусмотри версионность. Самый семантически верный и понятный способ это добавить версию в url.
/api/v2/posts
не возвращай больше чем нужно. Если определённое свойство возвращаемых объектов является внутренним, то лучше его не возвращать.
не нужно использовать все возможные коды ответа сервера. Достаточно привычных и часто используемых: 200, 201, 302, 404, 400, 500 и т. д.
не повторяйся. Не делай несколько похожих методов.
структура ответа должна быть одинаковой для всех методов.
Ты будешь благодарен себе из прошлого и другие разработчики будут благодарны тебе, если к API будет документация. Для внутреннего пользования достаточно комментариев и самодокументируемого кода(об этом в следующих статьях).
Для внешних пользователей необходимо сделать документацию. Можно воспользоваться атрибутами и автогенерацией API, это лучше чем ничего.
Технические правила (или, скорее, рекомендации)
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Passport { get; set; } //ай ай ай
}
public class PersonsController : ApiController
{
public IHttpActionResult Put(int id, [FromBody] Person person)
{
//update the Person object
}
}
Видишь проблему? У пользователя есть возможность изменить или получить свойство Passport. То есть он может просто передать новое значение в метод и изменить его.
Да, безусловно можно передавать данные в обновлении поимённо, но не лучше ли сделать прослойку? Дай пользователю только то, что ему нужно. Это называется DTO(Data Transfer Object):
public class PersonDto
{
public int Id { get; set; }
public string Name { get; set; }
}
public class PersonsController : ApiController
{
public IHttpActionResult Put(int id, [FromBody] PersonDto person)
{
//update the Person object
}
}
Все данные должны считаться плохими пока не произведена какая-то проверка. Иначе рано или поздно какой-то запрос сломает твой API.
Например при оформлении заказа в интернет-магазине следует проверить наличие в заказе по крайней мере одного товара.
Контролеры должны только принимать данные отдавать их службам и возвращать данные обратно. Бизнес-логики в контроллерах быть не должно.
Раздели на простейшие составляющие весь API.
Один пользовательский метод — одно действие.
Один метод в модели — одно действие.
Упрощай и разделяй!
Ты сам скажешь себе спасибо когда трафик на приложение вырастет
Nov 29th 21