none
Colon in Api Get Request URL RRS feed

  • Question

  • Hello,

    I have to send a get request with one parameter to a API, The url looks like this

    https://myapi/v1/api/visits/:visitUuid

    When i send the request as https://myapi/v1/api/visits?visitUuid=1 i am getting a error from server that says that visitUuid is missing

    In postman it looks like this

    So how to send the request with the param correctly in c#?

    Friday, January 11, 2019 1:45 PM

Answers

  • Step 1: Use Fiddler or any other sniffer to display the raw request data..

    Step 2: RTFM. I guess :visitUuid as a parameter is only a placeholder, thus the correct URI/URL is in this case simply https://myapi/v1/api/visits/1.

    btw, your path naming seems that it could use some rework. api is redundantly used and imho the version should be not part of the path. I prefer the http way using a header line. Otherwise I use sub domains for that (https://v1.domain.tld/api/visits/1). Thus the path for the same request is identical (/api/visits/1).


    Edit: a UUID is not an ordinary number. It is a 128-bit (16 byte) value formatted as e.g. 550e8400-e29b-11d4-a716-446655440000. Thus a value like 123 in the given screenshot seems to be nonsense. 1 would be 00000000-0000-0000-0000-000000000001 and 123 would be 00000000-0000-0000-0000-00000000007B, when using sequential, local UUIDs.

    • Edited by Stefan Hoffmann Friday, January 11, 2019 2:23 PM
    • Proposed as answer by Tim Roberts Saturday, January 12, 2019 2:15 AM
    • Marked as answer by KBid Monday, January 14, 2019 3:08 PM
    Friday, January 11, 2019 2:18 PM
  • If you're responsible for the API itself then you may have a routing issue. Questions related to creating REST APIs should be posted in the ASP.NET forums.

    If you're simply the client of the API then I assume you're using HttpClient. Ideally you have wrapped the client calls into a responsible class.

    The URL you're sending is not the same as what the API wants. The API says the id is part of the URL. You are trying to pass it as part of the query string. Two completely different things. You didn't post the code you're using which is where the problem lies. Here's how I'd do it.

    class Program
    {
        static void Main ( string[] args )
        {
            //In a real app this should be created once per URL and then reused for the life of the app
            //It is very important that the URL end with a slash otherwise Uri does not properly build URLs
            var client = new HttpClient() { BaseAddress = new Uri("https://myapi/v1/api/") };
    
            //When you need to make the calls, create an instance of your client
            var myClient = new MyApiClient(client);
    
            //For most code you can call the method async but for older versions of C# or code that is not async
            //then you have to wait for the result
            var visit = myClient.GetVisitAsync(1, CancellationToken.None).Result;
        }
    }
    
    class MyApiClient
    {
        //HttpClient is a special type that should be created only once per URL and should be pre-configured by the app
        public MyApiClient ( HttpClient client )
        {
            _client = client;
        }        
    
        //HttpClient is async by nature so exposing the functionality as async is standard
        public Task<Visit> GetVisitAsync ( int id, CancellationToken cancellationToken )
        {
            //The URL
            var url = $"visits/:{id}";
    
            //Make the call
            return GetAsync<Visit>(url, cancellationToken);
        }        
    
        //We normally use an extension method to make this easier but we'll do it via a private method
        private async Task<T> GetAsync<T> ( string resourceUrl, CancellationToken cancellationToken )
        {
            var response = await _client.GetAsync(resourceUrl, cancellationToken).ConfigureAwait(false);
    
            //Check for errors
            response.EnsureSuccessStatusCode();
    
            //Convert the JSON results to your business type
            var results = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    
            return await Task.Run(() => JsonConvert.DeserializeObject<T>(results), cancellationToken).ConfigureAwait(false);
        }
    
        private readonly HttpClient _client;        
    }
    
    //This is the data that the API returns back to you for a "visit"
    class Visit
    {
    }


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by KBid Monday, January 14, 2019 3:08 PM
    Friday, January 11, 2019 3:46 PM
    Moderator

All replies

  • Step 1: Use Fiddler or any other sniffer to display the raw request data..

    Step 2: RTFM. I guess :visitUuid as a parameter is only a placeholder, thus the correct URI/URL is in this case simply https://myapi/v1/api/visits/1.

    btw, your path naming seems that it could use some rework. api is redundantly used and imho the version should be not part of the path. I prefer the http way using a header line. Otherwise I use sub domains for that (https://v1.domain.tld/api/visits/1). Thus the path for the same request is identical (/api/visits/1).


    Edit: a UUID is not an ordinary number. It is a 128-bit (16 byte) value formatted as e.g. 550e8400-e29b-11d4-a716-446655440000. Thus a value like 123 in the given screenshot seems to be nonsense. 1 would be 00000000-0000-0000-0000-000000000001 and 123 would be 00000000-0000-0000-0000-00000000007B, when using sequential, local UUIDs.

    • Edited by Stefan Hoffmann Friday, January 11, 2019 2:23 PM
    • Proposed as answer by Tim Roberts Saturday, January 12, 2019 2:15 AM
    • Marked as answer by KBid Monday, January 14, 2019 3:08 PM
    Friday, January 11, 2019 2:18 PM
  • If you're responsible for the API itself then you may have a routing issue. Questions related to creating REST APIs should be posted in the ASP.NET forums.

    If you're simply the client of the API then I assume you're using HttpClient. Ideally you have wrapped the client calls into a responsible class.

    The URL you're sending is not the same as what the API wants. The API says the id is part of the URL. You are trying to pass it as part of the query string. Two completely different things. You didn't post the code you're using which is where the problem lies. Here's how I'd do it.

    class Program
    {
        static void Main ( string[] args )
        {
            //In a real app this should be created once per URL and then reused for the life of the app
            //It is very important that the URL end with a slash otherwise Uri does not properly build URLs
            var client = new HttpClient() { BaseAddress = new Uri("https://myapi/v1/api/") };
    
            //When you need to make the calls, create an instance of your client
            var myClient = new MyApiClient(client);
    
            //For most code you can call the method async but for older versions of C# or code that is not async
            //then you have to wait for the result
            var visit = myClient.GetVisitAsync(1, CancellationToken.None).Result;
        }
    }
    
    class MyApiClient
    {
        //HttpClient is a special type that should be created only once per URL and should be pre-configured by the app
        public MyApiClient ( HttpClient client )
        {
            _client = client;
        }        
    
        //HttpClient is async by nature so exposing the functionality as async is standard
        public Task<Visit> GetVisitAsync ( int id, CancellationToken cancellationToken )
        {
            //The URL
            var url = $"visits/:{id}";
    
            //Make the call
            return GetAsync<Visit>(url, cancellationToken);
        }        
    
        //We normally use an extension method to make this easier but we'll do it via a private method
        private async Task<T> GetAsync<T> ( string resourceUrl, CancellationToken cancellationToken )
        {
            var response = await _client.GetAsync(resourceUrl, cancellationToken).ConfigureAwait(false);
    
            //Check for errors
            response.EnsureSuccessStatusCode();
    
            //Convert the JSON results to your business type
            var results = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    
            return await Task.Run(() => JsonConvert.DeserializeObject<T>(results), cancellationToken).ConfigureAwait(false);
        }
    
        private readonly HttpClient _client;        
    }
    
    //This is the data that the API returns back to you for a "visit"
    class Visit
    {
    }


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by KBid Monday, January 14, 2019 3:08 PM
    Friday, January 11, 2019 3:46 PM
    Moderator