Difference between revisions of "API calls"

From Halon, SMTP software for hosting providers
Jump to: navigation, search
(Query external sources using REST)
Line 4: Line 4:
 
The combination of [http://docs.halon.se/hsl/functions.html#json_decode json_decode()], [http://docs.halon.se/hsl/functions.html#http http()] and the [http://docs.halon.se/hsl/structures.html#cache cache]'s <tt>update_function</tt> allows us to create very fast and resilient API call functions. The example below uses a normal (short) cache for performance, and a "long term" cache for resilience, in case the API is down. It uses the [http://docs.halon.se/hsl/functions.html#rate rate()] function to determine if the API takes too long to answer, in order to ensure high performance even if the API is slow. If more than 10 requests during the last 5 minutes took more than 1 second to finish, or it fails to verify the response with [http://docs.halon.se/hsl/functions.html#is_array is_array()], the value in the long-term cache is returned instead. In other words; the code below assumes that the result is always a JSON array.  
 
The combination of [http://docs.halon.se/hsl/functions.html#json_decode json_decode()], [http://docs.halon.se/hsl/functions.html#http http()] and the [http://docs.halon.se/hsl/structures.html#cache cache]'s <tt>update_function</tt> allows us to create very fast and resilient API call functions. The example below uses a normal (short) cache for performance, and a "long term" cache for resilience, in case the API is down. It uses the [http://docs.halon.se/hsl/functions.html#rate rate()] function to determine if the API takes too long to answer, in order to ensure high performance even if the API is slow. If more than 10 requests during the last 5 minutes took more than 1 second to finish, or it fails to verify the response with [http://docs.halon.se/hsl/functions.html#is_array is_array()], the value in the long-term cache is returned instead. In other words; the code below assumes that the result is always a JSON array.  
 
<hsl type="include">
 
<hsl type="include">
// Wrapper function, manages the short- and long-term caches
+
echo api_call("?Adfafd", ["123"]);
function api_call($query, $args) {
 
$data = cache ["ttl_function" => api_call_ttl, "size" => 100000, "update_function" => api_call_update ] api_call_http($query, $args);
 
return $data;
 
}
 
  
// The actual API call function
+
// API call function
function api_call_http($query, $args) {
+
function api_call($query, $args)
$apiurl = "http://api.example.com/halon?api-key=Zu97uDyS9QeufBId";
+
{
$httpoption = ["timeout" => 5];
+
    $apiurl = "http://api.example.com/halon?api-key=Zu97uDyS9QeufBId";
// Bail out if the API is considered too slow
+
    $httpoption = ["timeout" => 5];
if (rate("api_call_http", serial(), 0, 300) >= 10)
 
return;
 
$t1 = executiontime();
 
// Perform the actual API call
 
$ret = http($apiurl.$query, $httpoption, $args);
 
// Measure the API response time
 
$time = executiontime() - $t1;
 
if ($time > 1)
 
rate("api_call_http", serial(), 10, 300);
 
return json_decode($ret);
 
}
 
  
// Cache helper function, referenced in api_call()
+
    return cache [
function api_call_update($old, $new) {
+
                    "ttl_function" => function($result) {
// Update the long-term cache and return the new value, if the response is valid...
+
                            if (!is_array($result))
if (is_array($new))
+
                                return 60; /* cache short time */
return $new;
+
                            return 3600;
// Otherwise use the old value from the long-term cache
+
                        },
cache [] syslog("crit", "api_call: Invalid response, using long-term cache");
+
                    "size" => 100000,  
return $old;
+
                    "update_function" => function($old, $new) {
 +
                            $new = json_decode($new);
 +
                            if (is_array($new)) /* expect array from API */
 +
                                return $new;
 +
                            cache [] syslog("crit", "api_call: Invalid response, using long-term cache");
 +
                            return $old;
 +
                        }
 +
    ] timed_call(http, $apiurl.$query, $httpoption, $args);
 +
    return $data;
 
}
 
}
  
// Cache helper function, referenced in api_call()
+
// The timed call (helper) function, it expects the execution to take less than 1 sec
function api_call_ttl($result) {
+
// if it exceeds that for more than 10 times in the last 5 minutes, it should
// Set the short-term cache TTL to 1 hour, if the response is valid
+
// return an empty response.
if (!is_array($result))
+
//
return 60;
+
function timed_call($function, ...$args)
return 3600;
+
{
 +
    if (rate("timed_call:" . serial(), $function, 0, 300) >= 10)
 +
        return; // function call was slow
 +
    $t1 = executiontime();
 +
    $ret = $function(...$args); // Call the function
 +
    $time = executiontime() - $t1;
 +
    if ($time > 1)
 +
        rate("timed_call:" . serial(), $function, 10, 300);
 +
    return $ret;
 
}
 
}
 
</hsl>
 
</hsl>

Revision as of 02:49, 21 February 2018

One of the most powerful features of the Halon platform is the HSL scripting language, which enables you tailor and integrate the system to perfection.

Query external sources using REST

The combination of json_decode(), http() and the cache's update_function allows us to create very fast and resilient API call functions. The example below uses a normal (short) cache for performance, and a "long term" cache for resilience, in case the API is down. It uses the rate() function to determine if the API takes too long to answer, in order to ensure high performance even if the API is slow. If more than 10 requests during the last 5 minutes took more than 1 second to finish, or it fails to verify the response with is_array(), the value in the long-term cache is returned instead. In other words; the code below assumes that the result is always a JSON array.

Include file
echo api_call("?Adfafd", ["123"]);

// API call function
function api_call($query$args)
{
    
$apiurl "http://api.example.com/halon?api-key=Zu97uDyS9QeufBId";
    
$httpoption = ["timeout" => 5];

    return 
cache [
                    
"ttl_function" => function($result) {
                            if (!
is_array($result))
                                return 
60/* cache short time */
                            
return 3600;
                        },
                    
"size" => 100000
                    
"update_function" => function($old$new) {
                            
$new json_decode($new);
                            if (
is_array($new)) /* expect array from API */
                                
return $new;
                            
cache [] syslog("crit""api_call: Invalid response, using long-term cache");
                            return 
$old;
                        }
    ] 
timed_call(http$apiurl.$query$httpoption$args);
    return 
$data;
}

// The timed call (helper) function, it expects the execution to take less than 1 sec
// if it exceeds that for more than 10 times in the last 5 minutes, it should
// return an empty response.
//
function timed_call($function, ...$args)
{
    if (
rate("timed_call:" serial(), $function0300) >= 10)
        return; 
// function call was slow
    
$t1 executiontime();
    
$ret $function(...$args); // Call the function
    
$time executiontime() - $t1;
    if (
$time 1)
        
rate("timed_call:" serial(), $function10300);
    return 
$ret;

Below is an example of how the api_call() function can be used; as domain-based routing in the pre-delivery context:

include "file:X";
if (
$transportid == "mailtransport:1") {
    
// Should use API routing
    
$route api_call("&type=route&recipientdomain=$1", [$recipientdomain]);
    if (!isset(
$route["dest"]))
        
Reschedule(3600, ["reason" => "No route""increment_retry" => false]);
    
SetDestination($route["dest"], number($route["port"]));
    if (
$route["sasl_user"])
        
SetSASL($route["sasl_user"], $route["sasl_pass"]);