soma.cell

CRUD API for Users

Full Create-Read-Update-Delete API using JSON serialization. Serve: soma serve 042_crud_api.cell Test: curl -X POST localhost:8080/create?name=Alice&[email protected] curl localhost:8080/get/1 curl localhost:8080/list

Example 042 of the basic Soma programs: a small, commented program that teaches one thing. Every output below was printed by soma 3.2.4 when this page was built.

How it is built

The cell UserCRUD declares 6 signals in its face: create(name: String, email: String) -> String, get(id: String) -> String, list_all() -> String, update(id: String, name: String) -> String, delete(id: String) -> Map and demo() -> String; keeps 2 memory slots: users (Map<String, String>, persistent and consistent) and meta (Map<String, Int>, persistent and consistent). Handlers: create (line 32), get (line 48), list_all (line 56), update (line 65), delete (line 76) and demo (line 85).

Generated from soma describe on this file.

The source

042_crud_api.cell

// ============================================================================
// 042 — CRUD API for Users
// ============================================================================
// Full Create-Read-Update-Delete API using JSON serialization.
//
// Serve: soma serve 042_crud_api.cell
// Test:  curl -X POST localhost:8080/create?name=Alice&[email protected]
//        curl localhost:8080/get/1
//        curl localhost:8080/list
//
// Run:   soma run 042_crud_api.cell demo
// Expect:
//   Created: {"id": 1, "name": "Alice", "email": "[email protected]"}
//   Created: {"id": 2, "name": "Bob", "email": "[email protected]"}
//   All users: 2

cell UserCRUD {
    face {
        signal create(name: String, email: String) -> String
        signal get(id: String) -> String
        signal list_all() -> String
        signal update(id: String, name: String) -> String
        signal delete(id: String) -> Map
        signal demo() -> String
    }

    memory {
        users: Map<String, String> [persistent, consistent]
        meta: Map<String, Int> [persistent, consistent]
    }

    on create(name: String, email: String) {
        // Auto-increment ID
        let current = meta.get("next_id")
        if current == () {
            meta.set("next_id", 1)
        }
        let id = meta.get("next_id")
        meta.set("next_id", id + 1)
        let id_str = to_string(id)

        // Store as JSON
        let user = map("id", id, "name", name, "email", email)
        users.set(id_str, to_json(user))
        return user
    }

    on get(id: String) {
        let raw = users.get(id)
        if raw == () {
            return response(404, map("error", "user not found"))
        }
        return from_json(raw)
    }

    on list_all() {
        let keys = users.keys()
        let result = list()
        for key in keys {
            result = list(result, from_json(users.get(key)))
        }
        return result
    }

    on update(id: String, name: String) {
        let raw = users.get(id)
        if raw == () {
            return response(404, map("error", "user not found"))
        }
        let existing = from_json(raw)
        let updated = map("id", id, "name", name, "email", existing.email)
        users.set(id, to_json(updated))
        return updated
    }

    on delete(id: String) {
        let existed = users.delete(id)
        if existed == false {
            return response(404, map("error", "user not found"))
        }
        return map("deleted", id)
    }

    // Self-contained demo
    on demo() {
        let u1 = create("Alice", "[email protected]")
        print("Created: {u1}")
        let u2 = create("Bob", "[email protected]")
        print("Created: {u2}")
        let all = list_all()
        let count = all.length
        print("All users: {count}")
        return "done"
    }
}

What the toolchain says

$ soma check 042_crud_api.cell
warning: handler 'create' returns a Map (`user`) but its face declares `-> String` — fix the value or the face (an error in edition 2027)
  --> 042_crud_api.cell:45:16
   |
45 |         return user
   |                ^
warning: handler 'update' returns a Map (`updated`) but its face declares `-> String` — fix the value or the face (an error in edition 2027)
  --> 042_crud_api.cell:73:16
   |
73 |         return updated
   |                ^
✓ 2 warning(s), no errors.
$ soma run 042_crud_api.cell demo
error: create(): the face declares `-> String` but the handler returned Map {"id": 1, "name": "Alice", "email": "ali
  --> 042_crud_api.cell:45:16
   |
45 |         return user
   |                ^