Introduction
👋 Welcome to Flux - a nuget package that simplifies interactions with external services.
What is Flux?
Flux is an abstraction between your application and external services. It allows you to interact with external services in a simple and consistent way.
The goal
The goal of Flux is to remove the necessity of worrying about the implementation details of external services and to allow you to focus on your application's logic.
The Main Principle
The main principle behind the development of Flux is the Dependency Inversion Principle. We believe that your application logic should not depend on the implementation details of external services, but rather on abstractions.
What is Flux designed to be
-
Easy to use - Flux provides a simple and intuitive API for interacting with external services.
-
Configurable - Flux is highly configurable and can be easily adapted to your needs.
-
Extendable - Flux is built with extensibility in mind. You can easily add your own implementations of Flux's core components.
-
Testable - Flux is built with testability in mind. You can easily mock Flux's components to test your applications.
Configure Flux
In this documentation we will review the general installation, configuration and usage, regardless of which implementatin you choose. Refer to your implementation of choice for more information on how to use it.
Installation
Install your implementation package of choice.
Configure Flux
To configure Flux, you need to add it to your DI container. You can do this by calling the AddFlux
extension method on your IServiceCollection
instance.
services.AddFlux(flux =>
{
// Configure Flux here
});
When configuring Flux, first you need to add your external services and give each one a unique name. You can add and configure external services by calling the AddService
method:
services.AddFlux(flux =>
{
flux.AddService("service1")
// Configure service1 here
flux.AddService("service2")
// Configure service2 here
});
Example external service configuration
services.AddFlux(flux =>
{
flux.AddService("service1")
.UsingRest("https://test.com")
.AddSet<Book>()
.WithEndpoint("books");
});
This example uses Flux.REST.
Refer to your implementation of choice for more information on how to configure your external services.
Use Flux
Use IFluxContext in your app
To use Flux in your application, you need to resolve the IFluxContext
from your DI container. Normally, this is done by injecting it into your class's constructor.
public class YourClass
{
private readonly IFluxContext _fluxContext;
public YourClass(IFluxContext fluxContext)
{
_fluxContext = fluxContext;
}
}
You can also retrieve it from the IServiceProvider
instance.
var fluxContext = serviceProvider.GetRequiredService<IFluxContext>();
Once you have the IFluxContext
instance, you can use it to interact with your external services.
Working with a specific external service
If you have multiple external services configured, you can specify which one you want to use by calling the Service
method on the IFluxContext
instance.
var externalService1 = _fluxContext.Service("service1");
Understanding Sets
Flux uses a concept of Sets to represent an external collection of data of a specific type. For external WebApis, this is usually a collection of models that you can retrieve using the same endpoint.
Let's say the external WebAPI uses REST and looks something like this:
GET https://test.com/students // returns either all students, or a page of students
POST https://test.com/students // creates a new student
GET https://test.com/students/1 // returns a student with id 1
PUT https://test.com/students/1 // updates a student with id 1
DELETE https://test.com/students/1 // deletes a student with id 1
In Flux, this collection of endpoints will be represented by a Set registered for type Student
. You can retrieve this Set's context by calling the Set
method on the IFluxContext
instance.
// resolve the Set directly
var studentSet = _fluxContext.Set<Student>();
// Or explicitly specify the external service you are working with
var studentSet = _fluxContext.Service("service1").Set<Student>();
ℹ️ Selecting a specific service can be useful in situations where you have multiple external services configured with the same model types.
Using external services
Once you have retrieved the Set's context, you can use it to interact with the external service.
var studentSet = _fluxContext.Set<Student>();
var student = await studentSet.GetAsync(1); // Will make an http request to https://test.com/students/1
var list = await studentSet.GetAllAsync(); // Will make an http request to https://test.com/students
var page = await studentSet.GetPageAsync(0, 10); // Will make an http request to https://test.com/students?offset=0&limit=10
Working with multiple Sets of the same type
You can configure multiple Sets for the same model type simultaneously. This can be useful if you need to work with the same model type, but with different endpoints.
For example, if you have a WebApi that exposes a collection of books, but you need to work with two different endpoints for this collection, you can configure two Sets for the same model type:
flux.AddService("service1")
.UsingRest("https://test.com")
.AddSet<Book>("books1")
.WithEndpoint("books")
.AddSet<Book>("books2")
.WithEndpoint("additional-endpoint-for-books");
You can then retrieve the Set's context by specifying the name of the Set you want to be working with.
// resolve external service implicitly:
var books1Set = _fluxContext.Set<Book>("books1");
var books2Set = _fluxContext.Set<Book>("books2");
// or explicitly specify the external service:
var books1Set = _fluxContext.Service("service1").Set<Book>("books1");
var books2Set = _fluxContext.Service("service1").Set<Book>("books2");
Flux Implementations:
Refer to your implementation of choice:
Introduction
Flux.REST is a REST client implementation for the Flux package.
We recommend reviewing the Flux documentation first.
Installation
To use a REST client in your project, add the nuget package (currently in prerelease state)
dotnet add package BitzArt.Flux.REST --prerelease
Usage
Configure Flux
services.AddFlux(flux =>
{
flux.AddService("service1") // Give your external service a specific name
.UsingRest("https://test.com") // External service's base url
.AddSet<YourModel>() // Adds a Set for a specific model
.WithEndpoint("model"); // Set endpoint : https://test.com/model
});
Refer to the Configuring Endpoints section for more information on configuring endpoints for your external APIs.
Use IFluxContext in your app
- Resolve
IFluxContext
from your DI container
serviceProvider.GetRequiredService<IFluxContext>();
- Get your set context
// Resolve the Set directly
var setContext = fluxContext.Set<YourModel>();
// Or specify the external service
var setContext = fluxContext.Service("service1").Set<YourModel>();
ℹ️ Selecting a specific service can be useful in situations where you have multiple external services configured with the same model types.
- Use the SetContext to interact with this Set:
var model = await setContext.GetAsync(1); // Will make an http request to https://test.com/model/1
var list = await setContext.GetAllAsync(); // Will make an http request to https://test.com/model
var page = await setContext.GetPageAsync(0, 10); // Will make an http request to https://test.com/model?offset=0&limit=10
Refer to the Pagination section for more information on using and customizing pagination.
Configuring endpoints
You can provide detailed configuration for your endpoints:
services.AddFlux(flux =>
{
flux.AddService("service1")
.UsingRest("https://test.com")
.AddSet<Author>()
// Configure this Set
.AddSet<Book>()
// Configure this Set
});
Methods
WithEndpoint
Configures the REST endpoint, e.g. https://test.com/your-set-endpoint
WithEndpoint("your-set-endpoint")
WithIdEndpoint
Configures the ID endpoint, e.g. https://test.com/something/1
WithIdEndpoint((key) => $"something/{key}")
WithPageEndpoint
Configures the Page endpoint, e.g. https://test.com/your-page-endpoint
WithPageEndpoint("your-page-endpoint")
More methods are expected to be added in the future.
Custom Variables
You can add custom variables to your endpoint configurations:
services.AddFlux(flux =>
{
flux.AddService("service1")
.UsingRest("https://test.com")
.AddSet<YourModel>()
.WithEndpoint("{a}/{b}");
});
Provide variable values when calling an appropriate method:
var a = "first";
var b = "second";
var result = await setContext.GetAsync(1, a, b); // Will make an http request to https://test.com/first/second/1
Custom Page endpoint with parent id example:
Flux configuration:
services.AddFlux(flux =>
{
flux.AddService("service1")
.UsingRest("https://test.com")
.AddSet<Book>()
.WithPageEndpoint("authors/{authorId}/books");
});
Usage:
var books = fluxContext.Set<Book>();
var offset = 0;
var limit = 10;
var authorId = 15;
var booksPage = await books.GetPage(offset, limit, authorId); // https://test.com/authors/15/books?offset=0&limit=10
Pagination
todo
Introduction
Flux.JSON is an implementation of Flux that uses JSON as a data source.
It's intended to be used for testing purposes, as it allows you to quickly mock external services by simply providing JSON data as a source, whether as a simple .Net string or a JSON file.
We recommend reviewing the Flux documentation first.
Installation
To use Flux.JSON in your project, add the nuget package (currently in prerelease state)
dotnet add package BitzArt.Flux.Json --prerelease
Usage
Configure Flux
You can populate Flux sets data from JSON strings:
var myJson =
"""
[
{
"id": 1,
"name": "Test object 1"
},
{
"id": 2,
"name": "Test object 2"
}
]
""";
services.AddFlux(flux =>
{
flux.AddService("service1") // Give your external service a specific name
.UsingJson() // Use Flux.JSON implementation
.AddSet<YourModel>() // Adds a Set for a specific model
.FromJson(myJson); // Set data source
});
Or from a JSON file:
var filePath = "path/to/my/file.json";
services.AddFlux(flux =>
{
flux.AddService("service1") // Give your external service a specific name
.UsingJson() // Use Flux.JSON implementation
.AddSet<YourModel>() // Adds a Set for a specific model
.FromJsonFile(filePath); // Set data source
});
Use IFluxContext in your app
You can then use Flux normally, as described in the general Flux documentation.