graphQL laytipay 开发笔记

174 阅读3分钟

添加sender

1 去playground 走通业务 。

playground 地址。

developer.flash-fx.com/senders api.dev.flash-fx.com.au

1.1 login 拿token .

```
mutation ($loginInput: LoginInput!) {
                    login(input: $loginInput) {
                        token
                        message
                        code
                        success
                    }
}

//variables
{
  "loginInput": {
    "email": "devops@latipay.net",
    "password": "Latipay2022"
  }
}
```
得到响应的数据
```json
{
  "data": {
    "login": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MGQ1NTkzMDU3MmMxYzUyYjhjZThmYzQiLCJjbGllbnRJZCI6IjYwZDU1OTMwNTcyYzFjMDcxZWNlOGZjNyIsImlhdCI6MTY2MTgzMzg2MiwiZXhwIjoxNjYxOTIwMjYyfQ.hXlPy8WymLdRDJCj4924oFjehf9VXteJqEVwBY_pyoU",
      "message": "OK",
      "code": "SUCCESS",
      "success": true
    }
  }
}
```

1.2 在playground 走通createSender

先参考手册 image.png

实现一个简版的走通。

mutation ($SenderInput: SenderInput!) {
     createSender(input: $SenderInput) {
        success
        code
        message
    	  sender {
          id
          nickName,
       }
     }
}

//设置header  通过1.1 login 获取
{"authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MGQ1NTkzMDU3MmMxYzUyYjhjZThmYzQiLCJjbGllbnRJZCI6IjYwZDU1OTMwNTcyYzFjMDcxZWNlOGZjNyIsImlhdCI6MTY2MTgzMzg2MiwiZXhwIjoxNjYxOTIwMjYyfQ.hXlPy8WymLdRDJCj4924oFjehf9VXteJqEVwBY_pyoU"}

//设置请求变量
{
  "SenderInput": {
    "firstName": "xu",
    "lastName": "xing",
    "email":"13823761206@163.com",
    "address": {
      "street": "1 Test st",
      "suburb": "London",
      "state": "TST",
      "country": "GB",
      "postcode": "2000"
    }
  }
}

走通后响应如下。

{
  "data": {
    "createSender": {
      "success": true,
      "code": "CREATED",
      "message": "New sender created",
      "sender": {
        "id": "630dadd0a0b12a29510286fc",
        "nickName": "xuxing"
      }
    }
  }
}

让响应内容丰富一些。

mutation ($SenderInput: SenderInput!) {
     createSender(input: $SenderInput) {
        success
        code
        message
    	  sender {
          id
          nickName,
       }
     }
}

调整后,效果如图。 image.png

2 开发service

2.1 定义请求体结构。 (习惯就好,json 带子结构,就用子类来包一下)

namespace FlashFxPayment.Shared.Services.FlashFx.Models.Sender
{
    public class SenderInput
    {
        public string FirstName { get; set; } = default!;
        public string LastName { get; set; } = default!;
        public string Email { get; set; } = default!;
        public SenderAddress Address { get; set; } = default!;
    }
    
    
   public class SenderAddress
    {
        public string? Street { get; set; } = default;
        public string? Suburb { get; set; } = default;
        public string? State { get; set; } = default;
        public CountryIso2? Country { get; set; } = default;
        public string? Postcode { get; set; } = default;
    }
    
}

2.2 定义响应

override tostring 方便打日志的时候看数据。

image.png

namespace FlashFxPayment.Shared.Services.FlashFx.Models.Sender
{
    public class CreateSenderReply
    {

        public bool Success { get; set; }
        public string Code { get; set; } = default!;
        public string Message { get; set; } = default!;

        public Sender Sender { get; set; } = default!;

        public override string ToString()
        {
            return "CreateSenderRelay: Success:" + Success + " Code:" + Code+ " Message:" + Message + " <SenderResponse> Sender" + Sender.ToString() + " base:" +base.ToString();
        }

    }
    
    
     public class Sender
    {
        //id 好像是
        public string Id { get; set; } = default!;

        //昵称
        public string NickName { get; set; } = default!;
        public string Email { get; set; } = default!;


        public override string ToString()
        {
            return "Id:"+Id + " - NickName" + NickName + " - Email:" + Email + " | base: " + base.ToString();
        }
    }
   
}

再用 Response包一下。 image.png

    public class CreateSenderResponse
    {
        public CreateSenderReply CreateSender { get; set; }
    }

2.3 实现业务方法

 //创建Sender 
    public async Task<CreateSenderReply?> CreateSender(string? token, String firstName, String lastName, String email, SenderAddress address)
    {
        try
        {
            var createSenderRequest = new GraphQLRequest
            {
                Query = @"mutation ($senderInput: SenderInput!) {
                    createSender(input: $senderInput) {
                        success
                        message
                        code
                        sender {
                          id
                          nickName
                          email
                        }
                    }}
                ",
                Variables = new
                {
                    senderInput = new SenderInput
                    {
                        FirstName = firstName ,
                        LastName = lastName,
                        Email = email,
                        Address = address
                    }
                }
            };

            _client.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
            var result = await _client.SendQueryAsync<CreateSenderResponse>(createSenderRequest);

            if ((result.Errors == null || result.Errors?.Length == 0) && result.Data.CreateSender != null)
            {
                _logger.LogInformation("---------------------   Code SendQueryAsyncResponse ------" + result.Data.CreateSender?.Code);
                _logger.LogInformation("---------------------   Message SendQueryAsyncResponse ------" + result.Data.CreateSender?.Message);
                _logger.LogInformation("---------------------   Success  SendQueryAsyncResponse ------" + result.Data.CreateSender?.Success);
                _logger.LogInformation("---------------------   Sender.Id  CreateSender _client.SendQueryAsync ------" + result.Data.CreateSender?.Sender?.Id);
                _logger.LogInformation("---------------------   Sender.NickName  CreateSender _client.SendQueryAsync ------" + result.Data.CreateSender?.Sender?.NickName);
                _logger.LogInformation("---------------------   Sender.obj  CreateSender _client.SendQueryAsync ------" + result.Data.CreateSender?.Sender);

                var myReturn = result.Data.CreateSender;
                _logger.LogInformation("||------------" + myReturn.ToString());
                return result.Data.CreateSender;
            } else {

                _logger.LogInformation("error");
                return null;
            }

           
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "FlashFxService.CreateSender: Failed to create sender");
            return null;
        }

    }

3 开发api (将用户请求,转为grapthQl 业务请求。)

请求结构。

预计一个用户请求为

{
    "firstName":"xu",
    "lastName":"xing",
    "email":"13823761206@163.com",
    "address":{
        "street":"test333",
        "state":"London",
        "suburb":"urb test1",
        "country":"GB",
        "postcode":"2000"
    }
}

//定义请求结构。

  public class CreateSenderRequest
    {
        public string? FirstName;
        public string? LastName;
        public string? Email;
        // public CreateSenderAddressRequest? Address;

        public AddressRequest? Address;


    }

    public class CreateSenderAddressRequest
    {
        public string? Street { get; set; }
        public string? State { get; set; }
        public string? Suburb { get; set; }
        public CountryIso2? Country { get; set; }
        public string? Postcode { get; set; }
    }

响应结构

image.png

  public class CreateSenderResponse
    {
        public string Id { get; set; } = default!;
        public string NickName { get; set; } = default!;
        public string Email { get; set; } = default!;

        public override string ToString()
        {
            return "CreateSenderResponse: Id:" + Id+ " - Nickname:" + NickName +" - Email:" + Email +  "   - " + base.ToString();
        }
    }

实现控制器代码。



        [Route("api/sender/create-sender")]
        [TokenAuthorize]
        public async Task<IActionResult> CreateSender([FromBody] CreateSenderRequest request)
        {
            try
            {
                //HttpContext.GetToken();
                _logger.LogInformation("Token = {Token}", HttpContext.GetToken());

                //一些输入校验。
                if (string.IsNullOrWhiteSpace(request.FirstName))
                {
                    return BadRequest(BaseResponse.Create(ResponseCode.ApiParameterIsMissing, nameof(request.FirstName).Lower(true)));
                }

                if (string.IsNullOrWhiteSpace(request.LastName))
                {
                    return BadRequest(BaseResponse.Create(ResponseCode.ApiParameterIsMissing, nameof(request.LastName).Lower(true)));
                }

                _logger.LogInformation("here to send reqest");

                /*
                if (request.Address == null)
                {
                    return BadRequest(BaseResponse.Create(ResponseCode.ApiParameterIsMissing, nameof(request.Address).Lower(true)));
                }
                */

                _logger.LogInformation("------- controller start to send  --------------" + request.FirstName + " - " + request.LastName);


                var address = request.Address.Adapt<SenderAddress>();

                //先走通不带address
                var senderRelay = await _flashFxService.CreateSender(HttpContext.GetToken(), request.FirstName, request.LastName, request.Email, address);
                //  _logger.LogInformation("_flashFxService:CreateSender" + senderRelay.ToString());


                if (senderRelay == null)
                {
                    return BadRequest(BaseResponse.Create(ResponseCode.ApiSenderCreateFailed));
                } else {

                    var MyData = senderRelay.Adapt<Models.Sender.CreateSenderResponse>();
                    _logger.LogInformation("||||------- controller response --------------" + senderRelay.ToString() );
                }

                return Ok(new DataResponse<Models.Sender.CreateSenderResponse>
                {

                                      Data = senderRelay.Adapt<Models.Sender.CreateSenderResponse>()
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AuthController.Login: Failed to log in");
                return InternalError(BaseResponse.Create(ResponseCode.Failure));
            }
        }

注意参数和响应的转换。

//注意dto 要转换。

// 1 请求时,要将request 中的 address  转为 service 中的 SenderAddress 对象。
//结构完全一致时。
    var address = request.Address.Adapt<SenderAddress>();
    
// 2 返回时,要将     senderReply 转为 senderReply.Adapt<Models.Sender.CreateSenderResponse>()

//由于 CreateSenderRelay  和 SenderResponse 结构不一致 所以需要写map .

        TypeAdapterConfig<CreateSenderReply, CreateSenderResponse>
            .ForType()
            .Map(dest => dest.Id, src => src.Sender.Id)
            .Map(dest => dest.NickName, src => src.Sender.NickName)
            .Map(dest => dest.Email, src => src.Sender.Email);
            
            
    

4 去postman 验收控制器。

image.png