4.2.2.15.2. HTTP Client Common Patterns
Passing on authentication information
When using the call authentication of type "OAuth2.0 With Credentials" then you can extract the token from the authentication response and reuse it. To do that, have a look at the configuration below and adapt it to your setup:
At the bottom of the form, an option allows you to extract metadata from the response:
The script would look something like this depending on the exact format of the JSON your service returns:
JSON.parse(loginResponseContent).access_token
loginResponseContent is one of the predefined variables the HTTP client gateway provisions for you.
Next, add your token to your headers:
Iterating over lists
When setting up an HTTP flow, you will likely run into the need to iterate over lists of data. This is an example of such a setup:
In the above flow, we will iterate over a list of items. The first call will request the list of invoices. The second one will fetch an invoice. The third call will update the invoice to indicate it has been processed.
In this pattern:
- Call 1 lists the items to fetch. You then need to initialize variables to save the remaining information:
The first variable will contain the entire list you recuperate from your content.
The second variable will keep track of the position you're at in that list. It starts at 0 and will count your processed invoices as you go through the list.
The third variable will initialize the next invoice to process if any.
The "Next Step" will check if there are invoices to process at all, and if so, will move on to fetching them:
- Call 2 fetches an item of your list based on the variables set in the first call:
This time, your URL is scripted, it contains a reference to the variable you previously set with the value of the invoice to fetch. Once your call completes, you will likely create a message with its response content:
Finally, you will move to the next step which will update your invoice to indicate it has been processed:
- Call 3 Updates your list item and calculates the next item to fetch if applicable.
Still using your nextInvoice variable, you will typically use a POST or PATCH request:
The important part of this step is to update your variables after running your update:
You want to save your currentInvoice value, update your counter value, and calculate your nextInvoice before fetching it.
You may additionally want to create a babelway message if the update does not result in a 200 (successful update) in order to send an email to an administrator for example etc.
Your next step will then go back to GetInvoice or stop if you've reached the end of your list:
Handling pagination
You can use this same mechanism to handle pagination for example, iterating over pages, and calculating your next page.
Note that for pagination you can also rely on scheduling. In the above example, we will fetch 5 invoices at a time. At the next run the gateway will fetch the next 5 invoices etc. Depending on your traffic this may be a simpler and more robust approach than iterating pages of lists of items.
Example
You can upload this sample flow file to an HTTP client gateway in order to preview this setup:
<?xml version="1.0" encoding="UTF-8"?>
<HttpGatewayClientFlow>
<Calls>
<Call>
<Name>ListInvoice</Name>
<Method>GET</Method>
<Url type="ConstantExpression">https://example.suitetalk.api.netsuite.com/services/rest/record/v1/invoice?limit=5&offset=0</Url>
<PostAction>
<CreateMessage>
<Content type="ScriptExpression">responseContent</Content>
<ResponseFileName type="ConstantExpression">invoiceList.json</ResponseFileName>
<SetMetadatas>
</SetMetadatas>
</CreateMessage>
<NextStep type="ScriptExpression">if(invoiceList.length>0) 'GetInvoice' else ''</NextStep>
<Variables>
<Variable>
<Name>invoiceList</Name>
<Value type="ScriptExpression">JSON.parse(responseContent).items</Value>
</Variable>
<Variable>
<Name>invoiceCounter</Name>
<Value type="ScriptExpression">0</Value>
</Variable>
<Variable>
<Name>nextInvoice</Name>
<Value type="ScriptExpression">if(invoiceList.length>0) invoiceList[0].id else 'na'</Value>
</Variable>
</Variables>
<Wait>0</Wait>
<Validate>
<ApplyRetryStrategy>false</ApplyRetryStrategy>
</Validate>
<SetMetadatas>
</SetMetadatas>
</PostAction>
<Authentication>
<PreemptiveAuthentication>false</PreemptiveAuthentication>
<HttpAuthenticationHeaders>
</HttpAuthenticationHeaders>
<MetadataFromLoginResponse>
</MetadataFromLoginResponse>
<AuthFormFields>
</AuthFormFields>
<UsedGlobalAuthentication>true</UsedGlobalAuthentication>
</Authentication>
<Wait>0</Wait>
<Headers>
</Headers>
<Timeout>90000</Timeout>
<PostExtraParameters>
</PostExtraParameters>
</Call>
<Call>
<Name>GetInvoice</Name>
<Method>GET</Method>
<Url type="ScriptExpression">"https://example.suitetalk.api.netsuite.com/services/rest/record/v1/invoice/"+nextInvoice+"?expandSubResources=true"</Url>
<PostAction>
<CreateMessage>
<Content type="ScriptExpression">responseContent</Content>
<ResponseFileName type="ScriptExpression">'invoice'+nextInvoice+'.json'</ResponseFileName>
<SetMetadatas>
</SetMetadatas>
</CreateMessage>
<NextStep type="ConstantExpression">UpdateReceivedFlag</NextStep>
<Wait>0</Wait>
</PostAction>
<Authentication>
<PreemptiveAuthentication>false</PreemptiveAuthentication>
<HttpAuthenticationHeaders>
</HttpAuthenticationHeaders>
<MetadataFromLoginResponse>
</MetadataFromLoginResponse>
<AuthFormFields>
</AuthFormFields>
<UsedGlobalAuthentication>true</UsedGlobalAuthentication>
</Authentication>
<Wait>0</Wait>
<ValidReturnCodes type="ConstantExpression">200,201,202,204,205,401,503,404</ValidReturnCodes>
<Headers>
</Headers>
<Timeout>90000</Timeout>
<PostExtraParameters>
</PostExtraParameters>
</Call>
<Call>
<Name>UpdateReceivedFlag</Name>
<Method>PATCH</Method>
<Url type="ScriptExpression">'https://example.suitetalk.api.netsuite.com/services/rest/record/v1/invoice/'+nextInvoice</Url>
<PostAction>
<CreateMessage>
<Content type="ScriptExpression">"{'invoice': "+currentInvoice+", 'step': 'UpdateReceivedFlag', 'responseContent':"+ responseContent +"}"</Content>
<Condition type="ScriptExpression">responseCode != 204</Condition>
<ResponseFileName type="ScriptExpression">currentInvoice+"UpdateError.json"</ResponseFileName>
<SetMetadatas>
<SetMetadata>
<Name type="ConstantExpression">step</Name>
<Value type="ConstantExpression">UpdateReceivedFlag</Value>
</SetMetadata>
<SetMetadata>
<Name type="ConstantExpression">invoice</Name>
<Value type="ScriptExpression">currentInvoice</Value>
</SetMetadata>
</SetMetadatas>
</CreateMessage>
<NextStep type="ScriptExpression">if(nextInvoice!= 'na') 'GetInvoice' else ''</NextStep>
<Variables>
<Variable>
<Name>currentInvoice</Name>
<Value type="ScriptExpression">nextInvoice</Value>
</Variable>
<Variable>
<Name>invoiceCounter</Name>
<Value type="ScriptExpression">invoiceCounter + 1</Value>
</Variable>
<Variable>
<Name>nextInvoice</Name>
<Value type="ScriptExpression">if(invoiceList.length>invoiceCounter) invoiceList[invoiceCounter].id else 'na'</Value>
</Variable>
</Variables>
<Wait>0</Wait>
<Validate>
<ApplyRetryStrategy>false</ApplyRetryStrategy>
</Validate>
<SetMetadatas>
</SetMetadatas>
</PostAction>
<Authentication>
<PreemptiveAuthentication>false</PreemptiveAuthentication>
<HttpAuthenticationHeaders>
</HttpAuthenticationHeaders>
<MetadataFromLoginResponse>
</MetadataFromLoginResponse>
<AuthFormFields>
</AuthFormFields>
<UsedGlobalAuthentication>true</UsedGlobalAuthentication>
</Authentication>
<Wait>0</Wait>
<ValidReturnCodes type="ConstantExpression">204,400</ValidReturnCodes>
<Headers>
<Header>
<Name>Content-Type</Name>
<Value type="ConstantExpression">application/json;charset=UTF-8</Value>
</Header>
</Headers>
<Content type="ConstantExpression">{ "custbody_te_cust_received_order": true}</Content>
<Timeout>90000</Timeout>
<PostExtraParameters>
</PostExtraParameters>
</Call>
</Calls>
<Session>
<Authentication>
<HttpAuthenticationType>OAUTH1</HttpAuthenticationType>
<PreemptiveAuthentication>false</PreemptiveAuthentication>
<TrustLevel>STANDARD</TrustLevel>
<Oauth1SignatureMethod>HmacSHA256</Oauth1SignatureMethod>
<Oauth1Token>sampleOAuth1Token</Oauth1Token>
<Oauth1TokenSecret></Oauth1TokenSecret>
<Oauth1ConsumerKey>sampleOAuth1ConsumerKey</Oauth1ConsumerKey>
<Oauth1ConsumerSecret></Oauth1ConsumerSecret>
<Oauth1Realm>EXAMPLE</Oauth1Realm>
<HttpAuthenticationHeaders>
</HttpAuthenticationHeaders>
<MetadataFromLoginResponse>
</MetadataFromLoginResponse>
<AuthFormFields>
</AuthFormFields>
<UsedGlobalAuthentication>false</UsedGlobalAuthentication>
</Authentication>
</Session>
<ScriptLanguage>
<Name>JS</Name>
</ScriptLanguage>
<Init>
<Variables>
</Variables>
</Init>
<IsBasic>false</IsBasic>
</HttpGatewayClientFlow>