Skip to content

Commit 1c45063

Browse files
codybromburmecia
andauthored
feat: Add OpenAPI Foreign Data Wrapper (supabase#566)
* feat: Add OpenAPI Foreign Data Wrapper * feat: Implement OpenAPI FDW with schema mapping and foreign table generation - Added schema.rs for mapping OpenAPI types to PostgreSQL types and generating CREATE FOREIGN TABLE statements. - Introduced spec.rs for parsing OpenAPI specifications and extracting endpoint/schema information. - Created world.wit file for OpenAPI FDW package definition. - Enhanced server.py to mock OpenAPI endpoints for testing. - Updated tests.rs to include tests for OpenAPI FDW functionality, including server creation and query execution. * feat(openapi_fdw): add GeoJSON support, configurable pagination, and cleanup dead code - Add object_path option for GeoJSON responses (e.g., /properties) - Make page_size_param configurable (default: limit) with table-level override - Add case-insensitive column matching for APIs with camelCase fields - Use nullable field to generate NOT NULL constraints in CREATE TABLE - Remove unused spec parsing structs: Parameter, RequestBody, SecurityScheme - Simplify EndpointInfo to only path and response_schema - Mark deserialize-only fields with #[allow(dead_code)] - Make from_str() test-only with #[cfg(test)] Tested with weather.gov API (stations, alerts endpoints) * refactor(openapi_fdw): simplify code for clarity and maintainability - Extract helper functions: json_to_rows, cell_to_string, extract_non_empty_string - Flatten nested control flow with early returns in build_url and handle_pagination - Simplify sanitize_column_name with cleaner string operations - Clean up doc comments and move #[allow(dead_code)] to field level * feat(vscode): add extensions.json for recommended Rust Analyzer * feat(openapi_fdw): add custom HTTP headers support - Add optional user_agent option for API identification (required by NWS) - Add optional accept option for content negotiation (GeoJSON, JSON-LD) - Add headers option for arbitrary custom headers as JSON object - Apply clippy fixes: #[derive(Default)] for Schema, .next_back() for iterator * feat(openapi_fdw): add path parameter substitution for complex endpoints Support endpoint templates with path parameters like: - /stations/{station_id}/observations - /gridpoints/{wfo}/{x},{y}/forecast - /zones/{type}/{zone_id}/alerts Path parameters are extracted from WHERE clause quals and substituted into the URL template. Values are also injected back into returned rows so PostgreSQL's WHERE filter passes (since API responses often don't include path param columns). Also changed page_size default from 100 to 0 to avoid adding ?limit=100 to APIs that don't support the limit parameter. * docs(openapi_fdw): add SAFETY comments to unsafe code Document the safety invariants for: - static mut INSTANCE: explains Wasm single-threaded execution model - init_instance(): explains intentional Box::leak for FDW lifetime - this_mut(): explains initialization order and aliasing guarantees * docs(openapi_fdw): use generic API examples instead of NWS-specific Replace NWS API-specific path parameter examples with generic REST API patterns to avoid bias toward any specific API. - /stations/{station_id}/observations -> /users/{user_id}/posts - /gridpoints/{wfo}/{x},{y}/forecast -> /projects/{org}/{repo}/issues - /zones/{type}/{zone_id} -> /resources/{type}/{id} * test(openapi_fdw): expand mock server and tests for all FDW features Add comprehensive test coverage for OpenAPI FDW: - Path parameter substitution (/users/{user_id}/posts) - Multiple path parameters (/projects/{org}/{repo}/issues) - GeoJSON FeatureCollection with object_path - Direct array responses - Resource type/id patterns (/resources/{type}/{id}) Update mock server with matching test endpoints. * docs(openapi_fdw): add documentation and make FDW read-only - Add docs/catalog/openapi.md with full usage documentation - Add OpenAPI FDW entry to root README.md - Remove untested INSERT/UPDATE/DELETE implementation - Replace write methods with read-only error stubs * fix(openapi_fdw): address clippy warnings and improve safety - Use try_from instead of unsafe `as` casts for integer conversions to prevent truncation on overflow (returns None instead) - Add depth limiting (MAX_RESOLVE_DEPTH=32) to schema resolution to prevent stack overflow on circular OpenAPI references - Fix SAFETY comments to correctly reference init() instead of host_version_requirement() - Fix numerous clippy warnings: doc_markdown, format strings, redundant closures, match arm simplification, map_or_else usage * feat(openapi_fdw): add rate limiting, limit pushdown, and documentation - Add README.md with comprehensive usage documentation, configuration options, query pushdown details, and type mapping reference - Add HTTP 429 rate limiting with retry-after header parsing and exponential backoff (1s, 2s, 4s) up to 3 retries - Add limit pushdown to stop pagination early when LIMIT is satisfied, reducing unnecessary API calls - Add URL validation for base_url and spec_url in init() * fix(openapi_fdw): improve path parameter validation and allOf schema merging - Return clear error when required path parameters are missing from WHERE clause instead of silently constructing invalid URLs that return empty results - Fix allOf property merging to use "later wins" semantics per OpenAPI spec, allowing child schemas to refine/override parent property definitions - Add test for allOf override behavior --------- Co-authored-by: Cody Bromley <[email protected]> * fix(openapi_fdw): address code review feedback - Add URL encoding for path params, query params, and pagination cursors using urlencoding crate - Quote SQL identifiers in generated foreign tables to handle special characters and prevent injection from external OpenAPI specs - Handle relative pagination URLs by prepending base_url - Validate OpenAPI version is 3.x with helpful error message - Rename init_instance() to init() for consistency with other Wasm FDWs - Report warning on invalid page_size option instead of silent fallback - Fix docs: document actual rate limiting behavior (HTTP 429 retry with Retry-After support and exponential backoff) * feat(openapi_fdw): fix query param filtering and bump to v0.1.2 - Inject query param values back into result rows so PostgreSQL's post-filter passes even when the API doesn't echo them back - Prefer WHERE clause value for query/path param columns to handle case mismatches (e.g. API accepts "actual" but returns "Actual") - Update docs with v0.1.2 release URL, checksum, and behavior note * perf(openapi_fdw): avoid cloning JSON response data, bump to v0.1.3 Use pointer_mut + Value::take() to move data out of the parsed JSON response instead of cloning every array element. Adds 14 unit tests covering json_to_rows, extract_data, and to_camel_case. Updates docs with v0.1.3 release URL and checksum. * style(openapi_fdw): fix code formatting for CI * style(openapi_fdw): inline format args for clippy * fix(openapi_fdw): update author name and remove standalone repo URL / checksum * feat(openapi_fdw): address Copilot review, add include_attrs option, bump to v0.1.4 Address all 12 Copilot review comments: - Type coercion for injected path/query param values based on column type - Mutual exclusivity check for api_key and bearer_token auth options - Error on invalid headers JSON and non-string header values - Error on invalid page_size values instead of silent fallback - Full-path table naming to avoid collisions (e.g., v1_users vs v2_users) - Smart rowid_column selection: id > first scalar column > omit - Deduplicate attrs column if schema already has one - Add next_url variants to pagination auto-detection - Robust relative URL joining for pagination (?, /, bare paths) - Document IMPORT FOREIGN SCHEMA limitation for parameterized paths - Update README version and backfill changelog New feature: - Add include_attrs server option to control attrs column in IMPORT FOREIGN SCHEMA Tests: - Add integration test for relative URL pagination (?page=2) * add default user agent and docs improvement --------- Co-authored-by: Cody Bromley <[email protected]> Co-authored-by: Bo Lu <[email protected]>
1 parent 513cb0e commit 1c45063

16 files changed

Lines changed: 3099 additions & 54 deletions

File tree

.vscode/extensions.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"recommendations": [
3+
"rust-lang.rust-analyzer"
4+
]
5+
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
| [Infura](./wasm-wrappers/fdw/infura_fdw) | A Wasm FDW for [Infura](https://www.infura.io/) blockchain data |||
2424
| [Logflare](./wrappers/src/fdw/logflare_fdw) | A FDW for [Logflare](https://logflare.app/) |||
2525
| [Notion](./wasm-wrappers/fdw/notion_fdw) | A Wasm FDW for [Notion](https://www.notion.so/) |||
26+
| [OpenAPI](./wasm-wrappers/fdw/openapi_fdw) | A Wasm FDW for any [OpenAPI](https://www.openapis.org/) 3.0+ REST API |||
2627
| [Orb](./wasm-wrappers/fdw/orb_fdw) | A Wasm FDW for [Orb](https://www.withorb.com/) |||
2728
| [Paddle](./wasm-wrappers/fdw/paddle_fdw) | A Wasm FDW for [Paddle](https://www.paddle.com/) |||
2829
| [Redis](./wrappers/src/fdw/redis_fdw) | A FDW for [Redis](https://redis.io/) |||

docs/catalog/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Each FDW documentation includes a detailed "Limitations" section that describes
2828
| Iceberg |||||||
2929
| Logflare |||||||
3030
| Notion |||||||
31+
| OpenAPI |||||||
3132
| Orb |||||||
3233
| Paddle |||||||
3334
| Redis |||||||
@@ -54,6 +55,7 @@ See [Developing a Wasm Wrapper](../guides/create-wasm-wrapper.md) for instructio
5455
| HubSpot | [Supabase](https://supabase.com) | [Link](hubspot.md) | [Link](https://github.com/supabase/wrappers/tree/main/wasm-wrappers/fdw/hubspot_fdw) |
5556
| Infura | [Supabase](https://supabase.com) | [Link](infura.md) | [Link](https://github.com/supabase/wrappers/tree/main/wasm-wrappers/fdw/infura_fdw) |
5657
| Notion | [Supabase](https://supabase.com) | [Link](notion.md) | [Link](https://github.com/supabase/wrappers/tree/main/wasm-wrappers/fdw/notion_fdw) |
58+
| OpenAPI | [Cody Bromley](https://github.com/codybrom) | [Link](openapi.md) | [Link](https://github.com/supabase/wrappers/tree/main/wasm-wrappers/fdw/openapi_fdw) |
5759
| Orb | [Supabase](https://supabase.com) | [Link](orb.md) | [Link](https://github.com/supabase/wrappers/tree/main/wasm-wrappers/fdw/orb_fdw) |
5860
| Paddle | [Supabase](https://supabase.com) | [Link](paddle.md) | [Link](https://github.com/supabase/wrappers/tree/main/wasm-wrappers/fdw/paddle_fdw) |
5961
| Shopify | [Supabase](https://supabase.com) | [Link](shopify.md) | [Link](https://github.com/supabase/wrappers/tree/main/wasm-wrappers/fdw/shopify_fdw) |

0 commit comments

Comments
 (0)