Skip to content

Commit 58ce899

Browse files
authored
Add Api helper methods for POST requests (#9134)
* Add Api helper methods for POST requests * Support json serializer setting for json requests * Minor changes and cleanup * Make ApiConnection disposable
1 parent ead8335 commit 58ce899

File tree

5 files changed

+118
-3
lines changed

5 files changed

+118
-3
lines changed

Api/Api.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,30 @@ public RestResponse AddProjectFile(int projectId, string name, string content)
207207
return result;
208208
}
209209

210+
/// <summary>
211+
/// Makes a simple POST request to the specified endpoint with the given payload
212+
/// </summary>
213+
protected bool TryPost<T>(string endpoint, IEnumerable<KeyValuePair<string, string>> payload, out T result,
214+
ApiConnection apiConnection = null, TimeSpan? timeout = null)
215+
where T : RestResponse
216+
{
217+
using var request = ApiUtils.CreatePostRequest(endpoint, payload);
218+
219+
return (apiConnection ?? ApiConnection).TryRequest(request, out result, timeout);
220+
}
221+
222+
/// <summary>
223+
/// Makes a simple POST request to the specified endpoint with the given payload
224+
/// </summary>
225+
protected bool TryJsonPost<T>(string endpoint, object payload, out T result,
226+
ApiConnection apiConnection = null, JsonSerializerSettings jsonSerializerSettings = null, TimeSpan? timeout = null)
227+
where T : RestResponse
228+
{
229+
using var request = ApiUtils.CreateJsonPostRequest(endpoint, payload, jsonSerializerSettings);
230+
231+
return (apiConnection ?? ApiConnection).TryRequest(request, out result, timeout);
232+
}
233+
210234

211235
/// <summary>
212236
/// Update the name of a file
@@ -1487,6 +1511,7 @@ public virtual void Dispose()
14871511
}
14881512
}
14891513
_clientPool.DisposeSafely();
1514+
ApiConnection?.DisposeSafely();
14901515
}
14911516

14921517
/// <summary>

Api/ApiConnection.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace QuantConnect.Api
3030
/// <summary>
3131
/// API Connection and Hash Manager
3232
/// </summary>
33-
public class ApiConnection
33+
public class ApiConnection : IDisposable
3434
{
3535
/// <summary>
3636
/// Authorized client to use for requests.
@@ -118,6 +118,14 @@ public void SetClient(string baseUrl, Dictionary<string, string> defaultHeaders
118118
}
119119
}
120120

121+
/// <summary>
122+
/// Disposes of the HTTP client
123+
/// </summary>
124+
public void Dispose()
125+
{
126+
_httpClient.Dispose();
127+
}
128+
121129
/// <summary>
122130
/// Place a secure request and get back an object of type T.
123131
/// </summary>

Api/ApiUtils.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3+
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at 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+
16+
using System.Net.Http;
17+
using System.Collections.Generic;
18+
using Newtonsoft.Json;
19+
using System.Net.Http.Headers;
20+
using System.Net.Mime;
21+
22+
namespace QuantConnect.Api
23+
{
24+
/// <summary>
25+
/// API utility methods
26+
/// </summary>
27+
public static class ApiUtils
28+
{
29+
/// <summary>
30+
/// Creates a POST <see cref="HttpRequestMessage"/> with the specified endpoint and payload as form url encoded content.
31+
/// </summary>
32+
/// <param name="endpoint">The request endpoint</param>
33+
/// <param name="payload">The request payload</param>
34+
/// <returns>The POST request</returns>
35+
public static HttpRequestMessage CreatePostRequest(string endpoint, IEnumerable<KeyValuePair<string, string>> payload = null)
36+
{
37+
var request = new HttpRequestMessage(HttpMethod.Post, endpoint);
38+
if (payload != null)
39+
{
40+
request.Content = new FormUrlEncodedContent(payload);
41+
}
42+
43+
return request;
44+
}
45+
46+
/// <summary>
47+
/// Creates a POST <see cref="HttpRequestMessage"/> with the specified endpoint and payload as json body
48+
/// </summary>
49+
/// <param name="endpoint">The request endpoint</param>
50+
/// <param name="payload">The request payload</param>
51+
/// <param name="jsonSerializerSettings">Settings for the json serializer</param>
52+
/// <returns>The POST request</returns>
53+
public static HttpRequestMessage CreateJsonPostRequest(string endpoint, object payload = null, JsonSerializerSettings jsonSerializerSettings = null)
54+
{
55+
var request = new HttpRequestMessage(HttpMethod.Post, endpoint);
56+
if (payload != null)
57+
{
58+
request.Content = new StringContent(JsonConvert.SerializeObject(payload, jsonSerializerSettings),
59+
new MediaTypeHeaderValue(MediaTypeNames.Application.Json));
60+
}
61+
62+
return request;
63+
}
64+
}
65+
}

Brokerages/Authentication/OAuthTokenHandler.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using RestSharp;
1818
using QuantConnect.Api;
1919
using System.Threading;
20+
using QuantConnect.Util;
2021

2122
namespace QuantConnect.Brokerages.Authentication
2223
{
@@ -50,6 +51,8 @@ public sealed class OAuthTokenHandler<TRequest, TResponse> : TokenHandler
5051
/// </summary>
5152
private TokenCredentials _tokenCredentials;
5253

54+
private bool _disposed;
55+
5356
/// <summary>
5457
/// Initializes a new instance of the <see cref="OAuthTokenHandler{TRequest, TResponse}"/> class.
5558
/// </summary>
@@ -96,5 +99,19 @@ public override TokenCredentials GetAccessToken(CancellationToken cancellationTo
9699
throw new InvalidOperationException($"{nameof(OAuthTokenHandler<TRequest, TResponse>)}.{nameof(GetAccessToken)}: {ex.Message}");
97100
}
98101
}
102+
103+
/// <summary>
104+
/// Disposes of resources
105+
/// </summary>
106+
protected override void Dispose(bool disposing)
107+
{
108+
if (disposing && !_disposed)
109+
{
110+
_disposed = true;
111+
_apiClient?.DisposeSafely();
112+
}
113+
114+
base.Dispose(disposing);
115+
}
99116
}
100117
}

Tests/Api/ApiTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class ApiTest : ApiTestBase
3434
[Test, Explicit("Requires configured api access")]
3535
public void ApiConnectionWillAuthenticate_ValidCredentials_Successfully()
3636
{
37-
var connection = new ApiConnection(TestAccount, TestToken);
37+
using var connection = new ApiConnection(TestAccount, TestToken);
3838
Assert.IsTrue(connection.Connected);
3939
}
4040

@@ -55,7 +55,7 @@ public void ApiWillAuthenticate_ValidCredentials_Successfully()
5555
[Test]
5656
public void ApiConnectionWillAuthenticate_InvalidCredentials_Unsuccessfully()
5757
{
58-
var connection = new ApiConnection(TestAccount, "");
58+
using var connection = new ApiConnection(TestAccount, "");
5959
Assert.IsFalse(connection.Connected);
6060
}
6161

0 commit comments

Comments
 (0)