Search
Requirements
This guide requires basic knowledge about smart contracts. If you are new to smart contract development, read the Consuming Data Feeds and Random Numbers guides before you begin.
In this guide, you will learn how to request data from a public API in a smart contract. This includes understanding what Tasks and External adapters are and how Oracle Jobs use them. You will also learn how to find the Oracle Jobs and Tasks for your contract and how to request data from an Oracle Job.
Table of Contents
The request and receive cycle describes how a smart contract requests data from an oracle and receives the response in a separate transaction. If you need a refresher, check out the Basic Request Model.
For contracts that use Chainlink VRF, you request randomness from a VRF oracle and then await the response. The fulfillment function is already given to us from the VRFConsumerBase
contract, so oracles already know where to send the response to. However, with API calls, the contract itself defines which function it wants to receive the response to.
Before creating any code, you should understand how Oracle jobs can get data on-chain.
Chainlink nodes require Jobs to do anything useful. In the case of a Request and Receive job, the Direct Request job monitors the blockchain for a request from a smart contract. Once it catches a request, it runs the tasks (both core and external adapters) that the job is configured to run and eventually returns the response to the requesting contract.
Each oracle job has a configured set of tasks it must complete when it is run. These tasks are split into two subcategories:
If a job needs to make a GET request to an API, find a specific unsigned integer field in a JSON response, then submit that back to the requesting contract, it would need a job containing the following Tasks:
method
must be set to GET.Let's walk through a real example, where you will retrieve 24 volumes of the ETH/USD pair from the cryptocompare API.
{"RAW":
{"ETH":
{"USD":
{
...,
"VOLUMEDAYTO":953806939.7194247,
"VOLUME24HOUR":703946.0675653099,
"VOLUME24HOURTO":1265826345.488568
...,
}
}
}
}
JSON Parse walks a specified path
("RAW,ETH,USD,VOLUME24HOUR"
) and returns the value found at that result. Example: 703946.0675653099
Multiply parses the input into a float and multiplies it by the 10^18. Example: 703946067565309900000000
ETH ABI Encode formats the input into an integer and then converts it into Solidity's uint256
format. Example: 0xc618a1e4
ETH Tx takes the given input, places it into the data field of the transaction, signs a transaction, and broadcasts it to the network. Example: transaction result
Note: Some tasks accept parameters to be passed to them to inform them how to run. Example: JSON Parse accepts a path
parameter which informs the task where to find the data in the JSON object.
Let's see what this looks like in a contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
/**
* Request testnet LINK and ETH here: https://faucets.chain.link/
* Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/docs/link-token-contracts/
*/
/**
* THIS IS AN EXAMPLE CONTRACT WHICH USES HARDCODED VALUES FOR CLARITY.
* PLEASE DO NOT USE THIS CODE IN PRODUCTION.
*/
contract APIConsumer is ChainlinkClient {
using Chainlink for Chainlink.Request;
uint256 public volume;
address private oracle;
bytes32 private jobId;
uint256 private fee;
/**
* Network: Kovan
* Oracle: 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8 (Chainlink Devrel
* Node)
* Job ID: d5270d1c311941d0b08bead21fea7747
* Fee: 0.1 LINK
*/
constructor() {
setPublicChainlinkToken();
oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
jobId = "d5270d1c311941d0b08bead21fea7747";
fee = 0.1 * 10 ** 18; // (Varies by network and job)
}
/**
* Create a Chainlink request to retrieve API response, find the target
* data, then multiply by 1000000000000000000 (to remove decimal places from data).
*/
function requestVolumeData() public returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Set the URL to perform the GET request on
request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
// Set the path to find the desired data in the API response, where the response format is:
// {"RAW":
// {"ETH":
// {"USD":
// {
// "VOLUME24HOUR": xxx.xxx,
// }
// }
// }
// }
// request.add("path", "RAW.ETH.USD.VOLUME24HOUR"); // Chainlink nodes prior to 1.0.0 support this format
request.add("path", "RAW,ETH,USD,VOLUME24HOUR"); // Chainlink nodes 1.0.0 and later support this format
// Multiply the result by 1000000000000000000 to remove decimals
int timesAmount = 10**18;
request.addInt("times", timesAmount);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
{
volume = _volume;
}
// function withdrawLink() external {} - Implement a withdraw function to avoid locking your LINK in the contract
}
Here is a breakdown of each component of this contract:
requestVolumeData
functions: This builds and sends a request - which includes the fulfillment functions selector - to the oracle. Notice how it adds the get
, path
and times
parameters. These are read by the Tasks in the job to perform correctly. get
is used by HTTP, path
is used by JSON Parse and times
is used by Multiply.fulfill
function: This is where the result is sent upon the Oracle Job's completion.Note: The calling contract should own enough LINK to pay the specified fee (by default 0.1 LINK). You can use this tutorial to fund your contract.
This is an example of a basic HTTP GET request. However, it requires defining the API URL directly in the smart contract. This can, in fact, be extracted and configured on the Job level inside the Oracle node.
Here are some examples of external adapters:
These external adapters, along with many others, can be found on Chainlink Market.
If all the parameters are defined within the Oracle job, the only things a smart contract needs to define to consume are:
This will make your smart contract much more succinct. The requestVolumeData
function from the code example above would look more like this:
function requestVolumeData() public returns (bytes32 requestId) {
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Extra parameters don't need to be defined here because they are already defined in the job
return sendChainlinkRequestTo(oracle, request, fee);
}
More on External Adapters can be found here.
Create a smart contract that can get sports data using the SportsDataIO oracle job found on Chainlink Market, without having to specify the URL inside the contract.
To consume an API response, your contract should inherit from ChainlinkClient
. This contract exposes a struct called Chainlink.Request
that your contract should use to build the API request.
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract sportContract is ChainlinkClient {
using Chainlink for Chainlink.Request;
}
The request should include the oracle address, the job id, the fee, adapter parameters, and the callback function signature. Create variables for these items using the correct data types.
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract sportContract is ChainlinkClient {
using Chainlink for Chainlink.Request;
address private oracle;
bytes32 private jobId;
uint256 private fee;
}
In the constructor, set up the contract with the Oracle address, Job ID, and LINK fee that the oracle charges for the job.
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract sportContract is ChainlinkClient {
using Chainlink for Chainlink.Request;
// ...
// { previously created variables }
// ...
constructor() {
setPublicChainlinkToken();
oracle = 0xfF07C97631Ff3bAb5e5e5660Cdf47AdEd8D4d4Fd;
jobId = "9abb342e5a1d41c6b72941a3064cf55f";
fee = 0.1 * 10 ** 18; // (Varies by network and job)
}
}
requestData
FunctionThe SportsDataIO job page specifies the request parameters to be date and teamName. To account for this, your requestData
function should have both of these items as parameters. Please refer to the job page to understand the specific input format for these items.
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract sportContract is ChainlinkClient {
using Chainlink for Chainlink.Request;
// ...
// { previously created variables }
// ...
// ...
// { constructor }
// ...
// Initial Request
function requestData(string memory _date, string memory _team) public returns (bytes32 requestId) {
Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
req.add("date", _date);
req.add("teamName", _team);
return sendChainlinkRequestTo(oracle, req, fee);
}
}
The last component of your contract should be the fulfill
function. This is where the sports data is sent upon the Oracle Job's completion. The SportsDataIO job page specifies that the request returns a bytes32
packed string
. You should add a data
variable to your contract to store this result.
Note: Currently, any return value must fit within 32 bytes. If the value is bigger than that, you must make multiple requests.
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract sportContract is ChainlinkClient {
using Chainlink for Chainlink.Request;
bytes32 public data;
// ...
// { previously created variables }
// ...
// ...
// { constructor }
// ...
// ...
// { requestData function }
// ...
// Callback Function
function fulfill(bytes32 _requestId, bytes32 _data) public recordChainlinkFulfillment(_requestId) {
data = _data;
}
}
Your contract is complete and ready to be compiled and deployed. You can see a complete version of the contract in Remix:
If you don't know how to deploy a contract to the Kovan testnet using Remix, follow getting started guide for Deploying Your First Smart Contract. To make a job request, you must have enough LINK to pay for it. Learn how to acquire testnet LINK and fund your contract. Once these steps are completed, you should be able to get sports data.
To learn more about connecting smart contracts to external APIs, read our blog posts:
To explore more applications of external API requests, check out our other tutorials.