View all results

Work with APIs

Ferret is not limited to HTML. It can fetch data from REST APIs, parse JSON responses, and combine API data with HTML extraction in a single script.

Make a GET request

Use io::net::http::get to fetch data from an API:

terminal
ferret run -e 'let response = io::net::http::get("https://jsonplaceholder.typicode.com/posts/1")let data = encoding::json_parse(to_string(response))return data'

io::net::http::get returns raw bytes. Use to_string to convert to a string, then encoding::json_parse to decode JSON.

Make a POST request

Use io::net::http::post with a body and headers:

example.fql
read-only
let response = io::net::http::post({ url: "https://jsonplaceholder.typicode.com/posts", body: to_binary(encoding::json_stringify({ title: "Ferret", body: "Data extraction", userId: 1 })), headers: { "Content-Type": "application/json" } }) return encoding::json_parse(to_string(response))

Iterate over API results

Fetch a list and process it with for:

terminal
ferret run -e 'let response = io::net::http::get("https://jsonplaceholder.typicode.com/posts")let posts = encoding::json_parse(to_string(response))return for post in posts    limit 5    return {        id: post.id,        title: post.title    }'

Paginate an API

Many APIs use offset or page-based pagination:

example.fql
read-only
let baseURL = "https://jsonplaceholder.typicode.com/posts?_start=" let pageSize = 10 let result = ( for pageNum in 0..2 let offset = pageNum * pageSize let url = baseURL + to_string(offset) + "&_limit=" + to_string(pageSize) let response = io::net::http::get(url) let posts = encoding::json_parse(to_string(response)) for post in posts return { id: post.id, title: post.title } ) return result

Add headers and authentication

Pass custom headers for APIs that require authentication:

example.fql
read-only
let response = io::net::http::get({ url: "https://api.example.com/data", headers: { "Authorization": "Bearer " + @token, "Accept": "application/json" } }) return encoding::json_parse(to_string(response))

Use a bind parameter (@token) so the secret is not hardcoded in the script:

terminal
ferret run script.fql --param token=your-api-key

Combine API and HTML data

A powerful pattern: fetch structured data from an API and enrich it with data from HTML pages:

example.fql
read-only
let response = io::net::http::get("https://jsonplaceholder.typicode.com/posts") let posts = encoding::json_parse(to_string(response)) return for post in posts limit 3 let page = web::html::open("https://mockery.ferretlang.org") on error return none return { id: post.id, title: post.title, pageTitle: page?.title }

Handle API errors

Use on error return and on error retry for network failures:

example.fql
read-only
let response = io::net::http::get("https://api.example.com/data") on error retry 3 delay 1s backoff EXPONENTIAL or return none return response != none ? encoding::json_parse(to_string(response)) : { error: "API unavailable" }

Next steps