A simple REST API built with Python, Flask, and SQLite for creating, reading, updating, and deleting short text notes.
This project is designed as a beginner-friendly introduction to building APIs with Flask and working with a SQLite database using Python's built-in sqlite3 module.
The Notes Keeper API provides a small but complete backend application with:
- Flask REST API
- SQLite database
- Single
notestable - CRUD operations
- JSON request and response handling
- HTTP status codes
- Parameterized SQL queries
- Flask's built-in test client
The project intentionally keeps the architecture simple so that the fundamental API โ database โ response workflow becomes clear.
- Python 3
- Flask
- SQLite
- sqlite3 โ Python's built-in SQLite database module
- JSON โ API request/response format
notes-api/
โ
โโโ 01_basic_notes_api.ipynb
โโโ notes_basic.db
โโโ README.md
notes_basic.dbis created by the application when the database is initialized.
git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git
cd YOUR-REPOSITORYInstall Flask using pip:
pip install flaskOr:
python -m pip install flaskOpen the notebook:
01_basic_notes_api.ipynb
Run the cells from top to bottom.
The notebook initializes the SQLite database, creates the notes table, registers the Flask routes, and tests the API using Flask's built-in test client.
The application uses a SQLite database:
notes_basic.db
The database contains one table:
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);| Field | Type | Description |
|---|---|---|
id |
INTEGER | Unique automatically generated note ID |
content |
TEXT | Text content of the note |
created_at |
TEXT | Timestamp when the note was created |
The API contains five endpoints.
| Method | Endpoint | Description |
|---|---|---|
GET |
/notes |
Get all notes |
GET |
/notes/<id> |
Get one note |
POST |
/notes |
Create a new note |
PUT |
/notes/<id> |
Update an existing note |
DELETE |
/notes/<id> |
Delete a note |
GET /notes[
{
"id": 2,
"content": "Walk the dog",
"created_at": "2026-08-11 05:23:03"
},
{
"id": 1,
"content": "Buy milk",
"created_at": "2026-08-11 05:23:03"
}
]Notes are returned with the newest note first.
GET /notes/1{
"id": 1,
"content": "Buy milk",
"created_at": "2026-08-11 05:23:03"
}If the requested note does not exist, the API returns:
404 Not Found
POST /notes{
"content": "Learn Flask"
}{
"id": 3,
"content": "Learn Flask"
}201 Created
The API uses 201 Created because a new note has been successfully created.
If content is missing:
400 Bad Request
PUT /notes/1{
"content": "Learn Flask deeply"
}{
"id": 1,
"content": "Learn Flask deeply"
}200 OK
If the note does not exist:
404 Not Found
DELETE /notes/1If the note is successfully deleted:
204 No Content
The response body is empty because there is no additional information that needs to be returned.
If the note does not exist:
404 Not Found
Database values are passed using SQLite parameterized queries.
For example:
conn.execute(
"SELECT * FROM notes WHERE id = ?",
(note_id,)
)Instead of directly inserting values into SQL strings.
This keeps user-provided values separate from the SQL statement and avoids unsafe string-based SQL construction.
The basic application follows this flow:
Client
โ
โ HTTP Request
โผ
Flask Route
โ
โผ
Database Connection
โ
โผ
SQL Query
โ
โผ
SQLite Database
โ
โผ
Query Result
โ
โผ
JSON Response
โ
โผ
Client
The core development loop is:
Connect
โ
Query
โ
Commit (when changing data)
โ
Convert result to JSON
โ
Return HTTP response
The project uses Flask's built-in test client:
client = app.test_client()This allows the API to be tested directly without starting a separate web server.
response = client.post(
"/notes",
json={"content": "Buy milk"}
)response = client.get("/notes")response = client.put(
"/notes/1",
json={"content": "Buy oat milk"}
)response = client.delete("/notes/2")The project demonstrates several important HTTP status codes:
| Status | Meaning | Used For |
|---|---|---|
200 |
OK | Successful GET/PUT |
201 |
Created | Successfully creating a note |
204 |
No Content | Successfully deleting a note |
400 |
Bad Request | Missing required content |
404 |
Not Found | Note does not exist |
This project focuses on the fundamentals of backend API development:
- Flask application setup
- Flask routes
- HTTP methods
- REST API structure
- JSON requests
- JSON responses
- SQLite database connections
- SQL
SELECT - SQL
INSERT - SQL
UPDATE - SQL
DELETE - Database transactions
commit()fetchone()fetchall()rowcount- Parameterized SQL queries
- HTTP status codes
- Error handling with
abort() - Flask test client
The API follows the standard CRUD pattern:
CREATE
POST /notes
READ
GET /notes
GET /notes/<id>
UPDATE
PUT /notes/<id>
DELETE
DELETE /notes/<id>
This is intentionally a Basic API.
It currently contains:
- One database table
- No table relationships
- No foreign keys
- No authentication
- No authorization
- No query filtering
- Basic error handling
- No pagination
These limitations are intentional so the core Flask + SQLite workflow can be learned first.
The next version of the project can build on this same architecture.
The planned intermediate project adds:
- Query filtering such as:
?done=true
- Global Flask error handling
- Consistent JSON error responses
The advanced project introduces:
- A second database table
- Foreign keys
- Relationships between tables
- Queries involving multiple tables
This allows the project to progress from a single-table API toward a more realistic backend architecture.
The main goal of this project is to understand the complete backend cycle:
HTTP Request
โ
Flask
โ
Route
โ
Python
โ
SQLite
โ
SQL
โ
Database Result
โ
JSON
โ
HTTP Response
Once this cycle becomes familiar, more advanced backend concepts such as validation, authentication, filtering, relationships, PostgreSQL, and larger application architectures can be added on top.
Developed as a learning project for understanding Flask REST APIs and SQLite database integration.
Notes Keeper API is a minimal Flask REST API that demonstrates how a Python backend receives HTTP requests, performs SQL operations on a SQLite database, and returns JSON responses.
It provides a complete beginner-level implementation of CRUD operations using Flask + SQLite.