Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

How do to REST API with xmarin.forms

veso266veso266 Member ✭✭

Hi there

I have used RestSharp and wrapped an api into a nice NET Standard library
the library takes username, password and platform as arguments and then api outputs api key which library uses internally it also had data models in it

now it works fine, but I don't know how to integrate it into Xmarin.Forms, where to initiate it to be able to acsess its methods and its data from every xmarin.forms subpage (I am using a AppShell)

if we start with Shell Template that visual studio 2019 provides

should I initiate my API in AppShell.xaml.cs or in App.xaml.cs
but then if I do that in there how would I acsess it in for instance AboutPage View Model (I can make it static but this doesn't seem right and it wierd you have to call AppShell.myApi everytime you want to use an api)?

How would I access it in Xmarin.Android portion (I could use MessageCenter(but I can only call void methods with this I cannot(or don't know how) return data) or I could create some static classes in Xmarin.Forms portion, but I don't know if it is the right approach)

what is the best way to handle exeptions (for now my library only throws Exeption with message: throw new Exception("Message Here"))
API has errors like this:

200 - Request successful. More information is returned in json object. Object schema depends on method.
201 - Request successful. No result returned.
400 - Error occurred. Additional information provided in json response (ErrorResponse format: more info below)
401 - Authentication failure. There are two possible reasons: disabled API access or invalid ApiKey provided
403 - Access forbidden
404 - Invalid method URL
405 - HTTP method not allowed, please verify HTTP method of the request
429 - Too many requests in a given amount of time. API limits are 20 requests/second, 1500 requests/hour, 10000 requests/day
5xx - Something wrong happened in Calamari backend. Please wait a while and repeat your request. If error still occurs, drop us a line.

If status 4xx is returned, you can read additional information from returned json object.
{
"message": string,
"code": string,
"field": string
}

message - Human readable error explanation.
code - Error code. Possible value depends on method but there is few common error codes.
field - Which field of payload object caused error. NULL when error is not related to particular field

What is the best aproach to throw appropriate exeption for this, at the end I would like to show an alert to the user if exeption accures, so my library would trow 500Exeption for instance and user would get an error

how would I do this globally, so I don't need to wrap every button in try/catch block

All theese are more of a design questions that bother me and I don't know where to find anwsers to them, as I never saw an example with Xmarin.Forms and REST api that takes username/password api then sends api key which app uses in all subsequent API requests

Hopefully someone can give me some advice on all this, (particulary how to handle exeption and inform the user and where in the project to construct the api so I can easly acsess it from all subpages)

Thannks for Anwsering and Best Regards

Tagged:

Answers

  • veso266veso266 Member ✭✭

    @igork_10
    after looking at this(Thanks for posting it): https://github.com/xamarin/xamarin-forms-samples/tree/master/WebServices/TodoREST/TodoREST
    I saw that they are iniciating the api in mainApp to so I saw that this is normal

    now I have to figure out how would I handle exeptions so I don't need to wrap every API call in try/catch to show alert to the user if anyone has any idea about it

  • grimordegrimorde Member ✭✭

    I have my API call return a default object if the returned status code is not Success/Conflict. The calling process then deals with that as appropriate.

    public async Task<TReturn> Post<T, TReturn>(string url, T data, int retry = 0)
            {
                CheckConnected();
    
                HttpClient httpClient = CreateHttpClient(url);
                var content = new StringContent(JsonConvert.SerializeObject(data));
                content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    
                HttpResponseMessage response = null;
                response = await httpClient.PostAsync(url, content);
    
                if (response.StatusCode == HttpStatusCode.Conflict)
                {
                    if (int.TryParse(response.Content.ReadAsStringAsync().Result, out int apiId))
                    {
                        throw new ConflictApiResponseException(apiId);
                    }
    
                    if (retry <= maxRetry)
                    {
                        return await Post<T, TReturn>(url, data, retry++);
                    }
    
                    throw new Exception($"Conflicts with Api {url}");
                }
    
                if (response.IsSuccessStatusCode)
                {
                    var result = JsonConvert.DeserializeObject<TReturn>(response.Content.ReadAsStringAsync().Result);
                    return result;
                }
    
                return default(TReturn);
            }
    

    I do think you need to have some kind of handling in place so you can let the user know something went wrong or have your code handle the fact it couldn't get/post what it needed.

  • igorkr_10igorkr_10 Member ✭✭✭✭
    edited February 4

    I have similar way to throw exceptions as @grimorde
    Your API must to return any data of exception. In your application you just need to check if any troubles exist and throw exception
    Try-catch-finally blocks I always use on events (or command) when the user interact with application. For example, user taps button and in command you have try-catch.

  • veso266veso266 Member ✭✭

    @igorkr_10 yea but then I need to wrap everywhere where I think exeption could accur in try/cath/finally, but I don't have acsess to await DisplayAlert (); everywhere so I wanted something globally

  • igorkr_10igorkr_10 Member ✭✭✭✭
    You can call everywhere this:
    ((App)Application).MainPage.DisplayAlert()
  • veso266veso266 Member ✭✭

    right yea I can do that (although I had to do it like this: App.Current.MainPage.DisplayAlert(e.message); to make it work (I have a static class))

    but I cannot seem to cath exeption (catch (Exeption e): CS0246 The type or namespace name 'Exeption' could not be found (are you missing a using directive or an assembly reference?)

    I(my library) am trowing them like so: throw new Exception(err.code);

    also if you remember I made my login page working: https://forums.xamarin.com/discussion/comment/401812#Comment_401812

    but now when I call my DoLogin method my ui freezes up while data is fetch

    so if I have method in my library like so

    public bool Login(string TENANTID, string username, string password, string platform)
            {
                bool isLoggedIn = false;
    
                this.TENANT_ID = TENANTID;
                this.BASE_URL = Regex.Replace(this.BASE_URL, "{.*?}", this.TENANT_ID);
    
                client = new RestClient(BASE_URL); //Construct new HTTP Client with request URL
                RestRequest request = new RestRequest(RestSharp.Method.POST); //Tell RestSharp we are doing POST requests
    
                string method = "mobileapi/auth/loginpass"; //Tell it on which method to connect to
                request.Resource = method; //Tell it on which method to connect to
    
                request.RequestFormat = DataFormat.Json; //Tell it that POST data is RAW JSON
    
                User user = new User(username, password, platform); //Construct USER Object (used later)
                request.AddJsonBody(user); //Construct USER Object (used later)
    
                var response = client.Execute(request); //Connect and get the response back
    
                if ((response.StatusCode == HttpStatusCode.OK) || (response.StatusCode == HttpStatusCode.Created)) //If login is successful 200 is returned
                {
                    API_TOKEN = JsonConvert.DeserializeObject<APIToken>(response.Content); //We have our API Key
                    isLoggedIn = true; //We are logged in
                }
                return isLoggedIn;
            }
    

    how could I change it so I won't lock the UI while it fetches data?
    I am calling it like so in my LoginViewModel

            public LoginViewModel()
            {
                AuthenticateCommand = new Command(() =>
                {
                    AreCredentialsInvalid = !UserAuthenticated(Username, Password);
                    if (AreCredentialsInvalid) return;
    
                    App.Current.MainPage = new MainPage();
                });
    
                AreCredentialsInvalid = false;
            }
    
            private bool UserAuthenticated(string username, string password)
            {
                bool loggedIn = false;
                if (string.IsNullOrEmpty(username)
                    || string.IsNullOrEmpty(password))
                {
                    return false;
                }
                loggedIn = App.api.Login("dxing", username, password, Device.RuntimePlatform.ToString());
                if (loggedIn)
                    App.IsUserLoggedIn = true;
                else
                    App.IsUserLoggedIn = false;
    
                return loggedIn;
            }
    

    how could I change and call my method so it won't lock the UI while it gets data?

  • igorkr_10igorkr_10 Member ✭✭✭✭
    edited February 12
    @veso266 you are talking about blocking the UI thread. To avoid this you need to use async/await mechanism. This example shows how to send requests asynchronously, implement this in your project https://docs.microsoft.com/ru-ru/xamarin/cross-platform/platform/async#writing-an-async-method
    I recommend to use HttpClient with methods SendAsync and GetAsync. You will find a lot of examples in web.
    Also, make sure the json from your request deserealizing asynchronously too.
    Also, you need to use async/await in any long running cases.
Sign In or Register to comment.