Full CRUD API Lifecycle
Welcome to the Full CRUD API Lifecycle documentation!
One of the most common requirements for API testing is verifying the complete lifecycle of a resource. This guarantees that your database and API contract remain stable across state mutations.
In this example, we will build a 4-step workflow that creates an item, retrieves it, updates it, and finally deletes it.
1. Create the Item (POST)
First, we create 1_create.toml. This request issues a POST, asserts a 201 Created status, and extracts the dynamically generated item_id so subsequent requests know which resource to target.
name = "Create Item"
[request]
method = "POST"
url = "{{base_url}}/items"
[body]
type = "json"
raw = '{"name": "Test Item", "price": 99.99}'
[extract]
item_id = "json.id"
[assert]
status = 201
body_contains = "Test Item"
2. Read the Item (GET)
Next, we create 2_read.toml. We must define a dependency on the create node so Rumour knows to wait for the item_id.
name = "Read Item"
[dependencies]
"1_create.toml" = "item_id"
[request]
method = "GET"
url = "{{base_url}}/items/{{item_id}}"
[assert]
status = 200
"json.price" = { equal = 99.99 }
3. Update the Item (PUT)
Now we update the item to test mutability. Create 3_update.toml. We depend on the read node to enforce strict sequential ordering (Create -> Read -> Update).
name = "Update Item"
[dependencies]
"2_read.toml" = "item_id"
[request]
method = "PUT"
url = "{{base_url}}/items/{{item_id}}"
[body]
type = "json"
raw = '{"name": "Updated Item", "price": 150.00}'
[assert]
status = 200
"json.price" = { equal = 150.00 }
4. Delete the Item (DELETE)
Finally, we clean up the state by deleting the resource. Create 4_delete.toml.
name = "Delete Item"
[dependencies]
"3_update.toml" = "item_id"
[request]
method = "DELETE"
url = "{{base_url}}/items/{{item_id}}"
[assert]
status = 204
Running the Lifecycle
When you run the directory containing these 4 files, Rumour's dependency engine guarantees they run in the exact necessary order: 1_create -> 2_read -> 3_update -> 4_delete.
rumour run ./crud_suite/ -v
Execution Trace
POST http://localhost:3000/items
✓ SUCCESS: ./crud_suite/1_create.toml (45ms)
GET http://localhost:3000/items/101
✓ SUCCESS: ./crud_suite/2_read.toml (12ms)
PUT http://localhost:3000/items/101
✓ SUCCESS: ./crud_suite/3_update.toml (23ms)
DELETE http://localhost:3000/items/101
✓ SUCCESS: ./crud_suite/4_delete.toml (18ms)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 4 │
│ Successful: 4 │
│ Failed: 0 │
│ Skipped: 0 │
│ Success Rate: 100.0% │
│ Total Time: 98ms │
╰──────────────────────────────────────────────────────────────────────────╯
✓ Successful Requests:
- ./crud_suite/1_create.toml [201] [45ms]
- ./crud_suite/2_read.toml [200] [12ms]
- ./crud_suite/3_update.toml [200] [23ms]
- ./crud_suite/4_delete.toml [204] [18ms]
By structuring your tests this way, you ensure that test state is completely ephemeral. The resource is created and destroyed within the same run, preventing database bloat and avoiding flaky tests caused by stale data.