简体   繁体   English

顺序调用多个api的设计模式

[英]design pattern for calling multiple api in sequence

I am doing an integration with payment service.我正在与支付服务进行整合。 And I have to onboard a merchant.我必须加入一个商人。 For onboarding a merchant I need to follow bellow steps对于入职商家,我需要遵循以下步骤

  1. Create a user on payment service, if successfully created: POST api call在支付服务上创建用户,如果创建成功:POST api call
  2. Create a business profile of the user created in previous step: POST api call创建在上一步中创建的用户的业务配置文件:POST api 调用
  3. Create a payment profile for the user: POST api call为用户创建付款资料:POST api 电话
  4. register a callback url for receiving webhook for transaction status change for payments for that user: POST api call注册回调 url 以接收该用户付款的交易状态更改的 webhook:POST api 调用

If any step fails, I need to retry from that step only.如果任何步骤失败,我只需要从该步骤重试。 I can not start from starting.我无法从头开始。

My Solution:我的解决方案:

I am maintaining a state object for onboarding of the user.我正在维护一个 state object 用于用户的入职。 state object has 4 fields state object 有 4 个字段

  • userCreated用户创建
  • businessProfileCreated businessProfile已创建
  • paymentProfileCreated付款资料已创建
  • webhookRegistered webhook已注册

with each step I am setting respective state attribute as true and saving it.在每一步中,我都将相应的 state 属性设置为 true 并保存。

Algotithm:算法:

Initialise state object all初始化 state object all

state.userCreated = false;
state.businessProfileCreated = false;
state.paymentProfileCreated = false;
state.webhookRegistered = false;`
if(state.userCreated != true)
    create user
if create profile **not** success
    save state 
    return
state.userCreated = true

if(state.businessProfileCreated != true)
    create business profile
if businessProfile creation  **not** success
    save state
    return
state.businessProfileCreated = true

if(state.paymentProfileCreated != true create payment profile if payment Profile creation not success save state return state.paymentProfileCreated if(state.paymentProfileCreated != true 创建支付配置文件如果支付配置文件创建不成功保存 state 返回 state.paymentProfileCreated

if(state.webhookRegistered:= true) :create webhook profile save state return if(state.webhookRegistered:= true) : 创建 webhook 配置文件保存 state 返回

state.paymentProfileCreated save state `` state.paymentProfileCreated 保存 state``

I need a clean way of doing this that also handle api failure.我需要一种干净的方法来处理 api 故障。 Is there any pattern exists for this task此任务是否存在任何模式

Maybe others have better ideas, but what comes to my mind is a modified version of the Strategy Pattern.也许其他人有更好的想法,但我想到的是 Strategy Pattern 的修改版本。 (See https://en.wikipedia.org/wiki/Strategy_pattern ) (参见https://en.wikipedia.org/wiki/Strategy_pattern

To implement this, you would need a list of functions to execute, (the strategy,) and you would write some code which walks through the list, invokes the function, checks the result, and keeps track of where the error occurred, by storing the index of the function that failed instead of jockeying a bunch of boolean flags.要实现这一点,您需要一个要执行的函数列表(策略),您将编写一些代码来遍历该列表、调用 function、检查结果并跟踪错误发生的位置,方法是存储function 的索引失败了,而不是操纵一堆 boolean 标志。

Your problem, if you decide to use this pattern, is that different functions may need different parameters, and to complicate things even more, some function may depend on some result returned by a previously invoked function. To solve this, you will have to store all of the information that these functions might need into a separate object and pass that object to each one of the functions, so that they can read fields from that object and write fields to it as they need.如果您决定使用此模式,您的问题是不同的函数可能需要不同的参数,并且使事情变得更加复杂,一些 function 可能取决于先前调用的 function 返回的某些结果。要解决这个问题,您必须存储这些函数可能需要的所有信息都放入一个单独的 object 中,并将该 object 传递给每个函数,以便它们可以从该 object 中读取字段并根据需要向其中写入字段。

It is probably not worth the hassle, and it will probably not make it any more clear to the reader what is happening.这可能不值得麻烦,而且可能不会让读者更清楚发生了什么。

Consider keeping the structure of your existing code but just improving it, for example:考虑保留现有代码的结构,但只是对其进行改进,例如:

  • Use a single enum telling you how far you went instead of a whole bunch of booleans;使用一个枚举告诉你你走了多远,而不是一大堆布尔值;

  • Move all the steps in a new function, and modify each error check so that it returns a failure indication instead of saving state and then returning.将所有步骤移到一个新的 function 中,并修改每个错误检查,使其返回失败指示,而不是保存 state 然后返回。 Then, from the place where you call this function, check whether it indicates error, and if so, save the state only in one place.然后从你调用这个function的地方看是否报错,如果报错就把state只存一处。

This is a place where State pattern can be used.这是可以使用 State 模式的地方。 As wiki says :正如维基所说

The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. state 模式是一种行为软件设计模式,它允许 object 在其内部 state 发生变化时改变其行为。 This pattern is close to the concept of finite-state machines这种模式接近于有限状态机的概念

Let me show how it can be implemented via C#.让我展示如何通过 C# 实现它。

This is a class which will run multiple API'in a sequence:这是一个 class,它将按顺序运行多个 API:

public class APIMachine
{
    IState _userState;
    IState _callbackState;
    IState _paymentState;
    IState _businessState;

    public string Run() 
    {
        _userState = InitializeState();
        _userState.Do();
        return _callbackState.GetResult().ToString();
    }

    private IState InitializeState() 
    {
        _callbackState = new CallbackState();
        _paymentState = new PaymentState(_callbackState);
        _businessState = new BusinessState(_paymentState);
        return new UserState(_businessState);
    }
}

This is an abstraction of all states:这是所有状态的抽象:

public interface IState
{
    void Do();

    bool HasSuccess { get; set; }

    int RetryCount { get; }

    object GetResult();
}

This is a concrete implementation of UserState :这是UserState的具体实现:

public class UserState : IState
{
    IState _state;

    public UserState(IState state) => _state = state;

    public int RetryCount => 3;

    public bool HasSuccess { get ; set ; }

    public void Do()
    {
       int count = 0;
        while (count <= RetryCount)
        {
            // Make post request here to create user
            HasSuccess = true;
            if (HasSuccess)
            {
                _state.Do();
                break;
            }
            count++;
        }
    }

    public object GetResult()
    {
        throw new NotImplementedException();
    }
}

and:和:

public class BusinessState : IState
{
    IState _state;

    public BusinessState(IState state) => _state = state;

    public int RetryCount => 3;

    public bool HasSuccess { get; set; }

    public void Do()
    {
        int count = 0;
        while (count <= RetryCount)
        {
            // Make post request here to create business profile
            HasSuccess = true; // if post request is okay
            if (HasSuccess)
            {
                _state.Do();
                break;
            }
            count++;
        }
    }

    public object GetResult()
    {
        throw new NotImplementedException();
    }
}

and:和:

public class PaymentState : IState
{
    IState _state;

    public PaymentState(IState state) => _state = state;

    public int RetryCount => 3;

    public bool HasSuccess { get; set; }

    public void Do()
    {
        int count = 0;
        while (count <= RetryCount)
        {
            // Make post request here to create payment profile
            HasSuccess = true; // if post request is okay
            if (HasSuccess) 
            {
                _state.Do();
                break;
            }
            count++;
        }
    }

    public object GetResult()
    {
        throw new NotImplementedException();
    }
}

and:和:

public class CallbackState : IState
{
    public int RetryCount => 3;

    public bool HasSuccess { get; set; }

    public void Do()
    {
        int count = 0;
        while (count <= RetryCount)
        {
            // Make post request here to create payment profile
            HasSuccess = true; // if post request is okay
            if (HasSuccess)
            {
                break;
            }
            count++;
        }
    }

    public object GetResult()
    {
        return "foobar.com";
    }
}

And the above code can be run like this:上面的代码可以这样运行:

APIMachine apiMachine = new();
string callbackUri = apiMachine.Run();

OUTPUT: foobar.com OUTPUT:foobar.com

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM