Zebble
  • About Zebble
  • Compare
  • Documentation
  • Themes
  • Plug-ins
  • Contact Us

    • What is Zebble?
    • Structure of a Zebble solution
    • Zebble Designer (UWP)
    • Installing - Introduction
    • Change log
    • Introduction
    • ViewModel development
    • VM.EXE
    • View development
    • Dialogs
    • Lists and Collections
    • Tips and shortcuts
    • List views
    • ViewModel testing
    • Automatic Views
    • View development process
    • Hello World - Core Concepts
    • Layout: Sizing & Positioning
    • Event handling
    • Navigation
    • Alerts, Dialog, Prompt and toast
    • View lifecycle
    • Managing Files & Resources
    • Config & Debugging
    • Forms
    • Page templates
    • Device API
    • Animations
    • Web Api - Part 1 (reading data)
    • Web Api - Part 2 (post and delete)
    • Web Api - Part 3 (server vs client domain model)
    • Gesture events
    • View class
    • Zebble Markup (.zbl files)
    • Data Binding and MVVM
    • Stack class
    • Sizing and positioning
    • Layout examples
    • ScrollView class
    • Page class
    • Styling in Zebble
    • CSS property mapping to Zebble
    • Supported selectors
    • Zebble CSS: Under the hood
    • Inline styling
    • CSS real-time updates
    • Dynamic expressions in CSS
    • Gradient background colours
    • CSS Pseudo-classes support
    • Using Bold and Light Fonts in Zebble
    • Rotation in Zebble
    • Using custom fonts in Zebble
    • Flashing on tap using AutoFlash
    • Button
    • Carousel class
    • Checkbox class
    • DatePicker
    • Drawing class
    • FilePicker class
    • Grid class
    • IconButton class
    • ImageView
    • ItemPicker class
    • ListView & Grid classes
    • OptionsList
    • SearchInput class
    • Slider class
    • Switch class
    • Tabs Class
    • TextInput class
    • TextView
    • TimePicker
    • TreeView
    • Waiting Indicator
    • WebView class (displaying html)
    • C# Methods and Properties Of UI Components
    • Nav.Forward() vs Nav.Go()
    • Passing parameters to the destination page
    • Going Back
    • Showing Popup pages
    • Waiting class
    • Hardware Back button (e.g. Android)
    • NavigationBar class
    • Tabs class
    • Caching (pages)
    • Navigation without event handler
    • Use the Windows version
    • Logging messages for Debugging
    • Debugging Zebble/Plugin
    • Exception handling in Zebble
    • Debugging layout and styles
    • Zebble Device API
    • Device.Screen and orientation (landscape | portrait)
    • Code that should run on a specific platform
    • Using Lamp (aka Flash, LED and Torch)
    • Using Compass (Smooth compass)
    • Using Accelerometer (device angle)
    • Using Gyroscope (device motion speed)
    • How to Vibrate the device?
    • Launching the device browser
    • Finding device model and manufacturer
    • Responding to System events
    • Handling device shake event
    • Permissions
    • Permissions declaration (manifest files)
    • Sharing
    • Prompt for rating the app
    • Finding if Internet connection is available
    • Device messaging (Make a phone call, send SMS or Email)
    • Showing a local notification
    • Copying to Clipboard
    • Accessing device contacts
    • Reading and writing into Gallery (albums)
    • Playing & Recording Audio
    • Cache and temp files and folders
    • C# async / await
    • Understanding Zebble Threading
    • Debugging - the StackTrace problem
    • Not awaiting (running in parallel)
    • Timer (interval / scheduled running)
    • Post-render changes to the UI (dynamic)
    • Introduction of Geo location
    • Map & Location Services
    • Launch directions to a location (external)
    • Getting current Location
    • Tracking user location
    • Device.Media: Taking and picking photos
    • Playing an audio file
    • VideoPlayer class
    • Augmented reality
    • Recording audio
    • Virtual Reality
    • Speech Recognition
    • Recording or picking video
    • Playing remote videos in iOS
    • Text to speech
    • Introduction to the importance of Mobile Testing
    • Why and what to test
    • Testing mobile apps on different devices
    • Testing mobile apps
    • Xamarin Profiler
    • Performance optimization
    • Moving a view to another container at run-time
    • Attaching custom data (tag) to objects
    • Saving a view as image
    • Naming best practices
    • Fastest way to update your nuget package
    • Tips for Clean and Brief code
    • Splash screen and icon generation
    • Advice for passing Approval
    • Options for iOS app distribution
    • Test Release (internal and UAT)
    • Application Icons in IOS
    • Submitting to App Store
    • Releasing to App Store
    • Crash reporting
    • Optimized Release Build
    • Android - Generating an APK for manual installation
    • Payment (subscriptions & in-app purchases)
    • Introduction to push notifications
    • Registration process (App)
    • Push notification setup - iOS
    • Push notification setup - Android
    • Push notification setup - Windows
    • Sending a push message from the web app
    • Introduction
    • Connecting Zebble to Web API
    • Installation
    • Creating an API class
    • GET APIs
    • Calling a GET API (in the mobile app)
    • POST, PUT, PATCH and DELETE APIs
    • Domain Model
    • Web API and Authentication
    • Versioning
    • Uniquely identifying installations (token)
    • Settings file: config.xml
    • Standard Zebble settings
    • Login/Register with Facebook
    • Creating a composite component / plugin
    • Creating a Zebble component using Html and Javascript
    • CustomRenderedView: Third-party native components / plugins
    • Mapbox
    • Naming considerations
    • Random problems?
    • Display Keyboard for Visual Studio Android Emulator
    • iOS goes mad?
    • Configuring a Windows phone for ad-hoc testing
    • Fixing Error DEP0001 : Unexpected Error: -2147009287 while deploying Windows UWP app on device
    • Fixing Error DEP0001 : Unexpected Error: -1988945906 while deploying Windows UWP app on device
    • Unable tp Connect to the Mac agent from Visual Studio
    • Can't connect to the Mac agent from Visual Studio?
    • Choosing the CPU architecture
    • Zebble CLI
    • How to add a Device API to Zebble source?
    • About Automated UI testing
    • What should we test in mobile applications?
    • Creating an Automated UI Test in Zebble



Calling a GET API (in the mobile app)


You can call Api.Get<T>() to invoke a GET based API. The parameters can either be embedded in the url (route) or added as query string. 

await Api.Get<Order[]>("api/v1/orders");

// Or with query string parameter:
await Api.Get<Order[]>("api/v1/orders?from=" + fromDate);

// You can also use an anonymous object for sending query string parameters:
await Api.Get<Order[]>("api/v1/orders", new { from = fromDate, to = toDate, ... });

Caching Get call results

Whenever the server returns a valid response (which is often Json) it will be saved in the application as a local file under  Resources\-ApiCache\[URL-HASH].txt which can then be used in the future when the same URL (i.e. the same API with the same parameters) is called when the network or server is unavailable or there is any error. This allows the application to function in a read-only mode when offline.

Note: In certain scenarios you should delete the cache. For example when logging out, it's very important to delete the cache folder to prevent previous user's data being accidentally revealed to a new user account, and to prevent errors. You can achieve that using the following:

await Api.DisposeCache();

ApiResponseCache parameter

An optional parameter of Api.Get() is called cacheChoice which you can set to any of the following:

  • Prefer: Means if a cache is available, that's preferred and there is no need for a fresh Web Api request.
  • PreferThenUpdate:  If a cache is available, that's returned immediately. But a call will still be made to the server to check for an update, in which case a provided refresher delegate will be invoked.
  • Accept (default): Means a new request should be sent. But if it failed and a cache is available, then that's accepted.
  • AcceptButWarn: Means a new request should be sent. But if it failed and a cache is available, then that's accepted. However, a warning toast will be displayed to the user in that case to say: The latest data cannot be received from the server right now.
  • Refuse: Means only a fresh response from the server is acceptable, and any cache should be ignored.

OnError parameter

Another optional parameter of Api.Get() is called errorAction, which allows you to specify what should happen in case the network or server is down, or there is any problem in processing the response. For example:

await Api.Get<Order[]>("api/v1/orders",  OnError.Ignore);

The default option is to show a Toast.  Learn more about OnError.

Example configurations

If the API responds successfully with no error, the fresh result will always be returned and your extra parameters will be ignored anyway (unless Cache option of Prefer is used). But if an error occurred, then use one of the following options depending on what outcome is acceptable for you:

  • A: Accept the latest cache. If none is available, inform the user to prevent confusion and return null (don't throw):
    return await Api.Get<Order[]>("...");
    // which means the default parameters of:
    return await Api.Get<Order[]>("...", OnError.Toast, ApiResponseCache.Accept);
  • B: Don't accept the cache. Inform the user and return null (don't throw):
    return await Api.Get<Order[]>("...", OnError.Toast, ApiResponseCache.Refuse)
  • C: Don't accept the cache. Just throw. 
    return await Api.Get<Order[]>("...", OnError.Throw, ApiResponseCache.Refuse)
  • D: Accept the latest cache. If none is available, throw:
    return await Api.Get<Order[]>("...", OnError.Throw, ApiResponseCache.Accept)
  • E: Accept the latest cache. If none is available just return null without informing the user:
    return await Api.Get<Order[]>("...", OnError.Ignore)
  • F: If we already have it cached, just use that (fastest option) and don't even send a new request.
    return await Api.Get<Order[]>("...", ApiResponseCache.Prefer);
  • ...

Where to use it?

It's recommended to make all API calls in your business domain or service classes in the App, which will be then called in your UI.

Example:

public class Order
{
     ...
     public static Task<Order[]> GetOrders() => Api.HttpGet<Order[]>("v1/orders");
     ...
}
This simple line is enough to handle all things related to invoking an API including: deserializing the result, handling exceptions, using the latest cache if the network or API server is down, informing the user, ...

In the UI then you can use this as your list module's data source.

<ListView ... DataSource="@await Order.GetOrders()" />

Best practice for fastest UX -> ApiResponseCache.PreferThenUpdate

Imagine a page which uses GET APIs to fetch and show a list of some data. At the first time that you visit that page, fresh data will be downloaded, cached locally and rendered.

In a typical scenario, you will probably go to another page and then back to this page. When you go back, the remote data may or may not have been changed. And you don't know what's the case. So you have to call the Web API for fresh data and wait for the response before rendering the page which will slow things down and annoy the user.

Zebble provides a better way!

  • When calling Api.Get(...) you can select the PreferThenUpdate cache option which makes the framework to immediately return the previously cached data (if available), which makes the page render immediately.
  • It will then also, in parallel, send a fresh request to the server to ask for fresh data.
  • If and only if the returned data is different from its previous cache (from which the UI is already rendered) then the UI will be refreshed to show the updated data. To achieve that you should provide a delegate which will update your UI.

This way every page of your app will be displayed immediately, providing the best user experience. Then if the data was changed, it will then reload the UI to reflect that, often in less than a second.

Example:

...
<ListView z-of="Product, Row" Id="ProductsList" DataSource="Items">
      .....
</ListView>
And in the code behind:

Product[] Items;
bool IsReturnVisitToCachedPage = false;

public override async Task OnInitializing()
{
      Items = await GetOrRefreshDataSource();

      await base.OnInitializing();
      await InitializeComponents();
      ...

    // If the page is cached, every time the user comes back to this page the ShownEvent will be fired (but not OnInitializing).
    // If you specifically don't want the page to be cached, you can remove it.
     await WhenShown(() =>
     {
           if (IsReturnVisitToCachedPage) await GetOrRefreshDataSource();
          else IsReturnVisitToCachedPage = true; // for next time
     });
}

Task<Product[]> GetOrRefreshDataSource()
{
     return Api.Get<Product[]>("api/v1/products", ApiResponseCache.PreferThenUpdate, Refresh);
}
Task Refresh(Product[] items) => WhenShown(() => ProductsList.UpdateSource(Items = items));




‹
Zebble is a product of Geeks Ltd , a software house based in London, UK. All rights are reserved.

Telephone: +44 (0)845 643 6229

Email: hello@zebble.net

Address: 66a London Road, Morden

Greater London, United Kingdom, SM4 5BE

Privacy Statement
Terms & Conditions
Contact Us