Mobile App: Fetching data from Snowpal API Server by calling REST Endpoints

Varun Palaniappan - Feb 21 - - Dev Community

The importance of Design Patterns couldn’t be stressed enough. Be it fundamental design patterns essential to building better software applications in general, or team specific design patterns that specifically span the realm of apps in a company’s ecosystem, it is imperative that every team member is well aware of the variety of patterns available so they can benefit from it.


At Snowpal, we use a number of design patterns that we’ve established to make our engineering lives more productive and we’ll look at one of them here.

Note that providing all of the context to such code snippets will make the article run into tens of pages so in the interest of brevity, we are going to jump right into it.

API & Caching Integration

Snowpal Mobile App integrates some of Snowpal’s APIs and here’s a piece of code that —

  1. Invokes a REST API to fetch content (in this case, Blocks)
  2. Makes the invocation conditionally — only when the results are not already in cache, that is.
 static Future<List<BaseBlockResponse>> fetchBlocks({
    required User user,
    required String keyId,
    required KeyKind keyKind,
    bool aclWriteOrHigher = false,
    int batchNumber = ApiBase.INVALID_BATCH_INDEX,
  }) async {
    final String apiName = BlockCacheApiName[CacheCreate.FetchBlocks]!;

    ///
    Future<dynamic> _fetchBlocks() async => await RestUtil.apiRequest(
      apiName: apiName,
      query: {
        RestUtil.apiParamName(apiName: apiName, paramName: "aclWriteOrHigher"):
        aclWriteOrHigher.toString(),
        ...ApiBase.batchNumberParam(batchNumber: batchNumber, apiName: apiName),
      },
      path: ApiBase.paramSubstitutedPath(apiName: apiName, keyId: keyId),
      user: user,
    );

    final blocks = await BlockCache(
      id: "fetchBlocks",
      apiCallback: _fetchBlocks,
      keyId: keyId,
    ).fetchCache();
    return keyKind.isCollegeKey()
        ? BlockCollection.fetchCollegeBlocksFromJson(json: blocks).blocks
        : BlockCollection.fetchBlocksFromJson(json: blocks).blocks;
  }
Enter fullscreen mode Exit fullscreen mode

The app calls 100s of endpoints as it has a lot of functionality but this design pattern is pretty much replicated so when a new developers joins our team and is implementing a new screen, they can simply mimic this pattern when they integrate a new endpoint that relates to their feature.

The code snippet above relies on a homegrown caching layer that is quite powerful and also, establishes its own design patterns so adding objects to cache, and invalidating them is extremely seamless (not requiring the new member to know any bit about the underlying implementation, that is).

Increased Productivity

The idea behind creating internal design patterns is to make lives much easier for both new and existing developers thereby allowing them to focus on the new feature or enhancement they are working on, and not have them worry about reinventing the wheel every single time. This obviously leads to increased productivity.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player