«Спецификация дизайна интерфейса RESTful», основанная на инженерном опыте

задняя часть база данных Архитектура API

предисловие

В этой статье я в основном хочу обобщить свой опыт и размышления о разработке RESTful API.

Некоторые спецификации могут отличаться от стандартных спецификаций, но все соображения основаны на «уменьшении дублирования работы, повышении удобочитаемости и ремонтопригодности». Сказав это, я всегда чувствовал, что не существует очевидной принятой спецификации для дизайна RESTful API (если вы имеете в виду документ изобретателя, предполагается, что немногие люди прочитали его подробно, и его автор просто предложил ряд концепций) . Учебники в Интернете кажутся такими же (я серьезно сомневаюсь: все они «заимствуют или копируют» статьи г-на Жуань Ифэна), жесткими и негибкими и немного догматичными (во всяком случае, никто никогда в них не сомневается, я следуйте этим API догматического дизайна, не очень весело).

Вышеперечисленное не все отрицается, хорошие вещи должны быть полностью поглощены, а плохие вещи должны быть объединены с собственным пониманием и трансформированы.

Знание RESTful API

Говоря об этом, кажется, говорят о том, что «RESTful — это абстракция ресурсов», «в сочетании с характеристиками HTTP» и так далее. Но это бесполезные клише с малой питательной ценностью, и я хочу поговорить об этом под другим углом.

Поскольку это API, он обычно соответствует общему шаблону API:

ResultType ApiName(ParamType )

1. 接口参数,即形参。可以是 string,int,以及其他任意可以称之为参数的东西
2. 接口返回值。可以是 string,int,以及其他任意可以称之为返回值的东西
3. 接口名(签名)

Давайте посмотрим, как RESTful вписывается в этот шаблон:

HttpResponse URL(HttpRequest)

1. HttpRequest:包括请求头,URL参数,请求body参数
2. HttpResponse: 包括响应头,响应的body

С этой точки зрения RESTful API — это не что иное, как специальный API, общие правила проектирования API подходят и для RESTful, но в непреобразованном виде.

Итак, какие у нас есть более общие стандарты? Наверное эти:

  1. Именование интерфейса должно быть понятным. Вообще говоря, достаточно делать «глагольно-объектные словосочетания».
  2. Количество интерфейсов, чем меньше, тем лучше. Три не так хороши, как два, два не так хороши, как один, и один не так хорош, как ни один, лучший API — это «без API».
  3. Есть четкие вход и выход. Если вы продолжите думать об этом, будет эхо, и всегда будет возвращаемое значение, сообщающее вызывающей стороне, что я сделал и как я это сделал, то есть обратная связь.

Давайте посмотрим, как эти стандарты влияют на содержание ниже, :).

Дизайн URL и его анти-шаблоны

URL — это сигнатура интерфейса, а сигнатура должна быть четкой и однозначной.

Имеет единый префикс и версию

Если серверная архитектура ориентирована на службы, возможно, что каждая служба будет предоставлять открытый RESTful API для внешнего мира, поэтому лучше иметь унифицированный формат префикса, например:

/SERVICE_NAME/v1/users
or
/APP_NAME/v2/users

как можно короче

Один и тот же ресурс может иметь разные пути для его понимания. Например:

User -- 1:N --> Server-- 1:N --> Client ... 更加复杂的实体映射关系

1. /users/{user_id}/servers/{server_id}/clients
2. /clients

一般大家倾向于选项 1(但是实体关联关系特复杂时,会缩短URL),
不过选项2 也是一个不错的选择,总而言之,口味问题吧。

как можно меньше

Чем меньше количество интерфейсов, тем лучше, и интерфейсы, которые можно комбинировать, должны комбинироваться как можно больше. Например, в этом случае:

获取用户列表信息:GET /users
获取单个用户信息:GET /users/{id}

坦白说,获取一个与获取一批,似乎并没有什么语义上的差别,
但是后端的同学就不一样了,他可能需要写两个 View Class。
所以只保留批量的接口,查询一个时,用 URL 参数传递就行了。

В таком случае:

PUT /users/{id}
PUT /users

直接合并到一个接口里面做就行了,PUT 一个 user与 PUT 一群 user,有啥本质的不同吗?

Бывают и крайние случаи:

DELETE /users/{id}

删除一个user与删除一批user,有啥不同?
如果要一次删除100 个 user,难道让前端同学,调 100 次这个接口?
多一次调用,就多一次风险(如网络问题),
这个时候就别守着 RESTful 那些个教条了,接口的可用性、效率性,更加重要。

这个时候,不如设计成这样(至于 DELETE 接口能不能传Request body,这里不讨论):
POST /users_deletion
{
    "user_ids": [1, 2, 3, 4, 5]
}

конструкция возвращаемого значения

Как упоминалось ранее, в HttpResponse мы можем использовать:

Response Headers
可以做少量文章,如自定义一个Header

Status Code
按照基本规范来,该404的404,该200的200

Response body
基本都是围绕这个做文章

Тело ответа должно не только нормально возвращать информацию, но также сообщать причину ошибки (код ошибки) и подробности ошибки, если она есть. Таким образом, мы, вероятно, можем спроектировать его следующим образом:

{
    是否成功
    boolean "is_success":
    错误码是多少
    number|null "err_code":
    错误信息
    string|null "err_msg": 
    错误详情(可选)
    string|null "err_detail":
    出错的时哪个服务
    string|null "provider": 
    
    正常返回时的数据
    "response_data": {

    }
}

Таким образом, когда внешний интерфейс вызывает API, существуют правила и положения, которым необходимо следовать, и он не будет слепым.

Соглашение об именах полей

Четкой спецификации нет, но старайтесь следовать стилю базы данных, т.е. стилю подчеркивания. Это может быть удобно при сериализации всей модели.

Другие характеристики

Ограничение тока интерфейса

Обратитесь к стилю GitHub.

безопасность интерфейса

Это не может быть систематическим, вы можете обратиться к соответствующим статьям в Интернете.