asp.netasp.net-web-api

Get data from external API with a asp.net core API


I'm learning to create APIs using ASP.NET core, in this I came up with a problem, I'm trying to execute a request for an external API using my API, but I do not know how to execute the request and return the JSON of the request, any help?

The flow of the application looks something like this:

SPA -> AspNet Core WEB API -> External API

What I've done so far:

[Route("api/[Controller]")]
    public class RankingsController : Controller
    {
        private readonly IRankingRepository _rankingRepository;

        public RankingsController(IRankingRepository rankingRepo)
        {
            _rankingRepository = rankingRepo;
        }

        [HttpGet("{id}", Name = "GetRanking")]
        public IActionResult GetById(long id)
        //Here is where I want to make the requisition
        }

    }

I need to make the request for this API:

http://api.football-data.org/v1/competitions/{id}/leagueTable

In the ID location, I need to pass a parameter that comes from the request made in my API;

Any help for this problem?

Sorry for not being such a complex question.

Thanks!!


Solution

  • You could use an HttpClient instance to achieve what you want. However, I always find easier to use RestSharp though.

    That, of course will depend on your constraints but assuming you have none for this case, you could use RestSharp to make the call to the external API:

    Install it:

    Install-Package RestSharp

    Usage:

    using RestSharp;
    
    [HttpGet("{id}", Name = "GetRanking")]
    public async Task<IActionResult> GetByIdAync(long id)
    {
        var client = new RestClient($"http://api.football-data.org/v1/competitions/{id}/leagueTable");
        var request = new RestRequest(Method.GET);
        IRestResponse response = await client.ExecuteAsync(request);
    
        //TODO: transform the response here to suit your needs
       
        return Ok(data);
    }
    

    To consume the rest response from RestSharp you must use the response.Content property.

    You could, for example, deserialize it to Json, manipulate it to fit your needs and return the required data to your API caller.

    Example:

    Let's say I'd like to get the rankings for the Premier League 2017/18 (Id = 445):

    I'll get a lot of help below from the legendary Newtonsoft.Json package and a little of jpath syntax but I'll assume you've already used both :)

    Create a couple models to hold the values to be returned to the API caller:

    public class LeagueTableModel
    {
        public string LeagueCaption { get; set; }
    
        public IEnumerable<StandingModel> Standings { get; set; }
    }
    public class StandingModel
    {
        public string TeamName { get; set; }
    
        public int Position { get; set; }
    }
    

    Implement the below method in the service class, injected to your controller through DI/IoC to avoid coupling and increase testability (as we all know we should do right?). I'm assuming this class is RankingRepository in your sample:

    public RankingRepository: IRankingRepository 
    {
        public Task<LeagueTableModel> GetRankingsAsync(long id)
        {
            var client = new RestClient($"http://api.football-data.org/v1/competitions/{id}/leagueTable");
            var request = new RestRequest(Method.GET);
            IRestResponse response = await client.ExecuteAsync(request);
            if (response.IsSuccessful)
            {
                var content = JsonConvert.DeserializeObject<JToken>(response.Content);
        
                //Get the league caption
                var leagueCaption = content["leagueCaption"].Value<string>();
        
                //Get the standings for the league.
                var rankings = content.SelectTokens("standing[*]")
                    .Select(team => new StandingModel
                    {
                        TeamName = (string)team["teamName"],
                        Position = (int)team["position"]
                    })
                    .ToList();
        
                //return the model to my caller.
                return new LeagueTableModel
                {
                    LeagueCaption = leagueCaption,
                    Standings = rankings
                };
            }
        
            //TODO: log error, throw exception or do other stuffs for failed requests here.
            Console.WriteLine(response.Content);
        
            return null;
        }
    }
    

    Use it from the controller:

    [Route("api/[Controller]")]
    public class RankingsController : Controller
    {
        private readonly IRankingRepository _rankingRepository;
    
        public RankingsController(IRankingRepository rankingRepo)
        {
            _rankingRepository = rankingRepo;
        }
    
        [HttpGet("{id}", Name = "GetRanking")]
        public Task<IActionResult> GetByIdAsync(long id)
            //Here is where I want to make the requisition
            var model = await _rankingRepository.GetRankingsAsync(id);
            
            //Validate if null
            if (model == null)
                return NotFound(); //or any other error code accordingly. Bad request is a strong candidate also.
    
            return Ok(model);
        }
    }
    

    Hope this helps!