nenu-lang / api-runnables
Stable

API Runnables

  • App Marché metadata defines the API route and its Request and Response contracts.
  • The Nenu source is the executable body of an implicit typed function.
  • Every successful path must return a value compatible with Response.

The Contract Comes From Metadata

An API runnable is an implicit function from a metadata-defined Request to a metadata-defined Response. The editor contains the function body only. Do not recreate either contract with type Request or type Response in source.

App Marché metadata ownsNenu source owns
Route and API node identityValidation and control flow
Authentication settingEntity reads and writes
Request fields and optional markersReads from request
Response fields and typesreturn Response { ... }

Create An Expense

Assume Request metadata contains room_id, payer_id, title, amount, and optional note. Response metadata contains expense: Expense. Required entities are loaded first, then the new value is constructed, saved, and returned.

apis/expenses/create.api.nenu
1need {2  room = Room(request.room_id)3  payer = User(request.payer_id)4}56if request.title.trim() == "" {7  throw Validation("Expense title is required")8}910if request.amount <= 0 {11  throw Validation("Expense amount must be positive")12}1314expense = Expense {15  room_id: room.id16  payer17  title: request.title.trim()18  amount: request.amount19  note: request.note20  status: ExpenseStatus.Open21}2223save(expense)24return Response { expense }

Same-name shorthand keeps the return concise: return Response { expense } means the Response field named expense receives the local binding named expense. The metadata contract must actually contain that field.

Read, Update, And Delete Patterns

code
1need expenses = Expense[]({2  room_id == request.room_id3}) | sort(createdAt, desc) | limit(100)45return Response { expenses }
  • Choose a required, optional, array, map, or join-row Response field that matches the real result.
  • Use with when an optional Request field means “change this only when supplied.”
  • Return a useful success value or explicit acknowledgement that exists in Response metadata.
  • A successful fetch or save does not excuse a missing or incompatible Response return.

Success Paths And Failure Paths

Every reachable successful path of a response-bearing API must return a compatible Response value. A throw ends a failing path, so that path does not also return a success value.

code
1need expense = Expense?(request.expense_id)23without expense {4  throw NotFound("Expense was not found")5}67return Response { expense }

Calling The API From Page Script

code
1use api/expenses/create as CreateExpenseApi23fn createExpense() {4  created = CreateExpenseApi({5    room_id6    payer_id7    title8    amount9    note10  })1112  expenses = expenses + [created.expense]13}
  • Import the root-qualified api/... route and give it an alias.
  • Call Alias() when Request has no required fields.
  • Pass one map payload when Request expects fields.
  • The result type comes from Response metadata; access only declared fields.

Common Mistakes

WrongCorrect
api CreateExpense { ... }Write the executable statements directly.
runnable CreateExpense { ... }The API node already supplies the runnable context.
Source-authored type RequestDefine Request fields in API metadata.
respond { expense }return Response { expense }
Return an undeclared fieldMake the value match the exact Response contract.

Continue Learning