Forum Discussion
Hi I am looking for some help with an irule that can call out to an api
- Jul 12, 2023
irules is not good at parsing JSON key value in HTTP Payload, Initiating HTTPS connections on irules' sideband is also cumbersome
I suggest you use irules and cooperate with iRulesLX to initiate a sideband https connection using node.js,Node.js can use its built-in JSON library to handle JSON, which is very advantageous
As juergen said, I'd script a procedure that calls API via a sideband connection.
You can use this as a starting point: (it's a working code that I'm running on a customer)
edit : if you want to debug it, i'd recommend logging $payload value to understand better what the api is returning
from there you can use string operators syntax to match the intended KV pair and estract the value
when RULE_INIT {
set static::calls_timeout 5
set static::first_recv_timeout 50
set static::first_recv_tries 25
}
proc apicall {ip port uri} {
set api_res ""
set retries 0
set api_req "GET $uri HTTP/1.1\r\nUser-Agent: F5 API service\r\nHost: TBD\r\n\r\n"
set api_conn [connect -timeout $static::calls_timeout -status conn_status $ip:$port]
if {[send -timeout $static::calls_timeout $api_conn $api_req]} {
while {$retries < $static::first_recv_tries} {
set api_res [recv -timeout $static::first_recv_timeout -status recv_status $api_conn]
if {$api_res ne ""} {
if {[string match -nocase "*Content-Length: *" $api_res]} {
set header_len [expr {[string first "\r\n\r\n" $api_res] + 4}]
set payload_len [findstr [string tolower $api_res] "content-length: " 16 "\r"]
set api_res_len [string length $api_res]
if {$payload_len ne "" and $payload_len > 0 and [expr {$header_len + $payload_len}] != $api_res_len} {
set api_res "$api_res[recv -peek -timeout $static::calls_timeout [expr {$header_len + $payload_len - $api_res_len}] $api_conn]"
set api_res_len [string length $api_res]
}
}
set payload [string range $api_res $header_len $api_res_len]
#the two lines below are used to match a string in response. In this example i want to retrieve VALUE from key KEY, formatted as {"KEY":"VALUE"} in response
set search_start [string first "\{" $payload]
set api_res_ret [string trim [string map {"\{\"KEY\":" ""} [string range $payload $search_start [expr {[string first "," $payload $search_start] - 1}]]] "\""]
break
} else {
set retries [expr {$retries + 1}]
log local0.debug "No response after $retries retries, T= [expr {$retries * $static::first_recv_timeout}]ms."}
set api_res_ret "FAILED"
}
}
}
close $api_conn
return $api_res_ret
}
when HTTP_REQUEST {
# < your code here >
# set token [HTTP::header Authorization]
# set uri "/api/scim/Me?attributes=$token"
set key [call apicall $api_ip $api_port $uri]
if {$key eq "FAILED"}{
# api call failed, do something
} else {
# < your code here >
HTTP::header replace Authorization ""
HTTP::header replace User-ID $euid
HTTP::header replace User-IDType "SYSTEMLOGIN"
}
}
Personally, it is recommended to use irules in conjunction with iRulesLX. Using iRulesLX to initiate HTTPS sideband connections and handle JSON is simple, while the official TCL super HTTPS sideband connection code is too long, which affects device performance.
Your code appears to be an http sideband, not an encrypted https sideband
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com