Module 01 · foundations · beginner
Exercises 01 · Text Post API
Start from workflow/starter.json (a linear Webhook → Build Post → Respond, with no validation: every request "creates" a post, even an empty one).
Exercise 1: Reject empty posts
Task: Add an IF node so requests without a text take a different path.
Done when: curl ... -d '{}' returns a different body than -d '{"text":"Shipped my first n8n API"}'.
Hint
Put the IF between the Webhook and Build Post. Check {{ $json.body.text }} with the is not empty operator.
Exercise 2: Return proper status codes
Task: Make a created post return HTTP 201, and a rejected one return 400 with {"error":"text must be 1-280 characters"}.
Done when: a valid post shows 201 and curl -d '{}' shows 400 (add -w '%{http_code}' to see the code).
Hint
You need two Respond to Webhook nodes, one per branch. The status code is under Options → Response Code, on each node.
Exercise 3: Enforce the 280-character limit
Task: Reject posts longer than 280 characters with the same 400 error.
Done when: ./test/test.sh passes all five checks.
Hint
Add a second condition to the same IF, combined with AND: {{ ($json.body.text || '').length }} is less than or equal to 280 (Number). The || '' keeps it from failing when text is missing.
Exercise 4: Go to production
Task: Publish the workflow and call the production URL instead of the test URL.
Done when: curl -X POST http://localhost:5678/webhook/posts ... works without clicking Listen, and the run shows in the Executions tab.
Hint
The production path is /webhook/, not /webhook-test/.
Stretch: Pull out hashtags
Task: Add a hashtags array to the created post, e.g. "Shipping #n8n #nocode" returns ["n8n","nocode"].
Hint
Add a field of type Array in Build Post. String.match() with a regex finds every #word; remember it returns null when there are none.