Middleware Plugins in RiotBlossom

RiotBlossom uses pluggable middleware as part of the HTTP request-response cycle. Creating a middleware plugin requires implementing from any of the following interfaces:

  • IRequestMiddleware
  • IResponseMiddleware
  • IRetryMiddleware

As part of the HTTP request-response lifecycle:

  • Before the request is sent (request information goes through request middleware IRequestMiddleware[])
  • On request (request function reference is passed to single retry middleware IRetryMiddleware)
  • After the response is received (response information goes through response middleware IResponseMiddleware[])

Knowing this lifecycle, MiddlewareStack is the system composition of IRequestMiddleware[], IRetryMiddleware, and IResponseMiddleware[]. A middleware stack is encapsulated to the APIs it is assigned to.

RiotBlossom client builder currently does the following:

  • AddRiotMiddlewareStack - the Riot middleware stack for Riot APIs
  • AddDataMiddlewareStack - the Data middleware stack for CommunityDragon and DataDragon APIs

Each request processed under the Riot MiddlewareStack is asynchronously locked per routing value to maintain data synchronization.

Having separate middleware systems offers more user configuration and flexibility in doing thingies. As an example, Riot MiddlewareStack is created with an AlgorithmicLimiter whereas Data `MiddlewareStack`` does not.

Hopefully, the system design was straightforward to understand...

anime-cirno

if I had lost you, I am very sorry...

Request interface

public interface IRequestMiddleware
{
    Task UseRequestAsync(ExecuteInfo info, HttpRequestMessage req, Action next, Action<byte[]> hit);
}
  • info, routing information of request
  • req, the raw HTTP request message
  • next, action to invoke for continuing to the next request middleware. Not invoking will end the request middleware chain.
  • hit, action to invoke for sending cached data

Example plugins:

  • AlgorithmicLimiter
  • InMemoryCache

Response interface

public interface IResponseMiddleware
{
    Task UseResponseAsync(ExecuteInfo info, HttpResponseMessage res, Action next);
}
  • info, routing information of request
  • res, the raw HTTP response message
  • next, action to invoke for continuing to the next response middleware. Not invoking will end the response middleware chain.

Example plugins:

  • AlgorithmicLimiter
  • InMemoryCache

Retry interface

public interface IRetryMiddleware
{
    Task<HttpResponseMessage> UseRetryAsync(Func<Task<HttpResponseMessage>> resFunc);
}
  • resFunc, function to invoke for receiving an HTTP response

Example plugins:

  • Retryer

Out-of-the-box Middleware Plugins

AlgorithmicLimiter

AlgorithmicLimiter limiter = new(new()
{
    CanThrowOn429 = true,
    CanThrowOnLimit = true,
    ShaperType = LimiterShaper.Burst
});

More documentation can be found in the AlgorithmicLimiter class.

InMemoryCache

InMemoryCache riotCache = new("rb-riot-cache");
InMemoryCache dataCache = new("rb-data-cache")
{
    Expiration = TimeSpan.FromHours(24),
    Size = 10000
};

More documentation can be found in the InMemoryCache class.

Retryer

Retryer retryer = new()
{
    CanThrowOn429 = true,
    RetryCount = 10,
    RetryDelay = TimeSpan.FromSeconds(10d)
};

More documentation can be found in the Retryer class.