Почему пользовательские методы не должны использовать URL для передачи данных? - PullRequest
1 голос
/ 02 февраля 2020

TL, DR; При реализации пользовательских методов , "конфигурация HTTP [...] должна использовать предложение body:*, а все остальные поля сообщения запроса должны сопоставить с телом HTTP-запроса. ". Почему?

У меня проблема с Руководством по разработке API Google , за которым я пытаюсь следовать с gRP C с конечными точками облака .

HttpRule используется для перекодирования HTTP / JSON в gRP C. Ссылка HttpRule гласит:

Обратите внимание, что когда использует * в отображении тела , невозможно иметь Параметры HTTP, так как все поля, не связанные концом пути в теле.

[...] Обычно * используется в пользовательских методах. которые вообще не используют URL для передачи данных.

... мнение также повторяется в документации пользовательских методов Google и усилены с помощью Google API Linter ,

При использовании именованного представления в отображении body остается хорошо определенное пространство, оставленное для добавления метаданных в форма параметров строки запроса; Например, для нумерации страниц, ссылок, предупреждений об устаревании, сообщений об ошибках).

service Messaging {
  rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
    option (google.api.http) = {
      put: "/v1/messages/{message_id}"

      // A named reference makes it possible to use querystring params
      // and the HTTP body.
      body: "data"
    };
  }
}
message UpdateMessageRequest {
  message Data {
    string foo = 1;
    string bar = 2;
    string baz = 3;
  }

  // mapped to the URL as querystring params
  bool format = 1;
  string revision = 2;

  // mapped to the body
  Data data = 3;
}

Это позволяет для запроса HTTP PUT /v1/messages/123456?format=true&revision=2 с телом

foo="I am foo"
bar="I am bar"
baz="I am baz"

Поскольку сопоставление связывается body до типа UpdateMessageRequest.Data, остальные поля попадают в строку запроса. Этот подход используется в стандартных методах, но не в пользовательских ) методах.

Пользовательские методы должны отображать body в *. Один и тот же API с пользовательским методом будет

service Messaging {
  rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
    option (google.api.http) = {
      put: "/v1/messages/{message_id}"

      // Every field not bound by the path template should be
      // mapped to the request body.
      body: "*"
    };
  }
}
message UpdateMessageRequest {
  message Data {
    string foo = 1;
    string bar = 2;
    string baz = 3;
  }

  // mapped to the body
  bool format = 1;
  string revision = 2;
  Data data = 3;
}

Если одинаковые метаданные используются в обоих стандартных и пользовательских ) методах, он должен быть добавлен в виде параметров строки запроса или помещен в тело.

Например, приложение Angular будет использовать HttpParams

// standard method
const params = new HttpParams().append('format', true).append('revision', 2);
const request = {
  foo: "I am foo",
  bar: "I am bar",
  baz: "I am baz",
}
this.http.post<Document>(url, request, {params});

Однако Пользовательский метод требует, чтобы клиент поместил все в тело:

// custom method
const request = {
  format: true,
  revision: 2,
  data: {
    foo: "I am foo",
    bar: "I am bar",
    baz: "I am baz",
  },
}
this.http.post<Document>(url, request);

Вопрос: В чем причина этого?

1 Ответ

2 голосов
/ 19 февраля 2020

Отличный вопрос.

Для справки я написал AIP для этой темы c, а также правило lint, а также являюсь текущим сопровождающим руководства по проектированию, которое вы ссылка.

Прежде всего, я упомяну, что в нашем последнем руководстве (ссылка выше) специально сказано, что должно , а не должно для этого. Другими словами, это правильно делать большую часть времени, но могут быть исключения. Ничто в реализации транскодирования gRP C не мешает вам использовать другой body - мы советуем вам использовать * для пользовательских методов, но мы не ставим никаких технических барьеров против выполнения чего-либо еще .

Я могу вспомнить пару хороших "исключительных случаев", когда тело, отличное от *, может иметь смысл. Первый - это пользовательский метод, который смоделирован по одному из стандартных методов, но по какой-то причине должен быть пользовательским. Вторым было бы, если бы пользовательский метод принял полный ресурс и хотел установить тело для этого ресурса. Это сделает этот метод совместимым с Create и Update, что, очевидно, имеет значение для пользователей API.

Если у вас есть случай, когда у вас есть явный аргумент для использования чего-то еще в качестве тела (особенно если это что-то является самим ресурсом), во что бы то ни стало, используйте другое тело и скажите линтеру, чтобы он молчал. Мы написали «следует» по какой-то причине.

Вы также спросили: почему у нас эта рекомендация в первую очередь?

Есть несколько причин. Самым большим является то, что описанные выше исключительные случаи редки. Я делаю сотни обзоров API внутри страны, и я на самом деле не могу придумать ни одного из них на макушке (что не означает, что они не существуют). В большинстве случаев для пользователей лучше всего, чтобы сообщение запроса отражало полезную нагрузку HTTP.

Другая причина - ключевое ограничение: назначение определенного поля в качестве тела ограничивает то, что вы можете добавить вне этого поля, поскольку строки запроса ограничены в том, что они могут представлять как в типе (только примитивы), так и в количестве (ограничения длины URI). Поскольку изменение body позже представляет собой серьезное изменение, это несколько связывает ваши руки. Это может быть хорошо для вашего случая использования, очевидно, но важно отметить.

В любом случае, я надеюсь, что это поможет - о, и спасибо за использование моих вещей. : -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...