Request-based API
snsinfu opened this issue · comments
As a deno library, it would be more natural to sign a Request object than an ad-hoc method-url pair (plus opts.body). The sign function should look like:
sign(req: Request, opts?: SignOptions): Request;
This way, I can compose a fully customized request object, sign it and immediately pass the result to the fetch function:
const request = new Request(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Version": "1",
},
body: JSON.stringify(data),
});
const response = await fetch(
client.sign(request, { token: userToken })
);
Docs on the Request class:
Notes on a request body.
A request object only provides a single-pass access to its body content as a stream. So, a client needs to clone the request object to sign the request body.
https://developer.mozilla.org/en-US/docs/Web/API/Request/clone
Also, the client needs to figure out if the body is form-encoded or not. Because, in and only in the former case, the form-encoded parameters must be signed in conjunction with OAuth protocol parameters.
In addition, a client needs an extra flag to sign non-form-encoded body or not. One can always sign a request object without body and attach a body thereafter, but the client cannot be sure if it should generate a hash for the empty body or not.
Critical flaw: Any access to Request body needs to be async. So, the sign method needs to be async if it is designed to sign a Request object.
That is not good. If I see an async method in an OAuth context, I expect it should actually do an HTTP request. It's too confusing.
The sign method could alternatively receive an RequestInit or a similar object and return a signed Request. This way the sign method can be made async-free. But, now the Request integration becomes half-assed (it can't sign pre-composed requests!), plus I will need to keep the sign method compatible with the Request constructor even if I don't care about extra Request options.
So, let's trash the idea.