- Markdown output:
md(Search API) andsearchArchiveMd(Search Archive API), returning the results as token-efficient Markdown for LLMs and AI agents, via theoutput=mdformat serpapi.Erroris exported from the module root (serpapi.Error.SerpApiError, previously onlyserpapi.client.Error)serpapi.versionis derived frombuild.zig.zonat build time instead of being duplicated insrc/client.zig, so the tag cut byrake releaseand the version reported to serpapi.com cannot drift apart- Fix: persistent connections are actually reused.
std.http.Client.fetchleaves the terminating chunk of a compressed, chunked response unread, so it judged every serpapi.com body unfinished and closed the socket:persistent = truewas silently a no-op and each request paid for a new TLS handshake. The client now drives the request itself and drains the framing;zig build benchgoes from ~2.4s to ~0.5-1.0s for 10 searches (3-4x), where before persistent and non-persistent were within noise - Fix: the
timeoutoption is enforced. It was accepted and documented but never applied, so a stalled connection blocked forever. Each request now races a timer on the client'sstd.Io.Threadedpool and is canceled when it fires, returningerror.Timeout;0disables the limit - Browser wasm demo (
demo/wasm): awasm32-freestandingmodule for request building and JSON parsing, served by a native proxy (zig build serve) that keepsSERPAPI_KEYoff the browser - Flight tracker demo (
demo/flight_tracker): typed results against the Google Flights API, as a standalone downstream project - Fix: one error rule for every decoder. An
{"error": "..."}payload isSerpApiErrorwhatever the HTTP status, for JSON, HTML, and Markdown output alike; a non-200 status without such a payload isHttpRequestFailed. Previouslyhtmlreported error payloads asHttpRequestFailed, and typed decoding (searchAsand friends) could surface an error payload asJsonParseErroror, with all-optional fields, as an empty success - Fix:
html(and any other raw-body decoder) double-freed its response buffer when the backend returned a non-200 status - Fix: Search Archive ids are percent-encoded in the request path
- CI: jobs are time-boxed, the kcov coverage job is advisory (it could hang the runner for six hours), and both demos are built on every push
Initial release, ported from serpapi-ruby.
- Search API:
search(JSON) andhtml(raw HTML) decoders - Location API:
location - Search Archive API:
searchArchive(JSON) andsearchArchiveHtml(raw HTML) - Account API:
account - Persistent HTTP connection (keep-alive) enabled by default
- Zero dependency: Zig standard library only (
std.http,std.json) - Unit tests, live integration tests, out-of-box testing demo, CI workflow