-
Notifications
You must be signed in to change notification settings - Fork 409
Re-implementing the HTTP Client Abstraction #280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Related to #274 |
|
I haven't started review yet, but why do we want to support HTTP requests? I am hoping that you are not planning to use this with unencrypted connections. |
|
I want to be able to use this to access things like the local Metadata service, which is only available over HTTP: https://github.com/firebase/firebase-admin-node/blob/master/src/auth/credential.ts#L338 |
src/utils/api-request.ts
Outdated
| public readonly headers: any; | ||
| public readonly text: string; | ||
|
|
||
| private readonly data_: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private properties should not use trailing underscores (typescript style guide).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/utils/api-request.ts
Outdated
| public readonly text: string; | ||
|
|
||
| private readonly data_: any; | ||
| private readonly request_: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private properties should not use trailing underscores (typescript style guide).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/utils/api-request.ts
Outdated
| return this.data_; | ||
| } | ||
| try { | ||
| return JSON.parse(this.text); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this try/catch needed again? You already test this in the constructor. You may as well throw an error directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| url: string; | ||
| headers?: {[key: string]: string}; | ||
| data?: string | object | Buffer; | ||
| timeout?: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there no port number (in case a non-default one is used)? It seems like this has to be provided in the URL. Maybe document that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| readonly data: any; | ||
| } | ||
|
|
||
| class DefaultHttpResponse implements HttpResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadocs for these new structures would be nice to have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/utils/api-request.ts
Outdated
| respStream.on('end', () => { | ||
| const responseData = Buffer.concat(responseBuffer).toString(); | ||
| response.data = responseData; | ||
| settle(resolve, reject, response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rename to something less abstract?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to finalizeRequest
| } | ||
|
|
||
| function enhanceError( | ||
| error, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error: Error,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not possible since we add new fields to the error object in the method body (triggers TS compilation error).
| return 'access_token_' + _.random(999999999); | ||
| } | ||
|
|
||
| export function responseFrom(data: any, status: number = 200, headers: any = {}): HttpResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add javadoc. Also where is this used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Not used anywhere at the moment. But it will be used once we start mocking interactions in other unit tests. I have separate PRs coming up for that.
| }); | ||
| }); | ||
|
|
||
| it('should be fulfilled for a 2xx response with a json payload', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks exactly like the test above it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
test/unit/utils/api-request.spec.ts
Outdated
| const reqData = {request: 'data'}; | ||
| const respData = {success: true}; | ||
| const scope = nock('https://' + mockHost, { | ||
| reqheaders: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indent 2 spaces instead of 4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
Made the suggested changes. Over to @bojeil-google for another look. |
bojeil-google
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Just have a bunch of javadoc nits to be consistent with the rest of the repo.
test/unit/utils.ts
Outdated
| /** | ||
| * Creates a mock HTTP response from the given data and parameters. | ||
| * | ||
| * @param data Data to be included in the response body. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@param {*} data ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/unit/utils.ts
Outdated
| * Creates a mock HTTP response from the given data and parameters. | ||
| * | ||
| * @param data Data to be included in the response body. | ||
| * @param status HTTP status code (defaults to 200). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@param {number=} status...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/unit/utils.ts
Outdated
| * | ||
| * @param data Data to be included in the response body. | ||
| * @param status HTTP status code (defaults to 200). | ||
| * @param headers HTTP headers to be included in the ersponse. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@param {*=} headers...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| this.request = `${resp.config.method} ${resp.config.url}`; | ||
| } | ||
|
|
||
| get data(): any { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc missing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to get inherited from the parent interface. At least on VSCode, hovering over the getter shows the documentation from the interface.
| response?: LowLevelResponse; | ||
| } | ||
|
|
||
| function sendRequest(config: HttpRequestConfig): Promise<LowLevelResponse> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| } | ||
|
|
||
| function settle(resolve, reject, response: LowLevelResponse) { | ||
| function finalizeRequest(resolve, reject, response: LowLevelResponse) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I'm only adding a description to these un-exported helper functions.
| private readonly parseError: Error; | ||
| private readonly request: string; | ||
|
|
||
| constructor(resp: LowLevelResponse) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be consistent, we have been adding javadocs in other files. Let's add one here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
Updated the documentation as recommended. |
The existing HTTP client abstractions (
HttpRequestHandlerandSignedApiRequestHandler) have a number of caveats:application/json,text/htmlandtext/plain)I ran into pretty much all the above problems while prototyping the IAM support for token minting.
To resolve these problems I propose a new set of HTTP client abstractions (
HttpClientandAuthorizedHttpClient). My original plan was to use theaxioslibrary under the hood, but its support for handling timeouts needs a bit of work. So I came up with an implementation which borrows from bothaxiosand our already existingHttpRequestHandlerclass. The resulting implementation:HttpErrorwhich provides access to the response object. All other low-level errors result in aFirebaseAppError.HttpRequestConfigtypeThis PR implements the new abstractions and provides unit tests. I will update the rest of the codebase to use them in a series of future PRs (work already underway in a separate branch).