More

    Example of full API code and Error/Exception Handling (Chapter 9)

    (1) Example of search a client list

    [Authorize(Role.Admin, Role.Operator)]
    [HttpGet("list")]
    public async Task<IActionResult> GetClientList([FromQuery] ClientSearchCommand command)
    {
        // Rewritten by Sammy Cheng, 2022-05-11
        //checkAdmin(Guid.Empty);
        var response = new GenericResponseModel<ClientListModel>();
        var clients = await _clientService.GetAllClientsAsync(command);
        response.Data = _clientFactory.PrepareClientListResponseModel(response.Data, clients);            
        return Ok(response);
    }
    namespace BlueSky.Service.Models.Client
    {
        // Rewritten by Sammy Cheng, 2022-05-10
        /// <summary>
        /// Represents search options for clients
        /// </summary>
        public partial record ClientSearchCommand : BasePageableModel
        {
            /// <summary>客戶 Guid, 如網上注冊,客戶 Guid 同跟用戶編號一樣</summary>
            public Guid? EntityGuid { get; set; }
            /// <summary>上級客戶編號</summary>
            public Guid? MasterClientGuid { get; set; }
            /// <summary>業務員編號或協銷聯盟編號</summary>
            public string SalesCode { get; set; }
            /// <summary>客戶分類, 網上注冊用戶為 N</summary>
            public string ClientTypeCode { get; set; }
            /// <summary>客戶名稱, 如公司客戶則公司名稱</summary>
            public string ClientName { get; set; }
            /// <summary>國家 (地址)</summary>
            public string CountryCode { get; set; }
            /// <summary>州/省 (地址)</summary>
            public string StateProvinceCode { get; set; }
            /// <summary>市/縣</summary>
            public string CountyCode { get; set; }
            /// <summary>城/鎮</summary>
            public string City { get; set; }
            /// <summary>地址</summary>
            public string Address { get; set; }
            /// <summary>電郵地址</summary>
            public string Email { get; set; }
            /// <summary>手提電話</summary>
            public string Phone { get; set; }
            /// <summary>狀況 0-新客戶, 1-活動, -1-暫停,-2-已刪除</summary>
            public short? Status { get; set; }
            /// <summary>Show Active Only</summary>
            public bool ActiveOnly { get; set; } = true;
            /// <summary>Include Deleted Records</summary>
            public bool IncludeDeleted { get; set; } = false;
            /// <summary>
            /// Order By :      0 - CreateTimeUtc
            ///                 1 - Client Code
            ///                 2 - Client Name
            /// </summary>
            public int? OrderBy { get; set; }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    // Rewritten by Sammy Cheng, 2022-05-11
    /// <summary>
    /// Represents a Client List Response Model
    /// </summary>
    namespace BlueSky.Service.Models.Client
    {
        public class ClientListModel
        {
            public IList<ClientModel> Clients { get; set; }
    
            public ClientListModel()
            {
                Clients = new List<ClientModel>();
            }
        }
        
    }
    
    namespace BlueSky.Service.Factories
    {
        public class ClientFactory : IClientFactory
        {
            #region Properties
    
            private readonly DataContext _context;
            private readonly IMapper _mapper;
            
            #endregion
    
            #region Ctor
    
            public ClientFactory(
                DataContext context,
                IMapper mapper)
            {
                _context = context;
                _mapper = mapper;
            }
    
            #endregion
    
            #region Utilities
            #endregion
    
            #region Methods
    
            public Client PrepareClientFromUpdateModel(Client response, ClientUpdateRequest model)
            {
                _mapper.Map<ClientUpdateRequest, Client>(model, response);
                return response;
            }
    
            public ClientModel PrepareClientResponseModel(ClientModel response, Client client)
            {
                response = _mapper.Map<ClientModel>(client);
                return response;
            }
    
            public ClientListModel PrepareClientListResponseModel(ClientListModel response, IPagedList<Client> list)
            {
                if (response == null)
                    response = new ClientListModel();
    
                response.Clients = _mapper.Map<List<ClientModel>>(list);
                return response;
            }
    
            #endregion
        }
    }
    public async Task<IPagedList<Client>> GetAllClientsAsync(ClientSearchCommand command)
    {
        // Rewrite by Sammy Cheng, 2022-05-11
        var clients = await _clientRepository.GetAllPagedAsync(query =>
        {
            if (command.EntityGuid != Guid.Empty && command.EntityGuid != null)
                query = query.Where(g => g.EntityGuid == command.EntityGuid);
            if (command.MasterClientGuid != Guid.Empty && command.EntityGuid != null)
                query = query.Where(g => g.MasterClientGuid == command.MasterClientGuid);
            if (String.IsNullOrEmpty(command.SalesCode))
                query = query.Where(s => s.SalesCode == command.SalesCode);
            if (string.IsNullOrEmpty(command.ClientTypeCode))
                query = query.Where(t => t.ClientTypeCode == command.ClientTypeCode);
            if (string.IsNullOrEmpty(command.ClientName))
                query = query.Where(c => c.ClientName.Contains(command.ClientName));
            if (string.IsNullOrEmpty(command.CountryCode))
                query = query.Where(c => c.CountryCode == command.CountryCode);
            if (string.IsNullOrEmpty(command.StateProvinceCode))
                query = query.Where(s => s.StateProvinceCode == command.StateProvinceCode);
            if (string.IsNullOrEmpty(command.CountyCode))
                query = query.Where(c => c.CountyCode == command.CountyCode);
            if (string.IsNullOrEmpty(command.City))
                query = query.Where(c => c.City.Contains(command.City));
            if (string.IsNullOrEmpty(command.Address))
                query = query.Where(a => a.Add1.Contains(command.Address) || a.Add2.Contains(command.Address));
            if (string.IsNullOrEmpty(command.Email))
                query = query.Where(e => e.Email.Contains(command.Email));
            if (string.IsNullOrEmpty(command.Phone))
                query = query.Where(p => p.MobilePhone.Contains(command.Phone) || p.Tel1.Contains(command.Phone)
                || p.Tel2.Contains(command.Phone) || p.Fax1.Contains(command.Phone) || p.Fax2.Contains(command.Phone));
            if (command.Status.HasValue)
                query = query.Where(s => s.Status == command.Status);
            switch (command.OrderBy)
            {
                case 1:
                    query = query.OrderBy(o => o.ClientCode);
                        break;
                    case 2:
                        query = query.OrderBy(o => o.ClientName);
                        break;
                    default:                    
                        query = query.OrderBy(o => o.CreateTimeUtc);
                        break;
                    }
    
    
                    return query;
           }, pageIndex: command.PageIndex, pageSize: command.PageSize, activeOnly: command.ActiveOnly, includeDeleted: command.IncludeDeleted );
    
           return clients;
    }

    This example has complete to demostrate how to create a API for search client and reture ClientListModel

    (2) Example of Updating a Client

    /// <summary>
    /// 更新當前客戶資料, 如客戶可使用 Cookie, 則不用指明 ClientGuid
    /// Update current client information record
    /// </summary> 
    /// <remarks>
    /// 
    /// 驗證 : Bearer Token + Cookie / Admin to update other client
    /// 
    /// 請求路由: api/client/update/{ClientGuid}
    /// 
    /// 請求方法: POST
    ///     
    /// </remarks>
    /// <response code="200">Ok Success</response>
    /// <response code="400">Error:304    Client record not found or UserGuid not correct. 客戶資料找不到, 可能是 UserGid 不正確</response>
    /// <response code="401">Unauthorized</response>
    [Authorize]
    [HttpPost("update/{ClientGuid}")]
    public async Task<IActionResult> UpdateClient([FromBody]ClientUpdateRequest model, Guid ClientGuid)
    {
        // Rewritten by Sammy Cheng, 2022-05-11
        var response = new GenericResponseModel<ClientModel>();
        // accept token from request body or cookie
        ClientGuid = getUserGuidCookie(ClientGuid);
    
        var client = await _clientService.UpdateClientFromModelAsync(model, ClientGuid);
        response.Data = _clientFactory.PrepareClientResponseModel(response.Data, client);
        return Ok(response);
    }
    namespace BlueSky.Service.Models.Client
    {
        public class ClientUpdateRequest
        {
            /// <summary>客戶 Guid, 如網上注冊,客戶 Guid 同跟用戶編號一樣</summary>
            public Guid EntityGuid { get; set; }
            /// <summary>上級客戶編號</summary>
            public Guid MasterClientGuid { get; set; }
            /// <summary>業務員編號或協銷聯盟編號</summary>
            public string SalesCode { get; set; }
            /// <summary>簡稱</summary>
            public string ShortName { get; set; }
            /// <summary>客戶分類, 網上注冊用戶為 N</summary>
            public string ClientTypeCode { get; set; }
            /// <summary>客戶名稱, 如公司客戶則公司名稱</summary>
            public string ClientName { get; set; }
            /// <summary>姓氏</summary>
            public string FirstName { get; set; }
            /// <summary>名子</summary>
            public string LastName { get; set; }
            /// <summary>國家 (地址)</summary>
            public string CountryCode { get; set; }
            /// <summary>州/省 (地址)</summary>
            public string StateProvinceCode { get; set; }
            /// <summary>市/縣</summary>
            public string CountyCode { get; set; }
            /// <summary>城/鎮</summary>
            public string City { get; set; }
            /// <summary>地址(一行)</summary>
            public string Add1 { get; set; }
            /// <summary>地址(二行)</summary>
            public string Add2 { get; set; }
            /// <summary>郵政編碼</summary>
            public string ZipCode { get; set; }
            /// <summary>預設帳單地址 ID, 跟 Addres ID</summary>
            public int? DefBillAddressId { get; set; }
            /// <summary>預設送貨地址 ID, 跟 Address ID</summary>
            public int? DefShipAddressId { get; set; }
            /// <summary>電郵地址</summary>
            public string Email { get; set; }
            /// <summary>電話 1</summary>
            public string Tel1 { get; set; }
            /// <summary>電話 2</summary>
            public string Tel2 { get; set; }
            /// <summary>傳真 1</summary>
            public string Fax1 { get; set; }
            /// <summary>傳真 2</summary>
            public string Fax2 { get; set; }
            /// <summary>手提電話</summary>
            public string Mobile { get; set; }
            /// <summary>貨幣</summary>
            public string CurrencyCode { get; set; }
            /// <summary>狀況 0-新客戶, 1-活動, -1-暫停,-2-已刪除</summary>
            public short? Status { get; set; }
            /// <summary>個人或公司網址</summary>
            public string WebPage { get; set; }
            /// <summary>備註</summary>
            public string Remarks { get; set; }
    
        }
    }
    namespace BlueSky.Service.Factories
    {
        public class ClientFactory : IClientFactory
        {
            #region Properties
    
            private readonly DataContext _context;
            private readonly IMapper _mapper;
            
            #endregion
    
            #region Ctor
    
            public ClientFactory(
                DataContext context,
                IMapper mapper)
            {
                _context = context;
                _mapper = mapper;
            }
    
            #endregion
    
            #region Utilities
            #endregion
    
            #region Methods
    
            public Client PrepareClientFromUpdateModel(Client response, ClientUpdateRequest model)
            {
                _mapper.Map<ClientUpdateRequest, Client>(model, response);
                return response;
            }
    
            public ClientModel PrepareClientResponseModel(ClientModel response, Client client)
            {
                response = _mapper.Map<ClientModel>(client);
                return response;
            }
    
            public ClientListModel PrepareClientListResponseModel(ClientListModel response, IPagedList<Client> list)
            {
                if (response == null)
                    response = new ClientListModel();
    
                response.Clients = _mapper.Map<List<ClientModel>>(list);
                return response;
            }
    
            #endregion
        }
    }
    private async Task ClientUpdateAsync(Client client)
    {
        try
        {
            await _clientRepository.UpdateAsync(client);
        }catch( Exception E)
        {
            throw new AppException(_context.errorList.Response(ErrorCode.DataUpdateError, _detail: E.Message).ToString());
    
        }
    }
    
    public async Task<Client> UpdateClientFromModelAsync(ClientUpdateRequest model, Guid ClientGuid)
    {
        // Rewrite by Sammy Cheng, 2022-05-11
        var client = await GetClientAsync(ClientGuid);
        client = _clientFactory.PrepareClientFromUpdateModel(client, model);
    
        await ClientUpdateAsync(client);
        return client;
    }

    For this example, it demonstrates how to use get the model and update to Database by repository.

    Error And Exception Handling

    Inside the Framework, to handle the error, we can easy by throwing a AppException to return a Bad Request response. The framework has created a “errorList” class that store list of most commonly used error code and description. To call the error, just simple use like this

    try
    {
        await _clientRepository.UpdateAsync(client);
    }catch( Exception E)
    {
        throw new AppException(_context.errorList.Response(ErrorCode.DataUpdateError, _detail: E.Message).ToString());
    }

    The errorList class current declared in the DataContent, but will move to as a new service in coming version. We will create more information once the error handle service completed.

    Overview : Developer Guide for BlueSky .NETCORE API Framework

    Previous : Creating Controller Classes with API endpoint (Ch.8)

    Next : Chapter 10 : PostMan Documentation Guide

    (c) 2022, BlueSky Information Technology (Int’l) Co. Ltd, All Rights Reserved.

    Recent Articles

    spot_img

    Related Stories

    Stay on op - Ge the daily news in your inbox