2 min read

Backend-For-Client

You can enable a Web API to become a Poq BFC by following the steps in this guideline.

Once enabled, the requests that have a controller and an action implemented in the BFC API will be handled. Poq platform requests that do not have a controller and an action are proxied to the configured platform URL (e.g. https://platform.poq.io). The requests that are neither handled nor Poq platform requests will return a "404 Not Found" response.

  1. Enabling and testing the BFC
  2. Examples
    1. Modifying an existing Poq Platform Response
    2. Creating a response
    3. Creating a response by composing data from multiple sources

Enabling and testing the BFC

  1. Install Poq.WebApi library by using the package manager.

    Install-Package Poq.WebApi
  2. Edit the Startup.cs to add the following lines:

    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Poq.WebApi.BackendForClient;
    internal class Startup
    {
    public void ConfigureServices(IServiceCollection services)
    {
    services.Configure<PoqPlatformConfiguration>("PoqPlatform", Configuration);
    services.AddPoqBackendForClientServices();
    services.AddHttpContextAccessor();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    // The order of these routing method calls are important
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
    endpoints.MapControllers();
    });
    app.UsePoqBackendForClientRouter("https://dev.poq.io");
    }
    }
  3. Add the following configuration:

    In appsettings.Development.json:

    "PoqPlatform": {
    "Url": "https://dev.poq.io"
    }

    In appsettings.Staging.json:

    "PoqPlatform": {
    "Url": "https://staging.poq.io"
    }

    In appsettings.Production.json:

    "PoqPlatform": {
    "Url": "https://poq.io"
    }
  4. Add the following Controller as an example customisation of an endpoint:

    using Microsoft.AspNetCore.Mvc;
    using Poq.Contract.Catalogue;
    using Poq.WebApi.BackendForClient;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    [Route("products")]
    [ApiController]
    public class ProductController : ControllerBase
    {
    private readonly IPoqPlatformAccess _poqPlatform;
    public ProductController(IPoqPlatformAccess poqPlatform)
    {
    _poqPlatform = poqPlatform;
    }
    [HttpGet]
    public async Task<ActionResult<IList<Product>>> Get()
    {
    var platformResult = await _poqPlatform.GetPlatformResponseAsync<List<Product>>();
    var products = await platformResult.ReadContentAsync();
    products?.ForEach(p => $"Customised - {p.Details.Name}");
    return products ?? new List<Product>();
    }
    }
  5. Run the project and test it using the following cURL request:

    curl --location --request GET 'https://{domain}/products?ids=<product id>' \
    --header 'Poq-App-Identifier: <app identifier>' \
    --header 'Poq-Currency-Identifier: GBP'

Examples

Modifying an existing Poq Platform Response

You may get a response from the Poq Platform and modify it before returning to the app.

To implement such customisation, you may use the IPoqPlatformAccess class as shown below.

private readonly IPoqPlatformAccess _poqPlatform;
public ProductController(IPoqPlatformAccess poqPlatform)
{
_poqPlatform = poqPlatform;
}
[HttpGet]
public async Task<ActionResult<IList<Product>>> Get()
{
var platformResult = await _poqPlatform.GetPlatformResponseAsync<List<Product>>();
var products = await platformResult.ReadContentAsync();
products = Customise(products); // Modify Poq Platform data before returning to the app
return products;
}

Creating a response

You may also choose to create a response without using Poq Platfom data as shown below:

[HttpGet]
public async Task<ActionResult<IList<Product>>> Get()
{
return new List<Product>
{
new Product(...); // Create a new product
};
}

This is useful when the data to fulfill the request is completely provided by an external system.

Creating a response by composing data from multiple sources

You may use the Poq Platform Clients provided in the SDK to query Poq Platform.

Below is an example of collecting data from various sources to compose a response.

The example is to customise a wishlist request. User's wishlist is returned from the Poq Platform.

Poq platform is also queried for a promotional product. The product price is updated from an external source. The product is associated to the wishlist response as custom data.

private readonly IPoqPlatformAccess _poqPlatform;
private readonly IProductClient _productClient;
public ProductController(
IPoqPlatformAccess poqPlatform,
IProductClient productClient,
IExternalPriceProvider priceProvider)
{
_poqPlatform = poqPlatform;
_productClient = productClient;
_priceProvider = priceProvider;
}
[HttpGet]
public async Task<ActionResult<UserWishlist>> Get()
{
var wishlistResponse = await _poqPlatform.GetPlatformResponseAsync<UserWishlist>();
var wishlist = await wishlistResponse.ReadContentAsync();
var productResponse = await _productClient.GetByIdAsync("<product id>", "<app identifier>", "<currency identifier>");
var product = productResponse.Content;
var price = await _priceProvider.GetPrice(product.Id);
product.Variants["<variant id>"].Prices["<currency code>"].Now = price;
wishlist.CustomData["PromotionalProduct"] = product;
return wishlist;
}

Reverse proxying a Non-Platform Endpoint

If the app is customised to make a non-platform request that an existing API can handle, you could configure the BFC to reverse-proxy this request to the current endpoint. This method can be beneficial while migrating an existing app to a BFC API.

Let's say you have a custom endpoint that handles login requests. Once migrated, the app will start sending these requests to the BFC. You may choose to migrate the implementation to the BFC or you may reverse-proxy this request to the existing API as shown in the following example:

internal class Startup
{
public void Configure()
{
// This is after the standard configuration code:
app.UsePoqBackendForClientRouter("https://platform.poq.io", new[]
{
new ReverseProxyDefinition(HttpMethod.Post, "account/login", "https://my-custom-account-api.azurewebsites.net"),
};
}
}