Looking for a design pattern in JavaScript to manage async requests dealing with success, failure, and retry scenarios?

In the process of developing a mobile application using Appcelerator Titanium, I find myself sending various xhr requests. While this isn't specifically related to Appcelerator Titanium, any code suggestions provided should be in Javascript.

The app requires authentication for certain interactions with the user, among other things.

At this stage, every request may yield different responses such as:

  • not authenticated
  • not logged in
  • invalid parameters
  • successful
  • ...

These requests are enclosed within different model methods or helpers.

However, since this is new territory for me, I'm curious about the best practices to follow.

For instance, some practical questions include:

  • If the app lacks authentication (e.g., token expiration), should it attempt authentication and then resend the denied request? (while keeping the process transparent to the user)

  • Should an authentication request be sent each time the app launches, followed by "forgetting" it?

The issue here is that addressing each request individually leads to lengthy code with nested callbacks, retry logic, event listeners, etc. It doesn't feel efficient or maintainable, as what's necessary is a streamlined approach where any request is checked for errors, rectified automatically if possible (through authentication or automatic login), and retried multiple times before giving up if necessary.

I've heard about the promise pattern but only understand it theoretically, unsure if it aligns with my requirements.

Hence, I would appreciate any guidance on tackling this specific challenge. I'm curious how apps like "Facebook" manage similar scenarios.

Thank you for your assistance.

Answer №1

Finding the right approach to working with APIs can be a challenging task, but allow me to share some insights:

One crucial aspect to consider before diving into coding for your application is the API itself. It must be reliable and compliant with standards. A well-designed RESTful API can simplify the complexity of your httpClient operations significantly by responding with standard http status codes and supporting methods like POST, GET, PUT, DELETE...

If you're interested in further reading on this topic, I recommend checking out George Reese's The REST API Design Handbook.

In my experience with Titanium and httpClients, I prefer using a single module that can be loaded via require() as needed. This helps me avoid issues related to multiple simultaneous calls by ensuring only one client operates at a time. Any incoming call is checked against existing ones, and if necessary, added to a queue.

Let me illustrate this approach with a simplified example:

// lib/customClient.js
var xhrRequest;     // HTTPClient instance
var callQueue = []; // Queue for requests

// Method to register a new request
function registerRequest(params) {
    if(!xhrRequest) {
        sendRequest(params);
    } else {
        queueRequest(params);
    }
}

// Queue up a request for later processing
function queueRequest(params) {
    callQueue.push(params);
}

// Send the actual request with provided params from registration
function sendRequest(params) {
    // Implementation details omitted for brevity
}

// Process any pending requests in the queue
function processQueue() {
    xhrRequest = null;
    var nextInQueue = callQueue.shift();
    if(nextInQueue) sendRequest(nextInQueue);
}

// Public API exposed by the module
var publicAPI = {
    sendRequest: function(params) {
        registerRequest(params);
    }
};

module.exports = publicAPI;

You can then make a request from any controller or view in your application:

var customClient = require('lib/customClient');

// Initiate a request
customClient.sendRequest({
    method: 'GET',
    url: 'http://test.com/api/v1/user/1',
    done: function(response) {
        Ti.API.debug(JSON.stringify(response));
    }
});

It's worth noting that this is just a starting point and lacks thorough validation, error handling, connectivity checks, and other essential features. Nonetheless, it serves as a foundation to build upon and refine your understanding of the process.

While there's much more to explore on this subject, I'll conclude here for now...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Failure in querying with Mongo's $lookup results in an empty array

My $lookup operation on schemas is always returning an empty array. What could be causing this issue? Result Collection const resultSchema = new mongoose.Schema({ trial: { type: mongoose.Schema.Types.ObjectId, ref: 'Trial', requir ...

Bootstrap Thumbnail Grid - dynamic loading with ajax

Situation: I am facing a challenge where I have a view displaying countries in a twitter bootstrap thumbnail grid. Upon clicking an image, the intention is to dynamically show cities related to that particular country within the same grid on the screen. T ...

Show or hide the sibling element of the current element without using a specific identifier in jQuery

I am looking to make div.edit-button toggle its corresponding sibling div.additionalFieldForm. There are multiple instances of both on the page, so I want to target only the pair that are related within the same group. If a div.edit-button is clicked, the ...

The issue with getting a token from Next-auth on the server side persists

Currently, I am working on an application using Next.js and implementing authentication with NextAuth. However, I am encountering an issue with the getToken function not working properly on the server-side. I have double-checked my callbacks configuration ...

What steps can be taken to restrict a user's access to the main page unless they are logged in?

I have created sign up and login pages using JavaScript, HTML, and PHP with a database. After a user successfully logs in on the login page, the following code is executed: sessionStorage.setItem('logged','loggedIn'); The user is then ...

Troubleshooting in ReactJS and NodeJS: Understanding the "Pass --update-binary to reinstall or --build-from-source to recompile" error

After moving a ReactJS + NodeJS project from one computer to another, I attempted to install dependencies by running npm install in the terminal. However, I received the following response: > [email protected] install /Users/Joshua/Projects/practi ...

Verify the changing text within a Span tag with the use of Selenium in Java

Can anyone assist me in creating a logic to verify a dynamic text? The text within the tag below is constantly changing (to 6 distinct words), and I need to validate if those 6 unique words match the expected text. Is there a method to do this verification ...

What is the purpose of deserializing the user for every request using PassportJS?

While I have scoured the official documentation and various online resources, I am still unable to find a solution to what seems like an obvious question. When working with Passport.js, it is necessary to define two methods - one for serializing and one f ...

Accessing CouchDB using AngularJS requires users to sign in, with the authentication cookie only being sent to the `/_

Check out my previous posts on this topic here: 1, 2 I currently have an AngularJS app with two controllers. The first one interacts with CouchDB documents, while the second handles sign-in requests to example.com/demo/_session. Upon opening the applicat ...

Don't give up on the entire task just because one promise was rejected

To handle multiple promises in redux saga, you can use the all function (equivalent to Promise.all): yield all( users.map((user) => call(signUser, user)), ); function* signUser() { yield call(someApi); yield put(someSuccessAction); } An issue ...

Tips for connecting multiple queries in Neo4j through the NodeJS driver and combining data into a new property

In my NodeJS project, I am developing an import function for a list of tagged elements in Javascript object format. This list may contain duplicates as it is a combination from multiple sources. Here is an example list (from test.json): [ ... ] The ...

Use percentages for the width in CSS and pixels for the height, ensuring that both dimensions are equal

I'm attempting to create a square that adjusts its size according to the screen size. Currently, I have the width set to 25%. Is there a way to ensure that the height remains the same length in pixels as the width? Appreciate any assistance on this ...

Trouble activating header checkbox on initial click

Hello everyone, I have a question about two views: 1- Index 2- Edit In my grid, the header has a single checkbox. When I try to click the checkbox to select all rows, it doesn't work properly. The first time I click to uncheck and then check it agai ...

Refrain from using inline JavaScript code within your

Here is the basic structure of my code: <a href="javascript:void(0);" onClick="viewServices(1)">Services</a> <a href="javascript:void(0);" onClick="viewServices(43)">Services</a> <a href="javascript:void(0);" onClick="viewServic ...

Employing the `instanceof` operator on instances generated by constructors from complex npm dependencies

Context: In one of my npm modules, I've implemented error handling code with a custom error type called CustomError: function CustomError () { /* ... */ } CustomError.prototype = Object.create(Error.prototype); CustomError.prototype.constructor = Cu ...

What is the best way to fix the Syntax error that reads "Unexpected token (1:13)"?

I can't seem to figure out why my code keeps showing errors in the browser. I'm still new to coding and learning slowly, with help from knowledgeable individuals on stackoverflow :) Card 1.jsx Syntax error:() Unexpected token (1:13) > 1 | i ...

The PHP jQuery AJAX request fails to increase the variable's value in the AJAX success function

I am facing an issue where I need to increment the value of a variable by one in the success callback of an AJAX call. Despite using a specific script for this purpose, the variable's value remains constant and does not increase as expected. jQuery(" ...

What is the best way to smoothly transition from one video to another with a simple click?

I am looking to enhance my website by implementing a feature where a video will play when a button is clicked, and then another video will smoothly fade in while fading out the current video upon clicking a different button. This transition should dynamica ...

Submitting incomplete values from a Jquery form to a MySQL database

I'm having an issue with my IntelXDK HTML5 mobile app where the form is submitting empty values to the MySQL database. Here is the HTML code for my single file app: <label class="item item-input widget uib_w_6 d-margins" data-uib="ionic/input" da ...

Enhance and modify data with AngularJS, while also incorporating new information into the

Working on a feature where Worklists can be added and edited or deleted from local storage. Encountering an issue where after editing a worklist, it cannot be added anymore as it updates the existing worklist data that was selected for editing. (the edite ...