Skip to content

Commit a40f69f

Browse files
authored
Merge pull request #23 from bunq/feature/exception-handler
Feature/exception handler
2 parents 4814e7e + 9e373c7 commit a40f69f

16 files changed

+222
-29
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,4 @@ bunq.conf
265265
**/Tmp/
266266
bunq-test.conf
267267
config.json
268+
.idea/.idea.BunqSdk/.idea/preferred-vcs.xml

BunqSdk.Tests/BunqSdkTestBase.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,13 @@ protected static ApiContext GetApiContext()
3636
try
3737
{
3838
apiContext = ApiContext.Restore(FILENAME_CONTEXT_CONF);
39-
User.List(apiContext);
4039
}
4140
catch (BunqException)
4241
{
4342
apiContext = CreateApiContext();
4443
}
45-
catch (ApiException)
46-
{
47-
apiContext = CreateApiContext();
48-
}
4944

45+
apiContext.EnsureSessionActive();
5046
apiContext.Save(FILENAME_CONTEXT_CONF);
5147

5248
return apiContext;

BunqSdk.Tests/Model/Generated/Endpoint/SessionTest.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
using Bunq.Sdk.Context;
1+
using System;
2+
using System.IO;
3+
using Bunq.Sdk.Context;
24
using Bunq.Sdk.Model.Generated.Endpoint;
35
using Xunit;
6+
using Xunit.Sdk;
47

58
namespace Bunq.Sdk.Tests.Model.Generated.Endpoint
69
{
@@ -10,6 +13,11 @@ namespace Bunq.Sdk.Tests.Model.Generated.Endpoint
1013
/// </summary>
1114
public class SessionTest : BunqSdkTestBase
1215
{
16+
/// <summary>
17+
/// Name of the context configuration file.
18+
/// </summary>
19+
private const string FILENAME_CONTEXT_CONF = "../../../bunq-test.conf";
20+
1321
/// <summary>
1422
/// Config values.
1523
/// </summary>
@@ -29,6 +37,8 @@ public class SessionTest : BunqSdkTestBase
2937
public void TestSessionDeletion()
3038
{
3139
Session.Delete(API_CONTEXT, SESSION_ID_DUMMY);
40+
41+
File.Delete(FILENAME_CONTEXT_CONF);
3242
}
3343
}
3444
}

BunqSdk/Exception/ApiException.cs

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,15 @@
1-
using System.Collections.Generic;
2-
1+

32
namespace Bunq.Sdk.Exception
43
{
5-
/// <summary>
6-
/// Exception triggered by API requests failed on the server side.
7-
/// </summary>
84
public class ApiException : System.Exception
95
{
10-
/// <summary>
11-
/// Glue to concatenate the error messages.
12-
/// </summary>
13-
private const string GLUE_ERROR_MESSAGES = "\n";
14-
156
public int ResponseCode { get; private set; }
16-
public IList<string> Messages { get; private set; }
177

188
/// <param name="responseCode">The HTTP Response code of the failed request.</param>
19-
/// <param name="messages">The list of messages related to this exception.</param>
20-
public ApiException(int responseCode, IList<string> messages) : base(
21-
ConcatenateMessages(messages))
9+
/// <param name="message">The error message related to this exception.</param>
10+
public ApiException(int responseCode, string message) : base(message)
2211
{
2312
ResponseCode = responseCode;
24-
Messages = messages;
25-
}
26-
27-
private static string ConcatenateMessages(IEnumerable<string> messages)
28-
{
29-
return string.Join(GLUE_ERROR_MESSAGES, messages);
3013
}
31-
}
14+
}
3215
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Bunq.Sdk.Exception
2+
{
3+
public class BadRequestException : ApiException
4+
{
5+
public BadRequestException(int responseCode, string message) : base(responseCode, message)
6+
{
7+
}
8+
}
9+
}

BunqSdk/Exception/EXCEPTIONS.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
## Exceptions
2+
When you make a request via the SDK, there is a chance of request failing
3+
due to various reasons. When such a failure happens, an exception
4+
corresponding to the error occurred is thrown.
5+
6+
7+
----
8+
#### Possible Exceptions
9+
* `BadRequestException` If the request returns with status code `400`
10+
* `UnauthorizedException` If the request returns with status code `401`
11+
* `ForbiddenException` If the request returns with status code `403`
12+
* `NotFoundException` If the request returns with status code `404`
13+
* `MethodNotAllowedException` If the request returns with status code `405`
14+
* `TooManyRequestsException` If the request returns with status code `429`
15+
* `PleaseContactBunqException` If the request returns with status code `500`.
16+
If you get this exception, please contact us preferably via the support chat in the bunq app.
17+
* `UnknownApiErrorException` If none of the above mentioned exceptions are thrown,
18+
this exception will be thrown instead.
19+
20+
For more information regarding these errors, please take a look on the documentation
21+
page here: https://doc.bunq.com/api/1/page/errors
22+
23+
---
24+
#### Base exception
25+
All the exceptions have the same base exception which looks like this:
26+
```c#
27+
public class ApiException : System.Exception
28+
{
29+
public int ResponseCode { get;}
30+
31+
/// <param name="responseCode">The HTTP Response code of the failed request.</param>
32+
/// <param name="message">The error messages related to this exception.</param>
33+
public ApiException(int responseCode, string message) : base(message)
34+
{
35+
// hidden code
36+
}
37+
}
38+
```
39+
This means that each exception will have a response code and an error message
40+
related to the specific error returned by API.
41+
42+
---
43+
#### Exception handling
44+
Since each API error has a distinct SDK exception type corresponding to it,
45+
you can catch the exact exceptions you expect 👏.
46+
47+
```c#
48+
using Bunq.Sdk.Context;
49+
using Bunq.Sdk.Exception;
50+
51+
public class BadRequest
52+
{
53+
private const string API_KEY = "Some invalid API key"
54+
private const string DESCRIPTION = "This will throw BadRequestException."
55+
56+
public void Run()
57+
{
58+
try
59+
{
60+
ApiContext.Create(ApiEnvironmentType.SANDBOX, API_KEY, DEVICE_DESCRIPTION);
61+
}
62+
catch(BadRequestException error)
63+
{
64+
Console.WriteLine(error.getMessage())
65+
Console.WriteLine(error.getResponseCode())
66+
}
67+
}
68+
}
69+
```
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Collections.Generic;
2+
3+
namespace Bunq.Sdk.Exception
4+
{
5+
public class ExceptionFactory
6+
{
7+
/// <summary>
8+
/// HTTP error response codes constants.
9+
/// </summary>
10+
private const int HTTP_RESPONSE_CODE_BAD_REQUEST = 400;
11+
private const int HTTP_RESPONSE_CODE_UNAUTHORIZED = 401;
12+
private const int HTTP_RESPONSE_CODE_FORBIDDEN = 403;
13+
private const int HTTP_RESPONSE_CODE_NOT_FOUND = 404;
14+
private const int HTTP_RESPONSE_CODE_METHOD_NOT_ALLOWED = 405;
15+
private const int HTTP_RESPONSE_CODE_TOO_MANY_REQUESTS = 429;
16+
private const int HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR = 500;
17+
18+
/// <summary>
19+
/// Glue to concatenate the error messages.
20+
/// </summary>
21+
private const string GLUE_ERROR_MESSAGES = "\n";
22+
23+
/// <returns>The exception that belongs to this status code.</returns>
24+
public static ApiException CreateExceptionForResponse(int responseCode, IList<string> messages)
25+
{
26+
var errorMessage = ConcatenateMessages(messages);
27+
28+
switch (responseCode)
29+
{
30+
case HTTP_RESPONSE_CODE_BAD_REQUEST:
31+
return new BadRequestException(responseCode, errorMessage);
32+
case HTTP_RESPONSE_CODE_UNAUTHORIZED:
33+
return new UnauthorizedException(responseCode, errorMessage);
34+
case HTTP_RESPONSE_CODE_FORBIDDEN:
35+
return new ForbiddenException(responseCode, errorMessage);
36+
case HTTP_RESPONSE_CODE_NOT_FOUND:
37+
return new NotFoundException(responseCode, errorMessage);
38+
case HTTP_RESPONSE_CODE_METHOD_NOT_ALLOWED:
39+
return new MethodNotAllowedException(responseCode, errorMessage);
40+
case HTTP_RESPONSE_CODE_TOO_MANY_REQUESTS:
41+
return new TooManyRequestsException(responseCode, errorMessage);
42+
case HTTP_RESPONSE_CODE_INTERNAL_SERVER_ERROR:
43+
return new PleaseContactBunqException(responseCode, errorMessage);
44+
default:
45+
return new UnknownApiErrorException(responseCode, errorMessage);
46+
}
47+
}
48+
49+
private static string ConcatenateMessages(IEnumerable<string> messages)
50+
{
51+
return string.Join(GLUE_ERROR_MESSAGES, messages);
52+
}
53+
}
54+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Bunq.Sdk.Exception
2+
{
3+
public class ForbiddenException : ApiException
4+
{
5+
public ForbiddenException(int responseCode, string message) : base(responseCode, message)
6+
{
7+
}
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Bunq.Sdk.Exception
2+
{
3+
public class MethodNotAllowedException : ApiException
4+
{
5+
public MethodNotAllowedException(int responseCode, string message) : base(responseCode, message)
6+
{
7+
}
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Bunq.Sdk.Exception
2+
{
3+
public class NotFoundException : ApiException
4+
{
5+
public NotFoundException(int responseCode, string message) : base(responseCode, message)
6+
{
7+
}
8+
}
9+
}

0 commit comments

Comments
 (0)