Language

Interfaces layer

L4 exposes queries, actions and use cases to programs through interfaces with endpoints.

The interfaces layer (L4) describes how application capabilities are exposed to programs: REST APIs, GraphQL schemas, MCP servers, webhooks or any other protocol. An interface maps endpoints to queries, actions and use cases, and adds transport restrictions. Web routes for pages people visit belong to the experience layer, not here.

Declaring an interface

interface rest PublicApi {
  auth bearer
  limit 100 per minute
  cors "https://shop.example.com"
  GET "/orders" -> OpenOrders as OrderSummary { reference, status, total }
  POST "/orders/{id}/place" -> PlaceOrder
}

interface <protocol> <Name> starts the declaration. The protocol is any identifier you choose, such as rest, graphql or mcp; the language does not restrict it. The Django and Ash generators generate code for rest interfaces.

The clauses come in this order, each optional:

ClauseMeaningExample
auth <scheme>The authentication scheme, any identifierauth bearer, auth apikey
limit <n> per <unit>A rate limit; the unit is second, minute or hourlimit 100 per minute
cors "<origin>", ...Allowed CORS originscors "https://a.example", "https://b.example"
EndpointsOne per lineGET "/orders" -> OpenOrders as OrderSummary

These transport policies only add restrictions. They never widen what the policies of the queries, actions, use cases and entities allow. See access.

Endpoints

<VERB> "<path>" -> <Target> as <Projection> { <picks> }
PartMeaning
VerbAny identifier, by convention an HTTP method such as GET, POST, PUT, PATCH, DELETE
PathA string, such as "/orders/{id}/place"
TargetA query, an action or a use case
as ProjectionThe projection that shapes the data, optional except for queries
{ picks }Some fields of that projection, separated by commas; without picks, all of them

An endpoint is identified by its verb and path: sales.PublicApi.endpoint[GET /orders].

Data only through projections

An interface never references an entity. It reaches entity data only through a projection, so the shape it exposes is declared once in the application layer and can only narrow the entity.

An endpoint that targets a query must name a projection: An endpoint exposes query results only through a projection: add "as <Projection>".

Picks resolve against the fields of the projection after as, including its computed fields.

What an interface may reference

Queries, projections and use cases from L3, actions from L2, enums and value types from L1, and cross cutting declarations. Any other reference is a layer error; in particular an interface never references a page. See reference rules.

Complete example

module sales {
  enum OrderStatus {
    draft
    placed
  }

  entity Order {
    reference: String unique
    status: OrderStatus state default draft
    total: Money
  }

  action PlaceOrder on Order {
  }

  query OpenOrders from Order {
    where { status == placed }
  }

  projection OrderSummary from Order {
    reference
    status
    total
    label = reference + " " + "order"
  }

  usecase Checkout (order: Order) {
    step PlaceOrder(order)
  }

  interface rest PublicApi {
    auth bearer
    limit 100 per minute
    cors "https://shop.example.com"
    GET "/orders" -> OpenOrders as OrderSummary { reference, status, label }
    POST "/orders/{id}/place" -> PlaceOrder
    POST "/checkout" -> Checkout
  }

  interface mcp Assistant {
    auth apikey
    GET "/orders" -> OpenOrders as OrderSummary
  }
}