Handling API Responses in Oracle Requests
When interacting with off-chain APIs via an Oracle in a smart contract, it’s important to properly handle how the response is processed. This guide will walk through how to use jsonResponsePath
to dynamically specify the path to the desired data within a JSON response from an API.
Overview
In a decentralized environment, once an Oracle request is made, the response needs to be processed and relayed back to the smart contract. This process often involves navigating through a structured JSON response returned by an external API.
To handle this, we use jsonResponsePath
, which allows us to specify the key or path where the relevant data is located within the JSON response.
This is especially useful when the response is complex or nested, as it gives us the ability to extract specific values.
Setting jsonResponsePath
in Requests
Here’s how you can define the jsonResponsePath
within your smart contract when sending a request to an Oracle.
Example: Sending a GET Request
function exampleSendRequestGET(uint256 fulfillGasUsed) external payable nonReentrant {
uint256 gasCost = gasCostFulfill(fulfillGasUsed);
require(
msg.value > gasCost,
"ETH sent is less than gas cost for the callback"
);
string memory url = "http://api.example.com/data";
OracleRequest.Request memory req;
req.url = url; // Define the API endpoint
req.method = "GET"; // Specify the HTTP method
req.jsonResponsePath = "data.clientId"; // Path to extract from JSON response
bytes memory requestData = req.encodeCBOR();
uint256 requestId = _sendRequest(requestData, fulfillGasUsed);
// Store any relevant information about the request, such as the requestId
}
How It Works:
req.jsonResponsePath
: This is where we specify the path within the JSON response where the data we need is located. In this case, we are extracting theclientId
from a nested JSON object, i.e.,"data.clientId"
.
For example, if the API response looks like this:
{
"data": {
"clientId": 12345,
"clientName": "John Doe"
}
}
In this case the path data.clientId will return 12345.
Handling Arrays in JSON Response
If the API response contains an array, and you need to access a specific index, you can modify the jsonResponsePath
to point to the exact index within the array.
For example, consider the following API response:
{
"data": {
"clientId": [111, 222, 333, 444, 555],
"clientName": "John Doe"
}
}
If you need to extract the value at index 3 from the clientId array (which is 444 in this case), you can set the jsonResponsePath like this:
req.jsonResponsePath = "data.clientId[3]";
- data.clientId: This navigates to the
clientId
array within the JSON structure. - [3]: Specifies the index of the array element you want to retrieve. In this case, it's the 4th element (444), since array indices start at 0.
By specifying the path in this format, the Oracle will extract the correct value from the array and return it to your contract.
Or consider this other API response example:
[
{ "clientId": 111, "clientName": "John Doe" },
{ "clientId": 222, "clientName": "Jane Doe" },
{ "clientId": 333, "clientName": "Sam Smith" },
{ "clientId": 444, "clientName": "Alex Johnson" }
]
If you need to extract the clientId value from the object at index 3 (which is 444 in this case), you can set the jsonResponsePath
like this:
req.jsonResponsePath = "[3].clientId";
- [3]: This specifies the index of the object in the array from which you want to retrieve the clientId. In this case, it's the 4th object (444), since array indices start at 0.
- .clientId: This accesses the clientId property of the specified object.
Allowed Responses from Oracle
- uint256
- boolean
- string
- bytes
- float --- will return bytes of uint256 (ex.if response is 3.5 oralce will return 3500000000000000000)
Handle float Responses
To accept float-type responses, the procedure will be as follows:
In the request object of your contract, you must specify allowFloatResponse
req.allowFloatResponse = true
Note: VERY IMPORTANT: If you pass
req.allowFloatResponse=true
, both floats and uints will be multiplied by the oracle by 10**18 before returning the response. This will apply to both uint256 and floats.