Search
This guide explains how to make an HTTP GET request to an external API from a smart contract, using Chainlink's Request & Receive Data cycle. External adapters are services which the core of the Chainlink node communicates via its API with a simple JSON specification. Refer to External Adapters Introduction for more information on external adapters and how to build them.
Smart contracts should inherit from ChainlinkClient
to consume an API request. This contract exposes a struct called Chainlink.Request
, which is used to build the API request. The request should include the following:
️ Note on Funding Contracts
Making a GET request will fail unless your deployed contract has enough LINK to pay for it. Learn how to Acquire testnet LINK and Fund your contract.
The return value must fit within 32 bytes. If the value is bigger than that, make multiple requests.
If the LINK address for targeted blockchain is not publicly available yet, replace setPublicChainlinkToken(/) with setChainlinkToken(_address) in the constructor, where _address
is a corresponding LINK token contract. Below is an example APIConsumer
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 the contract:
requestVolumeData
function: 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.fulfill
function: This is where the result is sent upon the Oracle Job's completion.oracle
refers to a specific Chainlink node that a contract makes an API call from. jobId
refers to a specific job for that node to run. Each job is unique and returns different types of data.
For example, a job that returns a bytes32
variable from an API would have a different jobId
than a job that retrieved the same data, but in the form of a uint256
variable.
market.link provides a searchable catalogue of Oracles, Jobs and their subsequent return types.
The APIConsumer
in the example above is flexible enough to call any public API, so long as the URL in the "get" adapter parameter is correct, and the format of the response is known.
The path task parameter depends on where the target data exists in the response. It uses JSONPath to determine the location of the data. For example, if the response from the API is {"USD":243.33}
, the "path" parameter is short: "USD"
.
If an API responds with a complex JSON object, the path parameter must specify where to retrieve the desired data using a dot delimited string for nested objects. For example, take the following response:
{
"Prices":{
"USD":243.33
}
}
This would require the following path: "Prices.USD"
.
The code example above returns an unsigned integer from the oracle response, but multiple data types are available such as:
uint256
- Unsigned integersint256
- Signed integersbool
- True or False valuesbytes32
/bytes
- Strings and byte valuesIf you need to return a string, use bytes32
. Here's one method of converting bytes32
to string
. Currently, any return value must fit within 32 bytes. If the value is bigger than that, make multiple requests.
The data type returned by a specific job depends on the tasks that it supports. Make sure to choose an oracle job that supports the data type that your contract needs to consume.
If your contract is calling a public API endpoint, an Oracle job may already exist for it. If so, it could mean you do not need to add the URL, or other adapter parameters into the request, since the job already configured to return the desired data. This makes your smart contract code more succinct. To see an example of a contract using an existing job which calls the AP Election data, see Make an Existing Job Request.
For more information about the functions in ChainlinkClient
, visit ChainlinkClient API Reference.