为什么自定义方法不应该使用URL传输数据?

问题描述 投票:1回答:1

TL,DR;在实现custom methods时,“ HTTP配置[...]必须使用body:*子句,并且所有剩余的请求消息字段都应映射到HTTP请求正文。”] >。 为什么?

我尝试使用API Design Guide跟踪Google的gRPC with Cloud Endpoints时遇到问题。

HttpRule用于transcode HTTP/JSON to gRPCHttpRule reference状态:

注意,当使用正文中的*

映射时,不可能具有HTTP参数,因为不受路径限制的所有字段都在主体结尾。

[...] *的常用用法在不使用]的自定义方法中>

完全用于传输数据的URL。

...在Google的Custom Methods documentation中也重复了这一观点,并以Google's 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;
}

这允许对带有主体的/v1/messages/123456?format=true&revision=2进行HTTP PUT请求>

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

由于映射将body绑定到类型UpdateMessageRequest.Data,因此其余字段最终出现在查询字符串中。这是standard方法中使用的方法,但custom)方法中没有使用。

自定义方法必须将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;
}

如果在standardcustom中都使用了相同的元数据

,则必须将其添加为查询字符串参数,或放置在正文中。

例如,一个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);

问题:

这是什么原因?

TL,DR;在实现自定义方法时,“ HTTP配置必须使用body:*子句,并且所有剩余的请求消息字段都应映射到HTTP请求主体。”为什么?我有问题...

好问题。

作为参考,我编写了the AIP on this topic以及皮棉规则,并且还是您所参考的设计指南的当前维护者。

首先,我会提到我们最新的指南(上面已链接)专门针对此问题,说的是[[应该

,而不是必须。换句话说,大部分时间都是正确的做法,但是可能会有例外。 the gRPC transcoding implementation中的任何内容都不会阻止您使用其他body-我们告诉您将*用于自定义方法,但是我们不会对执行其他操作设置任何技术障碍。我可以想到几个很好的“例外情况”,其中*以外的物体可能有意义。第一个是自定义方法,该方法以一种标准方法为模型,但是出于某种原因应该自定义。第二种情况是自定义方法是否接受了完整的资源,并希望将主体设置为该资源。这将使该方法与CreateUpdate一致,这显然对API的用户有价值。

[如果您有明确的论点,那就是将其他东西用作主体(尤其是某些东西本身就是资源本身),无论如何,请使用不同的主体并告诉短毛绒保持安静。我们写“应该”是有原因的。

您还问过:为什么我们首先提出该建议?

有几个原因。最大的一个是,上述例外情况很少见。我在内部进行了数百次API审查,但实际上我无法想到一个(不是说它们不存在)。在大多数情况下,对用户来说最好的事情是使请求消息镜像HTTP有效负载。

另一个原因是关键限制:将特定字段指定为正文会限制您可以在该字段中添加

outside

,因为查询字符串在类型(仅是基本类型)和数量方面都受到限制(URI长度限制)。因为以后更改body会造成重大变化,所以这在某种程度上会束缚您的双手。显然,这对您的用例可能很好,但是请务必注意。无论如何,希望对您有所帮助-哦,谢谢您使用我的东西。 :-)
grpc google-cloud-endpoints api-design google-api-linter
1个回答
0
投票

好问题。

© www.soinside.com 2019 - 2024. All rights reserved.