Backend responses in adapters
Understand the logic of invocation results both on the client side and inside adapters helps you handle different failure scenarios.
HTTP adapter flow
For a general description of an adapter flow, see Overview of MobileFirst adapters. The following sections explain how to handle backend responses in the case of an HTTP adapter. A typical HTTP adapter flow might involve the following sequence of events:
- The client (that is, the mobile app) uses the invokeProcedure method of the WL.Client class to invoke one of the adapter's procedures from the MobileFirst Server.
- The adapter then uses the invokeHttp method of the WL.Server class to call the backend service.
- The adapter procedure processes the data from the backend and returns a JSON object to the client.
- The client calls its onSuccess handler to process the data received by the adapter.
Responses from the invoke procedure
The adapter flow starts with a WL.Client class invokeProcedure call, which supports onSuccess and onFailure handlers. Both handlers receive an object, which is a standard JSON object. The following table describes some of its properties:
Property Description isSuccessful Whether the procedure call is successful.
The text following the table explains the circumstances when a request is considered to be successful.
status HTTP status code from the procedure call. This is not the HTTP code from the backend service, only from the connection with the MobileFirst Server. errorCode A possible error code if the call is not successful. errorMsg A possible error message if the call is not successful. invocationContext An optional object that is sent in the procedure call and is returned as-is. invocationResult JSON object that is returned by the procedure call. This object may be augmented with additional data such as session information. Which handler is called depends on the value of the isSuccessful property in the invocation result:
- If isSuccessful is set to true, onSuccess is called.
- If isSuccessful is set to false, onFailure is called.
As long as the adapter returns something, the procedure invocation is considered successful and so the isSuccessful property is set to true. The isSuccessful property is set to false under the following circumstances:
- When calling a procedure that does not exist.
- When calling an adapter that does not exist.
- When the MobileFirst Server is unresponsive (for example, due to a bad hostname or because the MobileFirst Server is currently unavailable).
- When the invocation times out (we can set a timeout value as one of the invokeProcedure options).
- When the adapter throws an exception.
- When the code in the procedure specifically overwrites the onSuccess property.
The isSuccessful property is set to false if there is a connection issue between the client and the adapter; not if there is an error in the backend service. This means, for example, that if the procedure calls a backend service which returns an error (such as a "404" error) but the procedure still returns a valid JSON object, the procedure invocation is still considered to be successful from the perspective of the client. If we simply return the result of invokeHttp straight to the client, since you are returning something, isSuccessful is true by default and onSuccess is called. This may or may not be what to happen. You need to make sure the procedure code is capable of handling cases when a backend service returns an error.
Invocations from the adapter to the backend
From your procedure, you call a remote backend service using the invokeHttp method of the WL.Server class. The returned object from this call is a JSON object that represents the result of the HTTP request. If the response is an XHTML or XML tree, it is converted to JSON. For example, if the response is an HTML page, you see a property called "html" (the root HTML tag) with the content tree inside.
The following table describes some of the other properties. Additional arbitrary properties might also be returned by the backend service.
Property Description errors Array of errors during the request. isSuccessful Boolean value summarizing whether the request is successful.
The text following the table explains the circumstances when a request is considered to be successful.
responseHeaders JSON object representing the different HTTP headers of the response. responseTime HTTP response time. statusCode HTTP status code of the remote invocation. statusReason Short text description that explains the status code. totalTime Response time plus any additional time for MPF to complete processing or convert formats. Similar to the client side, if isSuccessful is set to true, the data that you receive is not necessarily exactly what you expect. It merely indicates that something was returned. We can therefore assume that isSuccessful is true by default. This includes the following cases:
- The remote HTTP server returns an OK status code such as 200.
- The remote HTTP server returns any valid status code such as 2XX, 3XX, 4XX. 5XX, and other codes.
The isSuccessful property is set to false under the following circumstances:
- The HTTP host cannot be reached or is invalid.
- The HTTP request has timed out.
Because isSuccessful is set to true by default, you might not receive the data you want or expect. For example, you might want a "404" error to be treated as a failure whereasIBM MobileFirst Platform Foundation considers it a success. We can use properties such as the statusCode property that is returned in the result of a WL.Server.invokeHttp call (or any other interesting data from the response) to decide if the procedure should be considered successful or not. Then handle situations that should be considered unsuccessful in one of the following ways:
- Overwrite the isSuccessful property by setting its value to false in the JSON response.
- Consider the request as successful, set some custom flags in your JSON response, and handle the situation in the client's onSuccess handler. You might also want to place a try/catch block around the procedure code and handle any exceptions accordingly. If an exception is thrown, the client will receive an isSuccessful response set to false.
In a production environment, returning the result of the invokeHttp call back to the client might not be the ideal value to return at the end of the procedure for the following reasons:
- The meaning of a "successful" request might vary in different cases.
- The backend response might include additional data that should not be forwarded to the client; such as certain response headers, architecture of the backend, or any data that is not relevant to the logic of the app. Instead, consider building a new JSON object with our own data, which might possibly include parts of the original response.
Example
Here is an example of an adapter that receives a "404" error as a result of trying to get data from an invalid URL: www.ibm.com/no-such-place.
- adapt.xml
This file can be generated from the Design view in MobileFirst Studio. The backend hostname is set to www.ibm.com.
<?xml version="1.0" encoding="UTF-8"?> <wl:adapter name="adapt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wl="http://www.ibm.com/mfp/integration" xmlns:http="http://www.ibm.com/mfp/integration/http" <displayName>adapt</displayName> <description>adapt</description> <connectivity> <connectionPolicy xsi:type="http:HTTPConnectionPolicyType"> <protocol>http</protocol> <domain>www.ibm.com</domain> <port>80</port> </connectionPolicy> </connectivity> <procedure name="test"/> </wl:adapter>
- adapt-impl.js
This is the implementation of the procedure. It calls a remote URL and generates a response. If the HTTP status code is anything other than 200, the isSuccessful property is set to false.
function test(){ var input = { method : 'get', path : 'no-such-place' //Replace this with a valid path to see success var backendResponse = WL.Server.invokeHttp(input); var procedureResponse = {}; if(backendResponse.isSuccessful && backendResponse.statusCode == 200){ //For simplicity, considering only 200 as valid //Do something interesting with the data procedureResponse.interestingData = backendResponse.html.head.title; else{ procedureResponse.isSuccessful = false; //Overwrite to failure return procedureResponse; }
- main.js
The client app invokes the procedure. If the request is successful, the app logic continues. If the request is not successful, an error message is displayed.
WL.Client.invokeProcedure({ adapter : 'adapt', procedure : 'test' }, { onSuccess : function(result) { //Do something interesting with resulting JSON $('#someDiv').html(result.invocationResult.interestingData); }, onFailure: function(result){ WL.SimpleDialog.show("Error","The service is temporarily not available. Please try again later.",[{text: "OK"}]); });
Parent topic: Develop the server side of a MobileFirst application