postrust-server 3.0.0

PostgREST-compatible REST and GraphQL API server for PostgreSQL, built on Axum
Documentation
[package]
name = "postrust-server"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
authors.workspace = true
description = "PostgREST-compatible REST and GraphQL API server for PostgreSQL, built on Axum"
homepage.workspace = true
readme = "README.md"
keywords = ["postgres", "rest", "api", "graphql", "server"]

[[bin]]
name = "postrust"
path = "src/main.rs"

# musl's allocator serialises heavily under multithreaded load. Measured on the
# Alpine image: the GraphQL embed scenario ran at 636 req/s against 4,379 for
# the same code built with glibc, with the database image held constant to rule
# it out. mimalloc closes that gap and is only pulled in for musl targets.
[target.'cfg(target_env = "musl")'.dependencies]
mimalloc = "0.1"

[features]
default = []
# The GraphQL API. Separate from the admin UI so a host can serve one without
# the other -- the Lambda adapter serves GraphQL and has no use for Swagger.
graphql = ["postrust-graphql", "async-graphql", "async-graphql-axum"]
admin-ui = ["graphql", "utoipa"]

# OpenTelemetry: traces and metrics exported over OTLP, and the metrics as
# Prometheus text at `GET /metrics` on the admin port. Compiled into the
# published images, and inactive until configured: with no
# `OTEL_EXPORTER_OTLP_ENDPOINT` no exporter runs, and with no admin port either
# nothing is measured at all. See docs/observability.md.
#
# - OTLP over HTTP/protobuf only, so tonic and its gRPC stack are not pulled
#   in. No client feature of opentelemetry-otlp either: each of its clients is
#   reqwest 0.13 or a hyper client of its own, a second HTTP stack beside the
#   reqwest 0.12 the server already has for `PGRST_JWT_JWKS_URL`.
#   `otel::client` is that reqwest, behind the exporter's `HttpClient` trait.
# - tracing-opentelemetry turns the spans the server already opens into OTel
#   spans, so nothing is instrumented twice.
# - opentelemetry-prometheus renders the same meters as the exposition format.
#   Maintained in the opentelemetry-rust repository again since 0.32, and its
#   `prometheus` dependency no longer brings protobuf (RUSTSEC-2024-0437).
otel = [
    "dep:opentelemetry",
    "dep:opentelemetry_sdk",
    "dep:opentelemetry-otlp",
    "dep:opentelemetry-http",
    "dep:tracing-opentelemetry",
    "dep:opentelemetry-prometheus",
    "dep:prometheus",
]

# Test only, never shipped: REST requests run through the socket driver a
# Cloudflare Worker uses (`postrust_core::db::PgSocketDb`) instead of the sqlx
# pool, over a TCP connection per request. It exists so the conformance suite
# can prove the two drivers answer alike -- see
# `CONFORMANCE_EXTRA_FEATURES=pg-socket` in scripts/conformance/conformance.sh.
# GraphQL and the schema cache stay on sqlx.
pg-socket = ["postrust-core/pg-socket"]

# Return object keys in the order the columns were selected, as PostgREST does,
# rather than alphabetically.
#
# This cannot be a runtime setting. Key order follows from whether
# `serde_json::Map` is a BTreeMap or an IndexMap, which is fixed when the crate
# is compiled, so it is a feature rather than a flag in the config.
#
# Off by default because it is not free. Measured by running both builds as
# containers against one database and alternating between them: a 3-column
# response cost 1%, an 8-column response 15%. For small objects a handful of
# short string comparisons beats hashing every key, so the sorted map is
# genuinely the faster one here.
#
# Turn it on when byte-level PostgREST compatibility matters more than that.
compat-key-order = ["serde_json/preserve_order", "postrust-core/compat-key-order"]

[dependencies]
# Async
tokio = { workspace = true, features = ["full"] }
async-trait.workspace = true

# Web
axum.workspace = true
tower.workspace = true
tower-http.workspace = true
hyper.workspace = true

# Database
sqlx.workspace = true

# Serialization
serde.workspace = true
serde_json.workspace = true

# Error handling
thiserror.workspace = true
anyhow.workspace = true

# Utilities
http.workspace = true
# `request.headers` and `request.cookies` for `User`, the maps `Session` takes.
indexmap.workspace = true
bytes.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
chrono.workspace = true
# The request span's response future; already in the tree through tower.
pin-project-lite = "0.2"
# Fetching `PGRST_JWT_JWKS_URL`. rustls on ring, which sqlx already links, and
# webpki's roots; reqwest builds its TLS config with its provider named, so it
# does not depend on (or disturb) a process-wide default.
reqwest.workspace = true

# Internal
postrust-core = { workspace = true, features = ["sqlx"] }
postrust-sql.workspace = true
postrust-auth.workspace = true
postrust-response.workspace = true
postrust-engine.workspace = true

# Admin UI (optional)
utoipa = { version = "5", features = ["axum_extras"], optional = true }
postrust-graphql = { workspace = true, optional = true }
async-graphql = { version = "7", optional = true }
async-graphql-axum = { version = "7", optional = true }

# OpenTelemetry (optional; the `otel` feature)
opentelemetry = { workspace = true, optional = true }
opentelemetry_sdk = { workspace = true, optional = true }
opentelemetry-otlp = { workspace = true, optional = true }
opentelemetry-http = { workspace = true, optional = true }
tracing-opentelemetry = { workspace = true, optional = true }
opentelemetry-prometheus = { workspace = true, optional = true }
prometheus = { workspace = true, optional = true }

[dev-dependencies]
jsonwebtoken.workspace = true
futures.workspace = true
base64.workspace = true
# tests/otel.rs exports spans to memory rather than to a collector.
opentelemetry_sdk = { workspace = true, features = ["testing"] }
opentelemetry.workspace = true
# tests/drivers_agree.rs runs both database drivers side by side.
postrust-core = { workspace = true, features = ["sqlx", "pg-socket"] }
postrust-sql.workspace = true
tokio-postgres = { version = "0.7.18", default-features = false }
uuid.workspace = true
pretty_assertions.workspace = true
# Parses the workspace manifest in tests/sqlx_tls_feature.rs.
toml.workspace = true