Data Requests enable you to retrieve information from public API endpoints that do not require sensitive information like API keys. For APIs that do require keys, see Advanced: API-key Gated Data.
In this walkthrough, we'll use the SEDA Request Starter Kit, which includes all the necessary dependencies.
HTTP Fetch: GET
The httpFetch method is available only during the execution phase. Using it in the tally phase will trigger an error due to the non-deterministic nature of http_fetch. To make an HTTP request, we use the http_fetch method:
use seda_sdk_rs::{http_fetch, oracle_program, Process};
#[oracle_program]
impl PriceFeed {
fn execute() {
let response = http_fetch("https://swapi.dev/api/planets/1", None);
if !response.is_ok() {
Process::error("Could not fetch API endpoint".as_bytes());
return;
}
println!(String::from_utf8(response.bytes).unwrap());
}
fn tally() {
panic!("Not implemented");
}
}
Running this program with the following test will output the result of the execution, showing the http_fetch response as a string. You can place this test in tests/my-dr.test.ts:
import { describe, it} from "bun:test";
import { file } from "bun";
import { testOracleProgramExecution } from "@seda-protocol/dev-tools"
describe("data request execution", () => {
it("should run MyDataRequest", async () => {
const wasmBinary = await file("build/debug.wasm").arrayBuffer();
// Locally executes the Data Request
const vmResult = await testOracleProgramExecution(
Buffer.from(wasmBinary),
// This program doesn't have any inputs
Buffer.from(""),
);
console.log(vmResult.stdout);
});
});
Running the test will compile the binary and execute the test file, showing the output of the API formatted in JSON.
$ bun run test
Outputs:
bun test v1.1.26 (0a37423b)
tests/index.test.mts:
{"name":"Tatooine","rotation_period":"23","orbital_period":"304","diameter":"10465","climate":"arid","gravity":"1 standard","terrain":"desert","surface_water":"1","population":"200000","residents":["https://swapi.dev/api/people/1/","https://swapi.dev/api/people/2/","https://swapi.dev/api/people/4/","https://swapi.dev/api/people/6/","https://swapi.dev/api/people/7/","https://swapi.dev/api/people/8/","https://swapi.dev/api/people/9/","https://swapi.dev/api/people/11/","https://swapi.dev/api/people/43/","https://swapi.dev/api/people/62/"],"films":["https://swapi.dev/api/films/1/","https://swapi.dev/api/films/3/","https://swapi.dev/api/films/4/","https://swapi.dev/api/films/5/","https://swapi.dev/api/films/6/"],"created":"2014-12-09T13:50:49.641000Z","edited":"2014-12-20T20:58:18.411000Z","url":"https://swapi.dev/api/planets/1/"}
β data request execution > should run MyDataRequest [1854.33ms]
Weβve successfully created an Oracle Program that fetches data. To make the program more useful, we need to parse the JSON response and work with its properties. The SEDA-SDK utilizes the json-as library, allowing you to define a schema and parse a JSON string into that schema. This library is already included in the starter kit.
Letβs modify our example to integrate this library:
use seda_sdk_rs::{http_fetch, oracle_program, Process};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Planet {
name: String,
terrain: String,
}
#[oracle_program]
impl PriceFeed {
fn execute() {
let response = http_fetch("https://swapi.dev/api/planets/1", None);
if !response.is_ok() {
Process::error("Could not fetch API endpoint".as_bytes());
return;
}
let planet = serde_json::from_slice::<Planet>(&response.bytes).unwrap();
println!("We are on planet {}, which is a {} terrain", planet.name, planet.terrain);
}
fn tally() {
panic!("Not implemented");
}
}
Running the previous test again now outputs:
bun test v1.1.26 (0a37423b)
tests/index.test.mts:
We are on planet Tatooine, which is a desert terrain
β data request execution > should run MyDataRequest [174.21ms]
Now you can call any open API you want and process the data as needed.
HTTP Fetch: POST
The SEDA SDK enables you to send POST requests (as well as PATCH, PUT, and others) with an attached body. This allows you to work with various APIs, including GraphQL or uploading files to IPFS.
use std::collections::BTreeMap;
use seda_sdk_rs::{bytes::{Bytes, ToBytes}, http_fetch, oracle_program, HttpFetchMethod, HttpFetchOptions, Process};
use serde::{Deserialize, Serialize};
use serde_json::json;
#[oracle_program]
impl PriceFeed {
fn execute() {
let query_body = json!({
"key": "value_test"
});
let mut headers: BTreeMap<String, String> = BTreeMap::default();
headers.insert("content-type".to_string(), "application/json".to_string());
let body: Bytes = query_body.to_string().to_bytes();
let response = http_fetch("https://httpbin.org/post", Some(HttpFetchOptions { method: HttpFetchMethod::Post, headers, body: Some(body) }));
if !response.is_ok() {
dbg!(&String::from_utf8_lossy(&response.bytes));
Process::error("Could not fetch API endpoint".as_bytes());
return;
}
println!("{}", String::from_utf8(response.bytes).unwrap());
}
fn tally() {
panic!("Not implemented");
}
}
Running the same test will give you the response of the POST request: