drift Docs
Start
What is Drift?
The tour, if you are new here.
Use cases
Whether Drift does your thing.
Getting started
Nothing to deployed, in one command.
Architecture
How a slice is put together.
What it costs
The free grant, four unit prices, two rules.
Build
Canvas
Static sites, same origin as your API.
Tools
Operate
Auth
Route gates, API keys and your account.
Security
Boundaries, sandboxing and hardening.
Troubleshooting
Error codes
What went wrong, and what to do about it.
Legal
Acceptable use
What a slice may not be used for.
Data processing
The DPA, and every sub-processor.

Utilities & cross-slice

What sits at the SDK's top level, beside Backbone and Deed rather than inside either.

Signatures

Go
// Outbound HTTP, egress-gated.
HTTPRequest(method, url string, headers map[string]string, body []byte) (*HTTPResponse, error)
HTTPRequestWithTimeout(method, url string, headers map[string]string, body []byte, timeout time.Duration) (*HTTPResponse, error)

type HTTPResponse struct { Status int; Body []byte }   // no headers, status and body only

// drift.Slice(name): a slice you linked with `drift slice link add`.
// An unlinked name errors before any network I/O.
Get(path string) (*HTTPResponse, error)
Post(path string, body any) (*HTTPResponse, error)                                  // JSON-encodes body
Request(method, path string, headers map[string]string, body []byte) (*HTTPResponse, error)

CallerSlice(req Request) string   ·   Env(key string) string   ·   Log(msg string)

Outbound HTTP

The default timeout is 30 seconds; HTTPRequestWithTimeout takes your own. Private address space is unreachable whatever your Driftfile says: RFC-1918, link-local (including the cloud metadata endpoint) and CGNAT are excepted from the slice's outbound rule.

A blocked or failed request does not surface the same way in every language. Go, Python, Node.js and Ruby treat it as a failure: Go returns an error, and the other three raise or throw. PHP and Rust instead answer with a status of 0 and an empty or explanatory body, no exception involved, so a caller there has to check the status before trusting the rest of the response.

Go tells an egress refusal apart from a broken remote.

HTTPRequest wraps an allowlist refusal in *EgressDeniedError, matchable with errors.As, so a handler can answer one differently from a remote that is merely down. The match is best-effort, on the same connection refused that a refused dial and a genuinely dead host both produce, so treat it as a debugging aid rather than a proof.
Go
var ee *drift.EgressDeniedError
if errors.As(err, &ee) {
    return 502, "external API not allowlisted", map[string]string{"host": ee.Host}
}

Rust: outbound HTTPS needs the tls feature.

The default Rust build pulls ureq with default-features = false, so it is pure Rust and cross-compiles with rustup alone. In that build an https:// URL returns (0, "drift-sdk: outbound HTTPS needs the \"tls\" feature …") without a request ever leaving the process, so check the status and don't assume the call happened. Enabling features = ["tls"] pulls ring (C and assembly), and deploys then need a C cross-toolchain such as zig.

Cross-slice

All three Slice methods inject the X-Drift-Slice identity header, which is what the far end reads back with CallerSlice. Your own headers override it only by setting the same key.

Cross-slice calling is deliberately not under Backbone, because it is inter-slice networking, the seed of a different, hypothetical future pillar. Not to be confused with Deed.Link, which enrolls a device for one identity.

Environment

Env exists in all six SDKs and returns an empty string for a missing key. Reaching past it for the language's own accessor changes that: Python's os.environ[key] raises KeyError rather than returning "". For secrets specifically, use Secret.Get rather than either, because it resolves the value whichever way the runtime delivered it.