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:

  • Flux.REST - REST WebAPI client implementation
  • Flux.JSON - JSON data source implementation

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

  1. Resolve IFluxContext from your DI container
serviceProvider.GetRequiredService<IFluxContext>();
  1. 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.

  1. 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.