Skip to content

Commit f1a2bbe

Browse files
committed
Common logic for making http calls with error handling
1 parent 4582eed commit f1a2bbe

File tree

4 files changed

+134
-93
lines changed

4 files changed

+134
-93
lines changed

FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,33 @@ public async Task ListUsersIntermittentHttpError()
718718
Assert.Equal("token", query["nextPageToken"]);
719719
}
720720

721+
[Fact]
722+
public async Task ListUsersNonJsonResponse()
723+
{
724+
var handler = new MockMessageHandler()
725+
{
726+
Response = "not json",
727+
};
728+
var auth = this.CreateFirebaseAuth(handler);
729+
730+
var pagedEnumerable = auth.ListUsersAsync(null);
731+
var exception = await Assert.ThrowsAsync<FirebaseAuthException>(
732+
async () => await pagedEnumerable.First());
733+
734+
Assert.Equal(ErrorCode.Unknown, exception.ErrorCode);
735+
Assert.Equal(AuthErrorCode.UnexpectedResponse, exception.AuthErrorCode);
736+
Assert.Equal(
737+
"Error while parsing Auth service response.",
738+
exception.Message);
739+
Assert.NotNull(exception.HttpResponse);
740+
Assert.NotNull(exception.InnerException);
741+
742+
Assert.Single(handler.Requests);
743+
var query = this.ExtractQueryParams(handler.Requests[0]);
744+
Assert.Single(query);
745+
Assert.Equal("1000", query["maxResults"]);
746+
}
747+
721748
[Fact]
722749
public async Task CreateUser()
723750
{
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright 2019, Google Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Net.Http;
17+
using System.Threading;
18+
using System.Threading.Tasks;
19+
using Google.Apis.Http;
20+
using Google.Apis.Json;
21+
22+
namespace FirebaseAdmin.Auth
23+
{
24+
internal static class AuthHttpUtils
25+
{
26+
internal static async Task<ResponseInfo> SendAndReadAsync(
27+
this ConfigurableHttpClient httpClient,
28+
HttpRequestMessage request,
29+
CancellationToken cancellationToken)
30+
{
31+
try
32+
{
33+
var response = await httpClient.SendAsync(request, cancellationToken)
34+
.ConfigureAwait(false);
35+
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
36+
37+
return new ResponseInfo()
38+
{
39+
HttpResponse = response,
40+
Body = json,
41+
};
42+
}
43+
catch (HttpRequestException e)
44+
{
45+
var temp = e.ToFirebaseException();
46+
throw new FirebaseAuthException(
47+
temp.ErrorCode,
48+
temp.Message,
49+
inner: temp.InnerException,
50+
response: temp.HttpResponse);
51+
}
52+
}
53+
54+
internal class ResponseInfo
55+
{
56+
internal HttpResponseMessage HttpResponse { get; set; }
57+
58+
internal string Body { get; set; }
59+
60+
internal ParsedResponseInfo<TResult> SafeDeserialize<TResult>()
61+
{
62+
try
63+
{
64+
var parsed = NewtonsoftJsonSerializer.Instance.Deserialize<TResult>(this.Body);
65+
return new ParsedResponseInfo<TResult>()
66+
{
67+
Result = parsed,
68+
HttpResponse = this.HttpResponse,
69+
Body = this.Body,
70+
};
71+
}
72+
catch (Exception e)
73+
{
74+
throw new FirebaseAuthException(
75+
ErrorCode.Unknown,
76+
"Error while parsing Auth service response.",
77+
AuthErrorCode.UnexpectedResponse,
78+
inner: e,
79+
response: this.HttpResponse);
80+
}
81+
}
82+
}
83+
84+
internal class ParsedResponseInfo<T> : ResponseInfo
85+
{
86+
internal T Result { get; set; }
87+
}
88+
}
89+
}

FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs

Lines changed: 6 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,15 @@ private async Task<UserRecord> GetUserAsync(
256256
return new UserRecord(result.Users[0]);
257257
}
258258

259-
private async Task<ParsedResponseInfo<TResult>> PostAndDeserializeAsync<TResult>(
259+
private async Task<AuthHttpUtils.ParsedResponseInfo<TResult>> PostAndDeserializeAsync<TResult>(
260260
string path, object body, CancellationToken cancellationToken)
261261
{
262262
var response = await this.PostAsync(path, body, cancellationToken)
263263
.ConfigureAwait(false);
264264
return response.SafeDeserialize<TResult>();
265265
}
266266

267-
private async Task<ResponseInfo> PostAsync(
267+
private async Task<AuthHttpUtils.ResponseInfo> PostAsync(
268268
string path, object body, CancellationToken cancellationToken)
269269
{
270270
var request = new HttpRequestMessage()
@@ -276,26 +276,12 @@ private async Task<ResponseInfo> PostAsync(
276276
return await this.SendAsync(request, cancellationToken).ConfigureAwait(false);
277277
}
278278

279-
private async Task<ResponseInfo> SendAsync(
279+
private async Task<AuthHttpUtils.ResponseInfo> SendAsync(
280280
HttpRequestMessage request, CancellationToken cancellationToken)
281281
{
282-
try
283-
{
284-
var response = await this.httpClient.SendAsync(request, cancellationToken)
285-
.ConfigureAwait(false);
286-
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
287-
this.errorHandler.ThrowIfError(response, json);
288-
289-
return new ResponseInfo()
290-
{
291-
HttpResponse = response,
292-
Body = json,
293-
};
294-
}
295-
catch (HttpRequestException e)
296-
{
297-
throw this.ToFirebaseAuthException(e);
298-
}
282+
var response = await this.httpClient.SendAndReadAsync(request, cancellationToken);
283+
this.errorHandler.ThrowIfError(response.HttpResponse, response.Body);
284+
return response;
299285
}
300286

301287
private FirebaseAuthException ToFirebaseAuthException(
@@ -346,35 +332,5 @@ internal Dictionary<string, object> Build()
346332
};
347333
}
348334
}
349-
350-
private class ResponseInfo
351-
{
352-
internal HttpResponseMessage HttpResponse { get; set; }
353-
354-
internal string Body { get; set; }
355-
356-
internal ParsedResponseInfo<TResult> SafeDeserialize<TResult>()
357-
{
358-
try
359-
{
360-
var parsed = NewtonsoftJsonSerializer.Instance.Deserialize<TResult>(this.Body);
361-
return new ParsedResponseInfo<TResult>()
362-
{
363-
Result = parsed,
364-
HttpResponse = this.HttpResponse,
365-
Body = this.Body,
366-
};
367-
}
368-
catch (Exception e)
369-
{
370-
throw UnexpectedResponseException("Error while parsing Auth service response", e);
371-
}
372-
}
373-
}
374-
375-
private class ParsedResponseInfo<T> : ResponseInfo
376-
{
377-
internal T Result { get; set; }
378-
}
379335
}
380336
}

FirebaseAdmin/FirebaseAdmin/Auth/ListUsersRequest.cs

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
using System.Threading;
2121
using System.Threading.Tasks;
2222
using Google.Apis.Discovery;
23-
using Google.Apis.Json;
23+
using Google.Apis.Http;
2424
using Google.Apis.Requests;
2525
using Google.Apis.Services;
2626

@@ -35,11 +35,11 @@ internal sealed class ListUsersRequest : IClientServiceRequest<ExportedUserRecor
3535
private const int MaxListUsersResults = 1000;
3636

3737
private readonly string baseUrl;
38-
private readonly HttpClient httpClient;
38+
private readonly ConfigurableHttpClient httpClient;
3939
private readonly AuthErrorHandler errorHandler;
4040

4141
private ListUsersRequest(
42-
string baseUrl, HttpClient httpClient, ListUsersOptions options)
42+
string baseUrl, ConfigurableHttpClient httpClient, ListUsersOptions options)
4343
{
4444
this.baseUrl = baseUrl;
4545
this.httpClient = httpClient;
@@ -78,7 +78,7 @@ public Task<Stream> ExecuteAsStreamAsync()
7878
public Task<Stream> ExecuteAsStreamAsync(CancellationToken cancellationToken)
7979
{
8080
var response = this.SendAsync(this.CreateRequest(), cancellationToken);
81-
return response.Result.Content.ReadAsStreamAsync();
81+
return response.Result.HttpResponse.Content.ReadAsStreamAsync();
8282
}
8383

8484
public Stream ExecuteAsStream()
@@ -172,49 +172,18 @@ private void AddOrUpdate(string paramName, string value)
172172
private async Task<DownloadAccountResponse> SendAndDeserializeAsync(
173173
HttpRequestMessage request, CancellationToken cancellationToken)
174174
{
175-
var json = await this.SendAndReadAsync(request, cancellationToken)
175+
var response = await this.SendAsync(request, cancellationToken)
176176
.ConfigureAwait(false);
177-
try
178-
{
179-
return NewtonsoftJsonSerializer.Instance.Deserialize<DownloadAccountResponse>(json);
180-
}
181-
catch (Exception e)
182-
{
183-
throw new FirebaseAuthException(
184-
ErrorCode.Unknown,
185-
"Error while parsing Auth service response",
186-
AuthErrorCode.UnexpectedResponse,
187-
inner: e);
188-
}
189-
}
190-
191-
private async Task<string> SendAndReadAsync(
192-
HttpRequestMessage request, CancellationToken cancellationToken)
193-
{
194-
try
195-
{
196-
var response = await this.SendAsync(request, cancellationToken)
197-
.ConfigureAwait(false);
198-
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
199-
this.errorHandler.ThrowIfError(response, json);
200-
return json;
201-
}
202-
catch (HttpRequestException e)
203-
{
204-
var temp = e.ToFirebaseException();
205-
throw new FirebaseAuthException(
206-
temp.ErrorCode,
207-
temp.Message,
208-
inner: temp.InnerException,
209-
response: temp.HttpResponse);
210-
}
177+
return response.SafeDeserialize<DownloadAccountResponse>().Result;
211178
}
212179

213-
private async Task<HttpResponseMessage> SendAsync(
180+
private async Task<AuthHttpUtils.ResponseInfo> SendAsync(
214181
HttpRequestMessage request, CancellationToken cancellationToken)
215182
{
216-
return await this.httpClient.SendAsync(request, cancellationToken)
183+
var response = await this.httpClient.SendAndReadAsync(request, cancellationToken)
217184
.ConfigureAwait(false);
185+
this.errorHandler.ThrowIfError(response.HttpResponse, response.Body);
186+
return response;
218187
}
219188

220189
/// <summary>
@@ -224,11 +193,11 @@ private async Task<HttpResponseMessage> SendAsync(
224193
internal sealed class Factory
225194
{
226195
private readonly string baseUrl;
227-
private readonly HttpClient httpClient;
196+
private readonly ConfigurableHttpClient httpClient;
228197
private readonly ListUsersOptions options;
229198

230199
internal Factory(
231-
string baseUrl, HttpClient httpClient, ListUsersOptions options = null)
200+
string baseUrl, ConfigurableHttpClient httpClient, ListUsersOptions options = null)
232201
{
233202
this.baseUrl = baseUrl;
234203
this.httpClient = httpClient;

0 commit comments

Comments
 (0)