Basic REST API for a Notes App
Build a small REST API in plain PHP, with no framework, for a notes app. It supports creating, listing, reading, updating and deleting notes, stores them in MySQL through PDO, and always answers in JSON. For example, POST /notes with a title and content creates a note, and GET /notes lists all of them. You'll learn how a web request reaches PHP, how to route it yourself based on the HTTP method and path, how to use PDO prepared statements safely, and how to return proper JSON responses and HTTP status codes. It's a solid first backend project that shows what frameworks do for you behind the scenes.
- Estimate
- ~8.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
PDO · MySQL
Project roadmap
- 01
Set up the project and database
~1.5hInstall PHP 8 and MySQL (or run MySQL with Docker). Create a notes table with id (auto increment), title (up to 200 characters, required), content (text), created_at and updated_at. Save the SQL in schema.sql. Create a db.php file that returns a PDO connection with ERRMODE_EXCEPTION enabled, reading the credentials from environment variables. Done when: schema.sql creates the table and db.php connects without errors.
- 02
Write a simple router
~1.5hCreate public/index.php as the only entry point. Read the method from $_SERVER['REQUEST_METHOD'] and the path from $_SERVER['REQUEST_URI'], and match these routes: GET /notes, GET /notes/{id}, POST /notes, PUT /notes/{id} and DELETE /notes/{id}. Unknown paths return 404 and a wrong method returns 405. Start it with php -S localhost:8000 -t public. Done when: each route reaches its own handler function.
- 03
Create and list notes
~1.5hImplement POST /notes: read the JSON body with json_decode(file_get_contents('php://input'), true), check that title is present and at most 200 characters, and insert with a prepared statement. Return 201 with the created note. Implement GET /notes (newest first) and GET /notes/{id} (404 if missing). Done when: you can create a note with curl and see it in the list.
- 04
Update and delete notes
~1.5hImplement PUT /notes/{id}, which updates the title and content (same validation as creating) and updated_at, and DELETE /notes/{id}, which returns 204 No Content. Both return 404 when the note doesn't exist. Always use prepared statements; never put request values directly into SQL. Done when: updating and deleting work with curl and return the right codes.
- 05
Return consistent JSON
~1hWrite a helper json_response($status, $data) that sets the Content-Type: application/json header and the status code. Make every error use the same shape, {"error":"message"}: 400 for invalid JSON, 422 for validation errors, 404 and 405. Catch database exceptions and return 500 without showing SQL details. Done when: every response, including errors, is valid JSON with the correct status code.
- 06
Test every endpoint
~1.5hWrite a README with a curl example for each endpoint, and a test.sh script that runs them in order (create, list, read, update, delete, then read the deleted note) and checks the status codes. Include the error cases: a missing title, invalid JSON and an unknown id. Done when: test.sh runs and every check passes.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack