An almost 2x times faster fluent HTTP request service, build to simplify the communication with JSON endpoints, by automatically handling serialization / deserialization. Authenticated requests towards protected by IdentityServer4 resources are done in a simple compact way.
services.AddHttpClientService();
//Or if the resources are behind an IdentityServer4
services.AddHttpClientService(
.Configure<ClientCredentialsOptions>(Configuration.GetSection(nameof(ClientCredentialsOptions)));
var responseObject = await _requestServiceFactory
//Create a instance of the service
.CreateHttpClientService()
//GET and deserialize the response body to IEnumerable<Customers>
.GetAsync<IEnumerable<Customers>>("https://api/customers");
Check the Getting started guide for more details!
- Getting started
- How to setup an Access Token Request
- More info on how to serialize request, deserialize response
- Configuring the colleration id
- Contributing
Getting started with Geko.HttpClientService
is rather easy, since you only need three things:
- Install the nuget package Geko.HttpClientService
- Optionally, provide the options to request an access token from an IdentityServer4 service in the
appsettings.json
- Register the service in
Startup.cs
Install the Geko.HttpClientService nuget package, using any of your favorite ways.
Add the IdentityServer4 Access Token Request Options to your appsettings.json
(the configuration section should always be or end with ClientCredentialsOptions
):
"ClientCredentialsOptions": {
"Address": "https://demo.identityserver.io/connect/token",
"ClientId": "m2m",
"ClientSecret": "secret",
"Scope": "api"
}
// The values above are part of the demo offered in https://demo.identityserver.io/
Register the service In StartUp.cs
in ConfigureServices(IServiceCollection services)
:
services.AddHttpClientService()
//Optional, set it if you have ClientCredentialsOptions or PasswordOptions
.Configure<ClientCredentialsOptions>(Configuration.GetSection(nameof(ClientCredentialsOptions)));
Request the IHttpClientServiceFactory
wherever you want to make the authenticated requests:
using Geko.HttpClientService.Extensions;
[ApiController]
[Route("customers")]
public class CustomerController : ControllerBase
{
//Request the IHttpClientServiceFactory instance in your controller or service
private readonly IHttpClientServiceFactory _requestServiceFactory;
public CustomerController(IHttpClientServiceFactory requestServiceFactory){
_requestServiceFactory = requestServiceFactory;
}
[HttpGet]
public async Task<IActionResult> Get(){
//Make the request
var responseObject = await _requestServiceFactory
//Create a instance of the service
.CreateHttpClientService()
//GET and deserialize the response body to IEnumerable<Customers>
.GetAsync<IEnumerable<Customers>>("https://api/customers");
//Do something with the results
if (!responseObject.HasError)
{
var customers = responseObject.BodyAsType;
return Ok(customers);
}
else
{
var httpStatusCode = responseObject.StatusCode;
var errorMessage = responseObject.Error;
return StatusCode((int)httpStatusCode, errorMessage);
}
}
}
Configuring the service from startup following the Options Pattern is the simpler way, but there are more ways HTTP verbs supported are: GET, POST, PUT, DELETE, PATCH and HEAD.
You can also take a look at the Documentation for technical details, check the features sample or a more complete one.
The library supports multiple ways for setting up the necessary options for retrieving an access token. Upon success of retrieving one, the result is cached until the token expires; that means that a new request to a protected resource does not necessarily means a new request for an access token.
Currently, the library only supports
ClientCredentialsTokenRequest
andPasswordTokenRequest
.
Setup IdentityServer options by passing a ClientCredentialsOptions
or PasswordOptions
directly to the SetIdentityServerOptions
:
//...
.SetIdentityServerOptions(
new PasswordOptions
{
Address = "https://demo.identityserver.io/connect/token",
ClientId = "ClientId",
ClientSecret = "ClientSecret",
Scope = "Scope",
Username = "Username",
Password = "Password"
}
)
//...
Setup IdentityServer options using the options pattern (read more about the options pattern in Microsoft Docs):
//...
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddHttpClientService()
.AddSingleton<IProtectedResourceService, ProtectedResourceService>()
.Configure<ClientCredentialsOptions>(Configuration.GetSection(nameof(ClientCredentialsOptions)));
//...
}
//...
//...
public class ProtectedResourceService : IProtectedResourceService
{
private readonly IHttpClientServiceFactory _requestServiceFactory;
private readonly IOptions<ClientCredentialsOptions> _identityServerOptions;
public ProtectedResourceService(IHttpClientServiceFactory requestServiceFactory, IOptions<ClientCredentialsOptions> identityServerOptions)
{
_requestServiceFactory = requestServiceFactory;
_identityServerOptions = identityServerOptions;
}
public async Task<YourObject> Get(){
_requestServiceFactory
.CreateHttpClientService()
.SetIdentityServerOptions(_identityServerOptions)
.GetAsync<YourObject>("https://url_that_returns_YourObject");
}
)
//...
Setup IdentityServer options using a delegate:
//...
.SetIdentityServerOptions<PasswordOptions>( x => {
x.Address = "https://demo.identityserver.io/connect/token";
x.ClientId = "ClientId";
x.ClientSecret = "ClientSecret";
x.Scope = "Scope";
x.Username = "Username";
x.Password = "Password";
}
)
//...
Responses can always be deserialized to the type TResponseBody
with GetAsync<TResponseBody>
:
//...
.GetAsync<ResponsePoco>("https://url_that_returns_ResponsePoco_in_json");
//...
Using a complex type as a request body for POST, PUT and PATCH requests is also very easy. In the example that follows the type TRequestBody
of the PostAsync<TRequestBody,TResponseBody>
sets the type of the requestPoco
object. This will be serialized using JsonConvert.SerializeObject(requestPoco, Formatting.None)
:
//...
.PostAsync<RequestPoco,ResponsePoco>("https://url_that_accepts_RequestPoco_and_responds_with_ResponsePoco", requestPoco);
//...
If you want to fine tune how the
requestPoco
object is sent, please use the TypeContent(TRequestBody, Encoding, string). Without usingTypeContent(...)
to explitily set media-type and encoding, the defaults will be used ('application/json' and 'UTF-8').
The variable responseObject contains multiple properties: from the entire HttpResponseMessage
and HttpRequestMessage
, to the HttpStatusCode
and HttpResponseHeaders
. The most exciting feature though, is the TResponseBody BodyAsType
property which will contain the deserializabled complex types from JSON responses. For a complete list of all the properties, check the ResponseObject<TResponseBody> in the docs.
You can also fine tune encoding and media-type by using the TypeContent(TRequestBody model, Encoding encoding, string mediaType)
like this:
var responseObject = await _requestServiceFactory
//Create a instance of the service
.CreateHttpClientService()
//.PostAsync<TRequestBody,TResponseBody>(URL, customer of type Customer1)
.PostAsync<TypeContent<Customer1>,ReturnedObject>("https://api/customers", new TypeContent(customer, Encoding.UTF8, "application/json"));
Starting from version 2.3, a colleration id can be used for logging between cascading API calls. It can be configured from appsettings using the options pattern:
"HttpClientServiceOptions": {
//Switches on or off the sychronization of the colleration id
"HeaderCollerationIdActive": true,
//Sets the name of the header
"HeaderCollerationName": "X-Request-ID"
},
//...
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddHttpClientService()
.Configure<HttpClientServiceOptions>(Configuration.GetSection(nameof(HttpClientServiceOptions)));
//...
}
//...
Feedback and contibution is more than welcome, as there are many more things to do!
Just as a sample:
- Expand the Geko.HttpClientService.CompleteSample with more functionality.
- Support
JsonSerializerSettings
forJsonConvert.DeserializeObject<TResponseBody>(apiResponse.BodyAsString)
in HttpClientService. - Support more than IdentityServer4
- Improve logging.
Opening a ticket is sufficient, but you can also try and reach out if you need any help