• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rwjdk / TrelloDotNet / 5778070402

pending completion
5778070402

push

github

web-flow
Update README.md

824 of 1465 branches covered (56.25%)

Branch coverage included in aggregate %.

2084 of 2485 relevant lines covered (83.86%)

67.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.54
/TrelloDotNet/TrelloDotNet/Control/ApiRequestController.cs
1
using System;
2
using System.IO;
3
using System.Net;
4
using System.Net.Http;
5
using System.Net.Http.Headers;
6
using System.Text;
7
using System.Text.Json;
8
using System.Threading;
9
using System.Threading.Tasks;
10
using TrelloDotNet.Model;
11

12
namespace TrelloDotNet.Control
13
{
14
    internal class ApiRequestController
15
    {
16
        private const string BaseUrl = "https://api.trello.com/1/";
17
        private readonly HttpClient _httpClient;
18
        private readonly string _apiKey;
19
        private readonly string _token;
20
        private readonly TrelloClient _client;
21

22
        internal ApiRequestController(HttpClient httpClient, string apiKey, string token, TrelloClient client)
183✔
23
        {
24
            _httpClient = httpClient;
183✔
25
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
183✔
26
            _apiKey = apiKey;
183✔
27
            _token = token;
183✔
28
            _client = client;
183✔
29
        }
183✔
30

31
        public string Token => _token;
21✔
32

33
        internal async Task<T> Get<T>(string suffix, CancellationToken cancellationToken, params QueryParameter[] parameters)
34
        {
35
            string json = await Get(suffix, cancellationToken, 0, parameters);
301✔
36
            var @object = JsonSerializer.Deserialize<T>(json);
301✔
37
            return @object;
301✔
38
        }
301✔
39

40
        internal async Task<string> Get(string suffix, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
41
        {
42
            var uri = BuildUri(suffix, parameters);
371✔
43
            var response = await _httpClient.GetAsync(uri, cancellationToken);
371✔
44
            var responseContent = await response.Content.ReadAsStringAsync();
371✔
45
            if (response.StatusCode != HttpStatusCode.OK)
371✔
46
            {
47
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => Get(suffix, cancellationToken, retry, parameters), retryCount, cancellationToken);
134✔
48
            }
49
            return responseContent; //Content is assumed JSON
302✔
50
        }
367✔
51

52
        internal async Task<T> Post<T>(string suffix, CancellationToken cancellationToken, params QueryParameter[] parameters)
53
        {
54
            string json = await Post(suffix, cancellationToken, 0, parameters);
240✔
55
            var @object = JsonSerializer.Deserialize<T>(json);
240✔
56
            return @object;
240✔
57
        }
240✔
58

59
        internal async Task<T> PostWithAttachmentFileUpload<T>(string suffix, AttachmentFileUpload attachmentFile, CancellationToken cancellationToken, params QueryParameter[] parameters)
60
        {
61
            string json = await PostWithAttachmentFileUpload(suffix, attachmentFile, cancellationToken, 0, parameters);
2✔
62
            var @object = JsonSerializer.Deserialize<T>(json);
1✔
63
            return @object;
1✔
64
        }
1✔
65

66
        internal async Task<string> PostWithAttachmentFileUpload(string suffix, AttachmentFileUpload attachmentFile, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
67
        {
68
            var uri = BuildUri(suffix, parameters);
6✔
69
            using (var multipartFormContent = new MultipartFormDataContent())
6✔
70
            {
71
                multipartFormContent.Add(new StreamContent(attachmentFile.Stream), name: @"file", fileName: attachmentFile.Filename);
6✔
72
                var response = await _httpClient.PostAsync(uri, multipartFormContent, cancellationToken);
6✔
73
                var responseContent = await response.Content.ReadAsStringAsync();
6✔
74
                if (response.StatusCode != HttpStatusCode.OK)
6✔
75
                {
76
                    return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => PostWithAttachmentFileUpload(suffix, attachmentFile, cancellationToken, retry, parameters), retryCount, cancellationToken);
9✔
77
                }
78
                return responseContent; //Content is assumed JSON
1✔
79
            }
80
        }
1✔
81

82
        internal async Task<string> Post(string suffix, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
83
        {
84
            var uri = BuildUri(suffix, parameters);
268✔
85
            var response = await _httpClient.PostAsync(uri, null, cancellationToken);
268✔
86
            var content = await response.Content.ReadAsStringAsync();
268✔
87
            if (response.StatusCode != HttpStatusCode.OK)
268✔
88
            {
89
                return await PreformRetryIfNeededOrThrow(uri, content, retry => Post(suffix, cancellationToken, retry, parameters), retryCount, cancellationToken);
51✔
90
            }
91
            return content; //Content is assumed JSON
242✔
92
        }
267✔
93

94
        internal async Task<T> Put<T>(string suffix, CancellationToken cancellationToken, params QueryParameter[] parameters)
95
        {
96
            string json = await Put(suffix, cancellationToken, 0, parameters);
36✔
97
            var @object = JsonSerializer.Deserialize<T>(json);
36✔
98
            return @object;
36✔
99
        }
36✔
100

101
        internal async Task<string> Put(string suffix, CancellationToken cancellationToken, int retryCount, params QueryParameter[] parameters)
102
        {
103
            var uri = BuildUri(suffix, parameters);
49✔
104
            var response = await _httpClient.PutAsync(uri, null, cancellationToken);
49✔
105
            var responseContent = await response.Content.ReadAsStringAsync();
49✔
106
            if (response.StatusCode != HttpStatusCode.OK)
49✔
107
            {
108
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => Put(suffix, cancellationToken, retry, parameters), retryCount, cancellationToken);
17✔
109
            }
110
            return responseContent; //Content is assumed JSON
40✔
111
        }
48✔
112

113
        internal async Task<T> PutWithJsonPayload<T>(string suffix, CancellationToken cancellationToken, string payload, params QueryParameter[] parameters)
114
        {
115
            string json = await PutWithJsonPayload(suffix, cancellationToken, payload, 0, parameters);
38✔
116
            var @object = JsonSerializer.Deserialize<T>(json);
38✔
117
            return @object;
38✔
118
        }
38✔
119

120
        internal async Task<string> PutWithJsonPayload(string suffix, CancellationToken cancellationToken, string payload, int retryCount, params QueryParameter[] parameters)
121
        {
122
            var uri = BuildUri(suffix, parameters);
39✔
123
            var response = await _httpClient.PutAsync(uri, new StringContent(payload, Encoding.UTF8, "application/json"), cancellationToken);
39✔
124
            var responseContent = await response.Content.ReadAsStringAsync();
39✔
125
            if (response.StatusCode != HttpStatusCode.OK)
39!
126
            {
127
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => PutWithJsonPayload(suffix, cancellationToken, payload, retry, parameters), retryCount, cancellationToken);
×
128
            }
129
            return responseContent; //Content is assumed JSON
39✔
130
        }
39✔
131

132
        private string FormatExceptionUrlAccordingToClientOptions(string fullUrl)
133
        {
134
            switch (_client.Options.ApiCallExceptionOption)
8!
135
            {
136
                case ApiCallExceptionOption.IncludeUrlAndCredentials:
137
                    return fullUrl;
1✔
138
                case ApiCallExceptionOption.IncludeUrlButMaskCredentials:
139
                    // ReSharper disable StringLiteralTypo
140
                    return fullUrl.Replace($"?key={_apiKey}&token={_token}", "?key=XXXXX&token=XXXXXXXXXX");
6✔
141
                case ApiCallExceptionOption.DoNotIncludeTheUrl:
142
                    return string.Empty.PadLeft(5, 'X');
1✔
143
                default:
144
                    throw new ArgumentOutOfRangeException();
×
145
            }
146
        }
147

148
        private static StringBuilder GetParametersAsString(QueryParameter[] parameters)
149
        {
150
            StringBuilder parameterString = new StringBuilder();
804✔
151
            foreach (var parameter in parameters)
6,396✔
152
            {
153
                parameterString.Append($"&{parameter.Name}={parameter.GetValueAsApiFormattedString()}");
2,394✔
154
            }
155

156
            return parameterString;
804✔
157
        }
158

159
        private Uri BuildUri(string suffix, params QueryParameter[] parameters)
160
        {
161
            return new Uri($@"{BaseUrl}{suffix}?key={_apiKey}&token={_token}" + GetParametersAsString(parameters));
804!
162
        }
163

164
        internal async Task<string> Delete(string suffix, CancellationToken cancellationToken, int retryCount)
165
        {
166
            var uri = BuildUri(suffix);
71✔
167
            var response = await _httpClient.DeleteAsync(uri, cancellationToken);
71✔
168
            var responseContent = await response.Content.ReadAsStringAsync();
71✔
169
            if (response.StatusCode != HttpStatusCode.OK)
71✔
170
            {
171
                return await PreformRetryIfNeededOrThrow(uri, responseContent, retry => Delete(suffix, cancellationToken, retry), retryCount, cancellationToken);
47✔
172
            }
173
            return null;
47✔
174
        }
70✔
175

176
        private async Task<string> PreformRetryIfNeededOrThrow(Uri uri, string responseContent, Func<int,Task<string>> toRetry, int retryCount, CancellationToken cancellationToken)
177
        {
178
            if (responseContent.Contains("API_TOKEN_LIMIT_EXCEEDED") && retryCount <= _client.Options.MaxRetryCountForTokenLimitExceeded)
133✔
179
            {
180
                await Task.Delay(TimeSpan.FromSeconds(_client.Options.DelayInSecondsToWaitInTokenLimitExceededRetry), cancellationToken);
125✔
181
                retryCount++;
125✔
182
                return await toRetry(retryCount);
125✔
183
            }
184
            throw new TrelloApiException(responseContent, FormatExceptionUrlAccordingToClientOptions(uri.AbsoluteUri)); //Content is assumed Error Message       
8✔
185
        }
121✔
186
    }
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc