Совет по дизайну интерфейса gRPC - правильный стиль для обработки создает и обновляет

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

Мы пытаемся определить лучшие шаблоны для именования наших интерфейсов, чтобы избежать дублирования типов сообщений, необходимости обременительной обработки крайних случаев и

Простой пример того, что мы делаем, включает создание, обновление и получение пользователей. Вот пример того, как наш сервис может выглядеть сегодня:

service Users {
  rpc GetUser(UserRequest) returns (core.user.User) {}
  rpc ListUsers(google.protobuf.Empty) returns (ListUsersResponse) {}
  rpc CreateUser(core.user.User) returns (core.user.User) {}
  rpc UpdateUser(core.user.User) returns (core.user.User) {}
}

message UserRequest {
  string id = 1;
}

message ListUsersResponse{
  repeated core.user.User users = 1;
}

GetUser довольно прост - он принимает простое сообщение UserRequest с идентификатором и возвращает пользователя (из нашего основного пакета - многие службы в приложении принимают сообщение пользователя в качестве входных данных, поэтому мы помещаем его в общую папку. ).

Мой вопрос конкретно относится к вызовам Create / Update Users, поскольку неясно, какое решение является оптимальным. Эти две функции немного отличаются, в основном в том, что в одном случае у нас уже есть пользователь и, следовательно, идентификатор, а в другом мы создаем нового пользователя. В случае Create у нас, вероятно, есть только подмножество доступных полей, которые могут существовать в User, но в идеале нам нужно будет поддерживать этот список только в одном месте, поскольку он потенциально может стать довольно большим. Мы могли либо:

  • Для каждого вызова определите собственное сообщение запроса / ответа и вставьте в него любые общие сообщения. Это будет выглядеть примерно так, как показано ниже. Меня беспокоит, что в конечном итоге мы получим по сути тип сообщения для каждого вызова, что с точки зрения ремонтопригодности может оказаться очень обременительным.

Код

message CreateUserRequest{ 
  core.User user = 1;
}
message UpdateUserRequest{
  int32 id = 1;
  core.User user = 2;
}
  • Мы могли ожидать / отправлять общие типы сообщений и полагаться на комментарии или другие механизмы обратной связи, чтобы побудить потребителей передавать правильные значения (что продемонстрировала моя первоначальная реализация). Меня беспокоит этот подход, так как нам придется добавить много проверок, чтобы убедиться, что предоставленные поля являются «правильными».

Я изо всех сил пытаюсь найти в Интернете множество примеров того, как другие люди решали подобные проблемы. Приведенный мной пример довольно прост, но вы можете себе представить, что на протяжении всего нашего проекта у нас будут похожие проблемы. Я бы хотел увидеть пример довольно сложного интерфейса gRPC, который кто-то реализовал на практике, или просто обратную связь от кого-то, кто широко его использовал, чтобы увидеть, какие шаблоны в дизайне интерфейса, по их мнению, работают лучше всего.

Спасибо!


person David    schedule 10.10.2017    source источник


Ответы (2)


Я думаю, что вам нужно Руководство по проектированию сетевых API Google. См. Соглашения об именах. Особенно раздел «Имена методов» на этой странице. Вы увидите примеры, очень похожие на то, что вы пытаетесь сделать, что бывает очень часто.

Для более конкретного примера посмотрите, как etcd написал свой API здесь. Подобно вашим CreateUserRequest и UpdateUserRequest etcd имеет _5 _ и MemberUpdateRequest.

person Ulas Keles    schedule 11.10.2017
comment
Это круто! Большое спасибо :) - person David; 11.10.2017

Вы также можете посмотреть онлайн-проектную документацию UBER, в которой приводится обоснование для отдельных реализаций ответа и приводится подробное описание версий и соглашений об именах.

person Greg    schedule 18.12.2019