Moul

Records & Dynamic CRUD

Create, read, update, filter, paginate, sort, and delete dynamic collection records via REST API.

Moul provides instant, fully typed REST API endpoints for every dynamic collection. Record operations are validated against the schema and checked against the collection's access rules.


Query Parameters

List queries (GET /api/moul/:name/records) accept the following standard query parameters:

ParameterTypeDefaultDescriptionExample
pageinteger11-indexed page number.page=2
perPageinteger30Number of records per page (max 500).perPage=50
sortstring-createdComma-separated sort fields. Prefix with - for descending.sort=-views,title
filterstring""Filter expression evaluated against SQLite records.filter=published=true && views>100
expandstring""Comma-separated relation field names to expand inline.expand=author_id,categories
fieldsstring*Comma-separated fields to return in the payload.fields=id,title,created

Standard List Response Format

{
  "page": 1,
  "perPage": 30,
  "totalItems": 142,
  "totalPages": 5,
  "items": [
    {
      "id": "rec_01J6XYZ123",
      "title": "Getting Started with Moul",
      "slug": "getting-started-with-moul",
      "published": true,
      "views": 420,
      "created_at": "2026-08-01T12:00:00Z",
      "updated_at": "2026-08-02T15:30:00Z"
    }
  ]
}

CRUD Operations

1. List Records (GET /api/moul/:name/records)

curl -s "http://localhost:8090/api/moul/posts/records?page=1&perPage=20&sort=-created&filter=published=true"
const params = new URLSearchParams({
  page: '1',
  perPage: '20',
  sort: '-created',
  filter: 'published = true',
});

const res = await fetch(`http://localhost:8090/api/moul/posts/records?${params}`);
const data = await res.json();
console.log(`Found ${data.totalItems} posts:`, data.items);
req, _ := http.NewRequest("GET", "http://localhost:8090/api/moul/posts/records?page=1&perPage=20", nil)
resp, err := http.DefaultClient.Do(req)
// parse JSON...

2. View Single Record (GET /api/moul/:name/records/:id)

curl -s "http://localhost:8090/api/moul/posts/records/rec_01J6XYZ123"

3. Create Record (POST /api/moul/:name/records)

curl -X POST "http://localhost:8090/api/moul/posts/records" \
  -H "Authorization: Bearer <user_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Deploying on Bare Metal",
    "slug": "deploying-on-bare-metal",
    "content": "A complete walk-through...",
    "published": true
  }'
const res = await fetch('http://localhost:8090/api/moul/posts/records', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${userToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: 'Deploying on Bare Metal',
    slug: 'deploying-on-bare-metal',
    content: 'A complete walk-through...',
    published: true,
  }),
});
const record = await res.json();
payload := map[string]any{
	"title":     "Deploying on Bare Metal",
	"slug":      "deploying-on-bare-metal",
	"published": true,
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "http://localhost:8090/api/moul/posts/records", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+userToken)
req.Header.Set("Content-Type", "application/json")

4. Update Record (PATCH /api/moul/:name/records/:id)

curl -X PATCH "http://localhost:8090/api/moul/posts/records/rec_01J6XYZ123" \
  -H "Authorization: Bearer <user_token>" \
  -H "Content-Type: application/json" \
  -d '{"views": 500}'

5. Delete Record (DELETE /api/moul/:name/records/:id)

curl -X DELETE "http://localhost:8090/api/moul/posts/records/rec_01J6XYZ123" \
  -H "Authorization: Bearer <user_token>"
# Returns HTTP 204 No Content on success

On this page