---
warning: DO NOT CHANGE THIS MANUALLY, THIS IS GENERATED BY https://github.com/duckdb/community-extensions repository, check README there
title: quackapi
excerpt: |
DuckDB Community Extensions
FastAPI-class HTTP framework inside DuckDB — CREATE ROUTE turns SQL into typed, validated endpoints; one process is DB + HTTP (+ PDF/renderer via companion extensions).
# Community-extensions submission descriptor for the `quackapi` extension.
# Keep the root and packaging/description.yml copies identical.
# Release candidate descriptor; editing this file does not publish the CDN package.
#
# Submit:
# 1. Fork https://github.com/duckdb/community-extensions
# 2. Copy this file to extensions/quackapi/description.yml
# 3. Set repo.ref to the exact git SHA of the release commit (no merge markers)
# 4. Open a pull request against duckdb/community-extensions
#
# Schema: https://duckdb.org/community_extensions/documentation.html
extension:
name: quackapi
description: >-
FastAPI-class HTTP framework inside DuckDB — CREATE ROUTE turns SQL into
typed, validated endpoints; one process is DB + HTTP (+ PDF/renderer via
companion extensions).
version: 0.2.0
language: C++
build: cmake
license: MIT
maintainers:
- asubbarao
# HTTP server uses DuckDB's bundled httplib — no server sockets on wasm.
# windows_amd64 enabled (MSVC / extension-ci-tools). MinGW/rtools/arm64
# still excluded. Target signed arches: linux_*, osx_*, windows_amd64.
excluded_platforms: wasm_mvp;wasm_eh;wasm_threads;windows_amd64_mingw;windows_amd64_rtools;windows_arm64
repo:
github: asubbarao/quackapi
# Pin to the packaging commit SHA (set by release engineer; never a branch).
ref: d5c0e6784fda79930f952052302be89c16d6739c
# Preserve the community registry's pre-2.0 compatibility build.
variegata: 9da900bcaa1da48b64dbcab5cc3470c849b851a0
docs:
hello_world: |
LOAD quackapi;
-- JSON endpoint: the SELECT is the handler
CREATE ROUTE hello GET '/hello' AS SELECT 'world' AS msg;
-- Path params bind as $id; cast failure → FastAPI-shaped 422
CREATE ROUTE item GET '/items/:id' AS SELECT $id::INTEGER AS id;
-- HTML when the single output column is named html
CREATE ROUTE home GET '/' AS SELECT '
quackapi
' AS html;
-- Typed optional query param with constraint
CREATE ROUTE search GET '/search'
PARAM limit INTEGER DEFAULT 10 LE 100
AS
SELECT $q::VARCHAR AS q, $limit::INTEGER AS limit;
-- POST mutation (JSON body fields bind as $name / $age)
CREATE ROUTE create_user POST '/users' STATUS 201 AS
SELECT $name::VARCHAR AS name, $age::INTEGER AS age;
-- Serve (background threads; shell stays usable)
-- Optional: static_dir for unrouted GETs; cors_origins for browser CORS
SELECT * FROM quackapi_serve(8000);
-- curl http://127.0.0.1:8000/hello → [{"msg":"world"}]
-- curl http://127.0.0.1:8000/items/42 → [{"id":42}]
-- curl http://127.0.0.1:8000/items/abc → 422 detail[loc=path,id]
-- curl -X POST …/users -H 'Content-Type: application/json' -d '{"name":"a","age":3}'
SELECT * FROM quackapi_routes();
SELECT * FROM quackapi_stop(8000);
extended_description: |
# quackapi
**A FastAPI-class HTTP framework that lives inside DuckDB.** Routes are DDL,
handlers are SQL, and request validation is the database type system.
## Thesis: the backend IS the database
A conventional stack serializes at every hop (app server → workers → DB →
PDF microservice). quackapi collapses that into **one DuckDB process**:
browser → DuckDB [ quackapi(HTTP) · pdf · tera · fakeit · webbed · … ]
Companion community extensions (`pdf`, `tera`, `fakeit`, `crawler`/`webbed`,
`cronjob`, `curl_httpfs`, …) load into the same address space. A handler that
redacts a PDF is literally `SELECT pdf_redact(...)` — no RPC between tiers.
**Showcase:** the Closure redaction-review app (DB + HTML UI + PDF word
boxes + POST decisions + static assets) runs as a single DuckDB process via
`CREATE ROUTE` + `quackapi_serve`.
## CREATE ROUTE
CREATE [OR REPLACE] ROUTE ''
[STATUS ] [REQUIRE ] [GROUP ]
[BODY SCHEMA '' | BODY TYPE '']
[PARAM [] [HEADER|COOKIE|QUERY …] [DEFAULT …] [GE|LE|…] …]
AS