- scaffold 14 placeholder crates (app, db, engine, gen, http, logic,
policy, ql, service, sub, txn, ui, value, wal) — empty Cargo.toml +
src/lib.rs to receive code phase-by-phase from `rt`
- restructure docs/examples/ecommerce into multi-app layout: apps/admin
and apps/storefront, with shared/ types/logic/components, per-app
app.wo + wo.toml, and reusable .htmlx components (layout, money,
order-row)
- add reference/rest/{blog,ecommerce}.rest — VS Code/JetBrains HTTP
request files driving the running prototype, including 501/404/405
expectations for stubbed endpoints
- add docs/plan/09-concurrency-scaleout.md and docs/plan/ui/00-overview.md;
refine docs/plan/assembly/02-writeonce-stance.md
- refresh templates (about, article, header/footer, home, layout, styles)
and add static favicon/logo
- add infra/sync.sh and tighten .gitignore for reference/ symlinks
181 lines
5.9 KiB
ReStructuredText
181 lines
5.9 KiB
ReStructuredText
###############################################################################
|
|
# blog.rest — exercise the `.wo` runtime against docs/examples/blog/
|
|
#
|
|
# Start the server first:
|
|
# cargo run --bin wo -- run docs/examples/blog
|
|
#
|
|
# Then in VS Code (REST Client extension) or JetBrains (HTTP Client):
|
|
# click "Send Request" on each block, top to bottom
|
|
#
|
|
# Response back-references (# @name foo → {{foo.response.body.id}}) are
|
|
# supported by both clients — later blocks pick up ids minted by earlier
|
|
# blocks automatically. For `curl` equivalents, see reference/rest/README.md.
|
|
###############################################################################
|
|
|
|
@host = http://127.0.0.1:8080
|
|
|
|
|
|
### Runtime info — expected 200
|
|
GET {{host}}/
|
|
|
|
### Liveness probe — expected 200 "ok"
|
|
GET {{host}}/healthz
|
|
|
|
|
|
###############################################################################
|
|
# Author — exposes: list, get, me, subscribe
|
|
###############################################################################
|
|
|
|
### List authors (empty on fresh boot) — expected 200 []
|
|
GET {{host}}/api/authors
|
|
|
|
### Author create is NOT exposed in the blog sample (expose list, get, me, subscribe)
|
|
# Expected 405 — method not allowed. The sample expects authors seeded by
|
|
# `on startup do: seed_admin()` in app.wo. Stage 2 doesn't run startup hooks
|
|
# yet, so the list above will be empty.
|
|
POST {{host}}/api/authors
|
|
Content-Type: application/json
|
|
|
|
{ "email": "alice@example.com", "handle": "alice", "display": "Alice" }
|
|
|
|
### /me — Stage 3 session layer; expected 501
|
|
GET {{host}}/api/authors/me
|
|
|
|
### LIVE subscribe — Stage 3; expected 501
|
|
GET {{host}}/api/authors/live
|
|
|
|
|
|
###############################################################################
|
|
# Article — exposes: list, get, create, update, delete, subscribe
|
|
###############################################################################
|
|
|
|
### Create an article — expected 201
|
|
# @name createArticle
|
|
POST {{host}}/api/articles
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"slug": "hello-writeonce",
|
|
"title": "Hello, writeonce",
|
|
"author": 1,
|
|
"published": true,
|
|
"meta": {
|
|
"excerpt": "First post on the new runtime.",
|
|
"body_md": "# Hi\n\nHello from the `.wo` runtime. The server, the database, and this HTTP API are all one binary.\n"
|
|
}
|
|
}
|
|
|
|
### Create a second article (draft) — expected 201
|
|
# @name createDraft
|
|
POST {{host}}/api/articles
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"slug": "second-draft",
|
|
"title": "Second Post (draft)",
|
|
"author": 1,
|
|
"published": false,
|
|
"meta": { "excerpt": "", "body_md": "WIP." }
|
|
}
|
|
|
|
### List articles — expected 200 with 2 rows
|
|
GET {{host}}/api/articles
|
|
|
|
### Get one article by id — expected 200
|
|
GET {{host}}/api/articles/{{createArticle.response.body.id}}
|
|
|
|
### Partial update (PATCH) — change just the title — expected 200
|
|
PATCH {{host}}/api/articles/{{createArticle.response.body.id}}
|
|
Content-Type: application/json
|
|
|
|
{ "title": "Hi, writeonce!" }
|
|
|
|
### Partial update of an embedded-document field — expected 200
|
|
# Note: Stage 2's PATCH does a shallow merge at the top level.
|
|
# To change `meta.excerpt` alone you re-send the whole `meta` object.
|
|
PATCH {{host}}/api/articles/{{createArticle.response.body.id}}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"meta": { "excerpt": "Updated excerpt.", "body_md": "# Hi\n\nUpdated body." }
|
|
}
|
|
|
|
### Publish the draft — expected 200 (`on update` trigger that sets
|
|
### `published_at` is Stage 3+; Stage 2 just records the bool change).
|
|
PATCH {{host}}/api/articles/{{createDraft.response.body.id}}
|
|
Content-Type: application/json
|
|
|
|
{ "published": true }
|
|
|
|
### Delete the draft — expected 204 No Content
|
|
DELETE {{host}}/api/articles/{{createDraft.response.body.id}}
|
|
|
|
### Get the deleted id — expected 404
|
|
GET {{host}}/api/articles/{{createDraft.response.body.id}}
|
|
|
|
### LIVE subscribe (Article) — Stage 3; expected 501
|
|
GET {{host}}/api/articles/live
|
|
|
|
|
|
###############################################################################
|
|
# Tag — exposes: list, get, subscribe
|
|
###############################################################################
|
|
|
|
### List tags — expected 200 [] (create is not exposed)
|
|
GET {{host}}/api/tags
|
|
|
|
### Tag create NOT exposed (expose list, get, subscribe) — expected 405
|
|
POST {{host}}/api/tags
|
|
Content-Type: application/json
|
|
|
|
{ "slug": "rust", "label": "Rust" }
|
|
|
|
### LIVE subscribe (Tag) — Stage 3; expected 501
|
|
GET {{host}}/api/tags/live
|
|
|
|
|
|
###############################################################################
|
|
# Comment — exposes: list, get, create, update, delete, subscribe
|
|
###############################################################################
|
|
|
|
### Create a comment — expected 201
|
|
# @name createComment
|
|
POST {{host}}/api/comments
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"article": {{createArticle.response.body.id}},
|
|
"author": 1,
|
|
"body": "Nice post. Runs on one binary which is still weird to me."
|
|
}
|
|
|
|
### List comments — expected 200 with 1 row
|
|
GET {{host}}/api/comments
|
|
|
|
### Get one comment — expected 200
|
|
GET {{host}}/api/comments/{{createComment.response.body.id}}
|
|
|
|
### Update comment body — expected 200 (the `on update when old.body != new.body
|
|
### do set self.edited_at = now()` trigger is Stage 3+; edited_at stays unset)
|
|
PATCH {{host}}/api/comments/{{createComment.response.body.id}}
|
|
Content-Type: application/json
|
|
|
|
{ "body": "Edited: really, one binary? Neat." }
|
|
|
|
### Delete comment — expected 204
|
|
DELETE {{host}}/api/comments/{{createComment.response.body.id}}
|
|
|
|
### LIVE subscribe (Comment) — Stage 3; expected 501
|
|
GET {{host}}/api/comments/live
|
|
|
|
|
|
###############################################################################
|
|
# Final state — should show the updated article still there, no drafts,
|
|
# no comments (all deleted above).
|
|
###############################################################################
|
|
|
|
### Final article list — expected 200 with 1 row
|
|
GET {{host}}/api/articles
|
|
|
|
### Final comment list — expected 200 []
|
|
GET {{host}}/api/comments
|