MaCH repo

This commit is contained in:
2026-06-15 10:50:06 -05:00
parent 3bb10d7731
commit ff365d9812
+77 -64
View File
@@ -88,9 +88,9 @@ Builds a todo app one concept at a time. See the [Reference](#reference) for ful
* [2. Show Data](#2-show-data)
* [3. Accept Input](#3-accept-input)
* [4. Nested Data](#4-nested-data)
* [5. Tasks](#5-tasks)
* [6. Modules and Events](#6-modules-and-events)
* [7. Calling APIs](#7-calling-apis)
* [5. Calling APIs](#5-calling-apis)
* [6. Tasks](#6-tasks)
* [7. Modules and Events](#7-modules-and-events)
### 1. Pages and Templates
@@ -404,7 +404,65 @@ Register the migration and add a `todo` resource:
Both queries in one `sqlite_query()` call run concurrently. `join()` lifts `comments` inside each `todo_data` record, so the template reaches `{{#comments}}` from within `{{#todo_data}}`. `.must_exist = true` returns 404 when the id matches nothing. See [join](#join) and [query](#query).
### 5. Tasks
### 5. Calling APIs
`fetch()` calls external HTTP services like a query calls a database. JSON parses into context tables; multiple items in one `fetch()` run concurrently.
Show the responses on the home page:
**`home.mustache.html`**
```diff
<html>
<body>
<nav><a href='{{url:home}}'>Home</a> · <a href='{{url:todos}}'>My Todos</a></nav>
<main>
- {{$body}}
- <h1>Welcome</h1>
- {{/body}}
+ {{$body}}
+ <h1>Welcome</h1>
+ {{#weather}}
+ <p>{{city}}: {{precision:temp_c:0}}°C, {{conditions}}</p>
+ {{/weather}}
+ {{#quote}}
+ <blockquote>{{content}}, {{author}}</blockquote>
+ {{/quote}}
+ {{/body}}
</main>
</body>
</html>
```
Fetch both services concurrently before rendering:
**`main.c`**
```diff
#include <mach.h>
#include <sqlite.h>
mach(main){
sqlite_database(
.name = "todos_db",
.connect = "file:todos.db?mode=rwc",
.migrations = {"create_todos_table", "create_comments_table"},
.seeds = {"seed_todos"}
);
resource("home", "/",
.get = {
+ fetch(
+ {"https://api.quotes.dev/random", "quote"},
+ {"https://api.weather.dev/now", "weather"}
+ ),
mustache("home", "home_s"),
respond("home_s")
}
);
```
Both requests run concurrently under one `fetch()` call. The JSON parses into context tables the template walks with `{{#quote}}` and `{{#weather}}`. `fetch()` also supports other verbs, headers, request bodies, and interpolated URLs. See [fetch](#fetch).
### 6. Tasks
A task is a named, reusable pipeline. Define it once with optional `.cron`; dispatch durable background runs with `dispatch_task("name")` (from `dispatch.h`).
@@ -455,6 +513,10 @@ Register the migration, define the tasks, dispatch them from the POST:
+
resource("home", "/",
.get = {
fetch(
{"https://api.quotes.dev/random", "quote"},
{"https://api.weather.dev/now", "weather"}
),
mustache("home", "home_s"),
respond("home_s")
}
@@ -494,7 +556,7 @@ Register the migration, define the tasks, dispatch them from the POST:
`.cron` and `dispatch_task(...)` both run the task on a task reactor, off the request reactors, so the POST returns immediately. Dispatched tasks are durable: a crash mid-task resumes on the next boot. To hand values to a task, list them under `.accepts`; `notify_new_todo` pulls in `title` that way. `dispatch_task()` comes from `dispatch.h`. See [Task Pipelines](#task-pipelines).
### 6. Modules and Events
### 7. Modules and Events
Split features into modules that talk through pub/sub events. A module is a folder with a matching `.c` file (`todos/todos.c`) declaring `mach(todos){ ... }`, which registers the module's resources, databases, tasks, and subscribers. Assets in the folder belong to the module. `main.c` composes modules by `#include`ing each `.c` file; the include is all that is needed.
@@ -554,6 +616,10 @@ This step moves todos into its own module and adds an `activity` module that rec
-
resource("home", "/",
.get = {
fetch(
{"https://api.quotes.dev/random", "quote"},
{"https://api.weather.dev/now", "weather"}
),
mustache("home", "home_s"),
respond("home_s")
}
@@ -602,6 +668,12 @@ Add an Activity link to the shared nav:
<main>
{{$body}}
<h1>Welcome</h1>
{{#weather}}
<p>{{city}}: {{precision:temp_c:0}}°C, {{conditions}}</p>
{{/weather}}
{{#quote}}
<blockquote>{{content}}, {{author}}</blockquote>
{{/quote}}
{{/body}}
</main>
</body>
@@ -739,65 +811,6 @@ mach(activity){
When the POST calls `emit("todo_created")`, MACH propagates the keys named in `publish(...).with` (`title`) to every subscriber. The `activity` module writes its row with no direct link to the publisher. Events are durable: undelivered ones replay after a crash. Adding a third subscriber is a new file with its own `subscribe(...)`; the publisher does not change. See [Modules and Composition](#modules-and-composition) and [Event Pipelines](#event-pipelines).
### 7. Calling APIs
`fetch()` calls external HTTP services like a query calls a database. JSON parses into context tables; multiple items in one `fetch()` run concurrently.
Show the responses on the home page:
**`home.mustache.html`**
```diff
<html>
<body>
<nav><a href='{{url:home}}'>Home</a> · <a href='{{url:todos}}'>My Todos</a> · <a href='{{url:activity}}'>Activity</a></nav>
<main>
- {{$body}}
- <h1>Welcome</h1>
- {{/body}}
+ {{$body}}
+ <h1>Welcome</h1>
+ {{#weather}}
+ <p>{{city}}: {{precision:temp_c:0}}°C, {{conditions}}</p>
+ {{/weather}}
+ {{#quote}}
+ <blockquote>{{content}}, {{author}}</blockquote>
+ {{/quote}}
+ {{/body}}
</main>
</body>
</html>
```
Fetch both services concurrently before rendering:
**`main.c`**
```diff
#include <mach.h>
#include "todos/todos.c"
#include "activity/activity.c"
mach(main){
- resource("home", "/",
- .get = {
- mustache("home", "home_s"),
- respond("home_s")
- }
- );
+ resource("home", "/",
+ .get = {
+ fetch(
+ {"https://api.quotes.dev/random", "quote"},
+ {"https://api.weather.dev/now", "weather"}
+ ),
+ mustache("home", "home_s"),
+ respond("home_s")
+ }
+ );
}
```
Both requests run concurrently under one `fetch()` call. The JSON parses into context tables the template walks with `{{#quote}}` and `{{#weather}}`. `fetch()` also supports other verbs, headers, request bodies, and interpolated URLs. See [fetch](#fetch).
---
## Reference