Skip to content

Commit 92ccdce

Browse files
authored
feat: produce a typed HTTP exception (influxdata#186)
1 parent 2e3d9d5 commit 92ccdce

19 files changed

+319
-82
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### Features
44
1. [#184](https://github.com/influxdata/influxdb-client-csharp/pull/184): Add possibility to specify `WebProxy` for Client
55
1. [#185](https://github.com/influxdata/influxdb-client-csharp/pull/185): Use `group()` function in output Flux query. See details - [Group function](/Client.Linq/README.md#group-function) [LINQ]
6+
1. [#186](https://github.com/influxdata/influxdb-client-csharp/pull/186): Produce a typed HTTP exception
67

78
### Bug Fixes
89
1. [#183](https://github.com/influxdata/influxdb-client-csharp/pull/183): Propagate runtime exception to EventHandler

Client.Core.Test/AbstractMockServerTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ public void ShutdownServer()
3838
MockServer?.Stop();
3939
}
4040

41-
protected IResponseBuilder CreateErrorResponse(string influxDbError)
41+
protected IResponseBuilder CreateErrorResponse(string influxDbError, int statusCode = 500)
4242
{
4343
var body = "{\"error\":\"" + influxDbError + "\"}";
4444

45-
return Response.Create().WithStatusCode(500)
45+
return Response.Create().WithStatusCode(statusCode)
4646
.WithHeader("X-Influx-Error", influxDbError)
4747
.WithBody(body);
4848
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System.Net;
2+
using InfluxDB.Client.Core.Exceptions;
3+
using NUnit.Framework;
4+
using RestSharp;
5+
6+
namespace InfluxDB.Client.Core.Test
7+
{
8+
[TestFixture]
9+
public class HttpExceptionTest
10+
{
11+
[Test]
12+
public void ExceptionTypes()
13+
{
14+
Assert.IsInstanceOf(typeof(BadRequestException), HttpException.Create(Response(400), ""));
15+
Assert.IsInstanceOf(typeof(UnauthorizedException), HttpException.Create(Response(401), ""));
16+
Assert.IsInstanceOf(typeof(PaymentRequiredException), HttpException.Create(Response(402), ""));
17+
Assert.IsInstanceOf(typeof(ForbiddenException), HttpException.Create(Response(403), ""));
18+
Assert.IsInstanceOf(typeof(NotFoundException), HttpException.Create(Response(404), ""));
19+
Assert.IsInstanceOf(typeof(MethodNotAllowedException), HttpException.Create(Response(405), ""));
20+
Assert.IsInstanceOf(typeof(NotAcceptableException), HttpException.Create(Response(406), ""));
21+
Assert.IsInstanceOf(typeof(ProxyAuthenticationRequiredException), HttpException.Create(Response(407), ""));
22+
Assert.IsInstanceOf(typeof(RequestTimeoutException), HttpException.Create(Response(408), ""));
23+
Assert.IsInstanceOf(typeof(RequestEntityTooLargeException), HttpException.Create(Response(413), ""));
24+
Assert.IsInstanceOf(typeof(UnprocessableEntityException), HttpException.Create(Response(422), ""));
25+
Assert.IsInstanceOf(typeof(TooManyRequestsException), HttpException.Create(Response(429), ""));
26+
Assert.IsInstanceOf(typeof(InternalServerErrorException), HttpException.Create(Response(500), ""));
27+
Assert.IsInstanceOf(typeof(HttpNotImplementedException), HttpException.Create(Response(501), ""));
28+
Assert.IsInstanceOf(typeof(BadGatewayException), HttpException.Create(Response(502), ""));
29+
Assert.IsInstanceOf(typeof(ServiceUnavailableException), HttpException.Create(Response(503), ""));
30+
Assert.IsInstanceOf(typeof(HttpException), HttpException.Create(Response(550), ""));
31+
Assert.IsInstanceOf(typeof(HttpException), HttpException.Create(Response(390), ""));
32+
}
33+
34+
private static HttpResponse Response(int statusCode)
35+
{
36+
return new HttpResponse {StatusCode = (HttpStatusCode) statusCode};
37+
}
38+
}
39+
}

Client.Core/Exceptions/InfluxException.cs

Lines changed: 185 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,191 @@ public static HttpException Create(object content, IList<HttpHeader> headers, st
126126
if (string.IsNullOrEmpty(errorMessage)) errorMessage = ErrorMessage;
127127
if (string.IsNullOrEmpty(errorMessage)) errorMessage = stringBody;
128128

129-
return new HttpException(errorMessage, (int) statusCode, exception)
130-
{ErrorBody = errorBody, RetryAfter = retryAfter};
129+
var err = (int) statusCode switch
130+
{
131+
400 => new BadRequestException(errorMessage, exception),
132+
401 => new UnauthorizedException(errorMessage, exception),
133+
402 => new PaymentRequiredException(errorMessage, exception),
134+
403 => new ForbiddenException(errorMessage, exception),
135+
404 => new NotFoundException(errorMessage, exception),
136+
405 => new MethodNotAllowedException(errorMessage, exception),
137+
406 => new NotAcceptableException(errorMessage, exception),
138+
407 => new ProxyAuthenticationRequiredException(errorMessage, exception),
139+
408 => new RequestTimeoutException(errorMessage, exception),
140+
413 => new RequestEntityTooLargeException(errorMessage, exception),
141+
422 => new UnprocessableEntityException(errorMessage, exception),
142+
429 => new TooManyRequestsException(errorMessage, exception),
143+
500 => new InternalServerErrorException(errorMessage, exception),
144+
501 => new HttpNotImplementedException(errorMessage, exception),
145+
502 => new BadGatewayException(errorMessage, exception),
146+
503 => new ServiceUnavailableException(errorMessage, exception),
147+
_ => new HttpException(errorMessage, (int) statusCode, exception)
148+
};
149+
150+
err.ErrorBody = errorBody;
151+
err.RetryAfter = retryAfter;
152+
153+
return err;
154+
}
155+
}
156+
157+
/// <summary>
158+
/// The exception for response: HTTP 400 - Bad Request.
159+
/// </summary>
160+
public class BadRequestException : HttpException
161+
{
162+
public BadRequestException(string message, Exception exception = null) : base(message, 400, exception)
163+
{
164+
}
165+
}
166+
167+
/// <summary>
168+
/// The exception for response: HTTP 401 - Unauthorized.
169+
/// </summary>
170+
public class UnauthorizedException : HttpException
171+
{
172+
public UnauthorizedException(string message, Exception exception = null) : base(message, 401, exception)
173+
{
174+
}
175+
}
176+
177+
/// <summary>
178+
/// The exception for response: HTTP 402 - Payment Required.
179+
/// </summary>
180+
public class PaymentRequiredException : HttpException
181+
{
182+
public PaymentRequiredException(string message, Exception exception = null) : base(message, 402, exception)
183+
{
184+
}
185+
}
186+
187+
/// <summary>
188+
/// The exception for response: HTTP 403 - Forbidden.
189+
/// </summary>
190+
public class ForbiddenException : HttpException
191+
{
192+
public ForbiddenException(string message, Exception exception = null) : base(message, 403, exception)
193+
{
194+
}
195+
}
196+
197+
/// <summary>
198+
/// The exception for response: HTTP 404 - Not Found.
199+
/// </summary>
200+
public class NotFoundException : HttpException
201+
{
202+
public NotFoundException(string message, Exception exception = null) : base(message, 404, exception)
203+
{
204+
}
205+
}
206+
207+
/// <summary>
208+
/// The exception for response: HTTP 405 - Method Not Allowed.
209+
/// </summary>
210+
public class MethodNotAllowedException : HttpException
211+
{
212+
public MethodNotAllowedException(string message, Exception exception = null) : base(message, 405, exception)
213+
{
214+
}
215+
}
216+
217+
/// <summary>
218+
/// The exception for response: HTTP 406 - Not Acceptable.
219+
/// </summary>
220+
public class NotAcceptableException : HttpException
221+
{
222+
public NotAcceptableException(string message, Exception exception = null) : base(message, 406, exception)
223+
{
224+
}
225+
}
226+
227+
/// <summary>
228+
/// The exception for response: HTTP 407 - Proxy Authentication Required.
229+
/// </summary>
230+
public class ProxyAuthenticationRequiredException : HttpException
231+
{
232+
public ProxyAuthenticationRequiredException(string message, Exception exception = null) : base(message, 407, exception)
233+
{
234+
}
235+
}
236+
237+
/// <summary>
238+
/// The exception for response: HTTP 408 - Request Timeout.
239+
/// </summary>
240+
public class RequestTimeoutException : HttpException
241+
{
242+
public RequestTimeoutException(string message, Exception exception = null) : base(message, 408, exception)
243+
{
244+
}
245+
}
246+
247+
/// <summary>
248+
/// The exception for response: HTTP 413 - Request Entity Too Large.
249+
/// </summary>
250+
public class RequestEntityTooLargeException : HttpException
251+
{
252+
public RequestEntityTooLargeException(string message, Exception exception = null) : base(message, 413, exception)
253+
{
254+
}
255+
}
256+
257+
/// <summary>
258+
/// The exception for response: HTTP 422 - Unprocessable Entity.
259+
/// </summary>
260+
public class UnprocessableEntityException : HttpException
261+
{
262+
public UnprocessableEntityException(string message, Exception exception = null) : base(message, 422, exception)
263+
{
264+
}
265+
}
266+
267+
/// <summary>
268+
/// The exception for response: HTTP 429 - Too Many Requests.
269+
/// </summary>
270+
public class TooManyRequestsException : HttpException
271+
{
272+
public TooManyRequestsException(string message, Exception exception = null) : base(message, 429, exception)
273+
{
274+
}
275+
}
276+
277+
/// <summary>
278+
/// The exception for response: HTTP 500 - Internal Server Error.
279+
/// </summary>
280+
public class InternalServerErrorException : HttpException
281+
{
282+
public InternalServerErrorException(string message, Exception exception = null) : base(message, 500, exception)
283+
{
284+
}
285+
}
286+
287+
/// <summary>
288+
/// The exception for response: HTTP 501 - Not Implemented.
289+
/// </summary>
290+
public class HttpNotImplementedException : HttpException
291+
{
292+
public HttpNotImplementedException(string message, Exception exception = null) : base(message, 501, exception)
293+
{
294+
}
295+
}
296+
297+
/// <summary>
298+
/// The exception for response: HTTP 502 - Bad Gateway.
299+
/// </summary>
300+
public class BadGatewayException : HttpException
301+
{
302+
public BadGatewayException(string message, Exception exception = null) : base(message, 502, exception)
303+
{
304+
}
305+
}
306+
307+
/// <summary>
308+
/// The exception for response: HTTP 503 - Service Unavailable.
309+
/// </summary>
310+
public class ServiceUnavailableException : HttpException
311+
{
312+
public ServiceUnavailableException(string message, Exception exception = null) : base(message, 503, exception)
313+
{
131314
}
132315
}
133316
}

Client.Test/InfluxDbClientTest.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using InfluxDB.Client.Api.Client;
66
using InfluxDB.Client.Api.Domain;
77
using InfluxDB.Client.Core;
8+
using InfluxDB.Client.Core.Exceptions;
89
using InfluxDB.Client.Core.Test;
910
using NUnit.Framework;
1011
using WireMock.RequestBuilders;
@@ -222,5 +223,18 @@ public void TrailingSlashInUrl()
222223
StringAssert.StartsWith(MockServerUrl + "/api/v2/", logEntry.RequestMessage.AbsoluteUrl);
223224
}
224225
}
226+
227+
[Test]
228+
public void ProduceTypedException()
229+
{
230+
MockServer
231+
.Given(Request.Create().UsingGet())
232+
.RespondWith(CreateErrorResponse("unauthorized", 401));
233+
234+
var ioe = Assert.ThrowsAsync<UnauthorizedException>(async () =>
235+
await _client.GetAuthorizationsApi().FindAuthorizationByIdAsync("id"));
236+
237+
Assert.AreEqual("unauthorized", ioe.Message);
238+
}
225239
}
226240
}

Client.Test/ItAuthorizationsApiTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public async Task FindAuthorizationsById()
136136
[Test]
137137
public void FindAuthorizationsByIdNull()
138138
{
139-
var ioe = Assert.ThrowsAsync<HttpException>(async () =>
139+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () =>
140140
await _authorizationsApi.FindAuthorizationByIdAsync("020f755c3c082000"));
141141

142142
Assert.AreEqual("authorization not found", ioe.Message);
@@ -154,7 +154,7 @@ public async Task DeleteAuthorization()
154154
// delete authorization
155155
await _authorizationsApi.DeleteAuthorizationAsync(createdAuthorization);
156156

157-
var ioe = Assert.ThrowsAsync<HttpException>(async () =>
157+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () =>
158158
await _authorizationsApi.FindAuthorizationByIdAsync(createdAuthorization.Id));
159159

160160
Assert.AreEqual("authorization not found", ioe.Message);
@@ -206,11 +206,11 @@ public async Task CloneAuthorization()
206206
[Test]
207207
public void CloneAuthorizationNotFound()
208208
{
209-
var ioe = Assert.ThrowsAsync<HttpException>(async () =>
209+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () =>
210210
await _authorizationsApi.CloneAuthorizationAsync("020f755c3c082000"));
211211

212212
Assert.AreEqual("authorization not found", ioe.Message);
213-
Assert.AreEqual(typeof(HttpException), ioe.GetType());
213+
Assert.AreEqual(typeof(NotFoundException), ioe.GetType());
214214
}
215215

216216
private List<Permission> NewPermissions()

Client.Test/ItBucketsApiTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public async Task CloneBucket()
6565
[Test]
6666
public void CloneBucketNotFound()
6767
{
68-
var ioe = Assert.ThrowsAsync<HttpException>(async () =>
68+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () =>
6969
await _bucketsApi.CloneBucketAsync(GenerateName("bucket"), "020f755c3c082000"));
7070

7171
Assert.AreEqual("bucket not found", ioe.Message);
@@ -117,7 +117,7 @@ public async Task DeleteBucket()
117117
// delete task
118118
await _bucketsApi.DeleteBucketAsync(createBucket);
119119

120-
var ioe = Assert.ThrowsAsync<HttpException>(async () => await _bucketsApi.FindBucketByIdAsync(createBucket.Id));
120+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () => await _bucketsApi.FindBucketByIdAsync(createBucket.Id));
121121

122122
Assert.AreEqual("bucket not found", ioe.Message);
123123
}
@@ -142,7 +142,7 @@ public async Task FindBucketById()
142142
[Test]
143143
public void FindBucketByIdNull()
144144
{
145-
var ioe = Assert.ThrowsAsync<HttpException>(async () =>
145+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () =>
146146
await _bucketsApi.FindBucketByIdAsync("020f755c3c082000"));
147147

148148
Assert.AreEqual("bucket not found", ioe.Message);

Client.Test/ItChecksApiTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public void UpdateCheckNotExists()
174174
var update = new CheckPatch(name: "not exits name", description: "not exists update",
175175
status: CheckPatch.StatusEnum.Active);
176176

177-
var ioe = Assert.ThrowsAsync<HttpException>(async () => await _checksApi
177+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () => await _checksApi
178178
.UpdateCheckAsync("020f755c3c082000", update));
179179

180180
Assert.AreEqual("check not found for key \"020f755c3c082000\"", ioe.Message);
@@ -198,7 +198,7 @@ public async Task DeleteCheck()
198198

199199
await _checksApi.DeleteCheckAsync(found);
200200

201-
var ioe = Assert.ThrowsAsync<HttpException>(async () => await _checksApi
201+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () => await _checksApi
202202
.FindCheckByIdAsync("020f755c3c082000"));
203203

204204
Assert.AreEqual("check not found for key \"020f755c3c082000\"", ioe.Message);
@@ -207,7 +207,7 @@ public async Task DeleteCheck()
207207
[Test]
208208
public void DeleteCheckNotFound()
209209
{
210-
var ioe = Assert.ThrowsAsync<HttpException>(async () => await _checksApi
210+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () => await _checksApi
211211
.DeleteCheckAsync("020f755c3c082000"));
212212

213213
Assert.AreEqual("check not found for key \"020f755c3c082000\"", ioe.Message);
@@ -235,7 +235,7 @@ public async Task FindCheckById()
235235
[Test]
236236
public void FindCheckByIdNotFound()
237237
{
238-
var ioe = Assert.ThrowsAsync<HttpException>(async () => await _checksApi
238+
var ioe = Assert.ThrowsAsync<NotFoundException>(async () => await _checksApi
239239
.FindCheckByIdAsync("020f755c3c082000"));
240240

241241
Assert.AreEqual("check not found for key \"020f755c3c082000\"", ioe.Message);

Client.Test/ItInfluxDBClientTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public void OnBoardingAlreadyDone()
9898
{
9999
var onboarding = new OnboardingRequest("admin", "11111111", "Testing", "test");
100100

101-
var ex = Assert.ThrowsAsync<HttpException>(async () => await Client.OnboardingAsync(onboarding));
101+
var ex = Assert.ThrowsAsync<UnprocessableEntityException>(async () => await Client.OnboardingAsync(onboarding));
102102

103103
Assert.AreEqual("onboarding has already been completed", ex.Message);
104104
Assert.AreEqual(422, ex.Status);

0 commit comments

Comments
 (0)