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"
}
}
Thanks , I will try this out in my test environment and see how it works.
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