Skip to content

Policies

A policy is a stateless D struct that defines how a Crate!T is exposed over the wire. It controls routing (which HTTP method and path), serialization (how JSON is formatted), and response behavior (status codes, headers, MIME types).

You define your data model once, then pick a policy — or several — to decide how clients access it.

PolicyProtocolRoutingDefault Path
RestApiJSON over HTTPPath-based/models/:id
JsonApiJSON:APIPath-based/models/:id
McpModel Context ProtocolBody-matched/mcp
GraphQLGraphQLBody-matched/graphql

Pass a policy as a template parameter to crateSetup:

auto crateRouter = router.crateSetup!RestApi;
crateRouter.add(productCrate);

Pass multiple policies to serve the same model over multiple protocols simultaneously:

auto crateRouter = router.crateSetup!(RestApi, Mcp);
crateRouter.add(productCrate);
// Product is now accessible via:
// GET /products (REST)
// POST /mcp (MCP: tools/call, name: "list_products")

All four at once:

auto crateRouter = router.crateSetup!(RestApi, JsonApi, Mcp, GraphQL);
crateRouter.add(productCrate);

Not every model needs every protocol. Use prepareFor to pick which policies apply:

auto crateRouter = router.crateSetup!(RestApi, Mcp, GraphQL);
// Spaces get all three protocols
crateRouter.add(spaceCrate);
// Users only get REST
crateRouter.prepareFor!(RestApi)(userCrate)
.and(authMiddleware);
// Products get REST + MCP but no GraphQL
crateRouter.prepareFor!(RestApi, Mcp)(productCrate)
.and(validationFilter);

Selecting a policy that is not configured on the router is a compile error.

Switching from one protocol to another is a one-line template change:

// Before: REST
auto crateRouter = router.crateSetup!RestApi;
// After: JSON:API
auto crateRouter = router.crateSetup!JsonApi;
// Everything else stays the same
crateRouter.add(productCrate);

The Crate!T, middleware, and custom operations are protocol-agnostic. Only the policy changes.

Each policy accepts a PolicyConfig for base URL customization:

auto crateRouter = router.crateSetup!(
RestApiPolicy!(PolicyConfig("/api/v1")),
McpPolicy!(PolicyConfig("/tools")),
GraphQLPolicy!(PolicyConfig("/api"))
);
crateRouter.add(productCrate);
// REST: GET /api/v1/products
// MCP: POST /tools/mcp
// GraphQL: POST /api/graphql

See Creating a Custom Policy for how to implement a new protocol.