Creates a new user account with secure password hashing.
This endpoint validates input, prevents duplicate registrations, and ensures passwords are never stored in plaintext.
POST /api/v1/auth/register
{
"email": "user@example.com",
"password": "StrongPassword123"
}Status Code: 201 Created
{
"id": 1,
"email": "user@example.com",
"createdAt": "2026-01-02T12:00:00.000Z"
}{
"message": "Error description",
"statusCode": 400
}Possible Error Messages
- Email and password are required – 400
- Password must be at least 8 characters long – 400
- User already exists – 409
- Internal Server Error – 500
curl -X POST http://localhost:3000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "StrongPassword123"
}'
Authenticates a registered user and returns a JWT token along with user details.
The token allows the client to access protected APIs without storing session data on the server.
POST /api/v1/auth/login
{
"email": "user@example.com",
"password": "StrongPassword123"
}Status Code: 200 OK
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"email": "user@example.com"
}
}{
"message": "Error description",
"statusCode": 400
}Possible Error Messages
- Email and password are required – 400
- User not found – 404
- Invalid email or password - 400
- Internal Server Error – 500
curl -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "StrongPassword123"
}'
Creates a new note for the authenticated user.
Each newly created note automatically creates version 1 in the note version history.
This API requires authentication via JWT. Authorization: Bearer <JWT_TOKEN>
POST /api/v1/notes
{
"title": "My First Note",
"content": "This is the content of my note."
}Status Code: 200 OK
{
"id": 1,
"title": "My First Note",
"content": "This is the content of my note.",
"userId": 1,
"createdAt": "2026-01-02T12:00:00.000Z",
"updatedAt": "2026-01-02T12:00:00.000Z"
}{
"message": "Error description",
"statusCode": 400
}Possible Error Messages:
- Title and content are required – 400
- Access token missing – 401
- Invalid token – 401
curl -X POST http://localhost:3000/api/v1/notes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-d '{
"title": "My First Note",
"content": "This is the content of my note."
}'
Fetches all notes associated with the authenticated user.
Only the latest version of each note is returned.
Historical versions are not included in this response.
This API requires authentication via JWT.
Authorization: Bearer <JWT_TOKEN>
GET /api/v1/notes
Status Code: 200 OK
[
{
"id": 2,
"title": "Meeting Notes",
"content": "Discussion points..."
},
{
"id": 1,
"title": "My First Note",
"content": "This is the content of my note."
}
]curl -X GET http://localhost:3000/api/v1/notes \
-H "Authorization: Bearer <JWT_TOKEN>"
Fetches a specific note by its ID for the authenticated user. Returns the latest note data along with all historical versions.
This API requires authentication via JWT.
Authorization: Bearer <JWT_TOKEN>
GET /api/v1/notes/:id
id– ID of the note to retrieve
Status Code: 200 OK
{
"id": 1,
"title": "Latest note title",
"content": "Latest note content",
"userId": 1,
"createdAt": "2026-01-02T09:00:00.000Z",
"updatedAt": "2026-01-02T12:30:00.000Z",
"versions": [
{
"versionNumber": 1,
"title": "My First Note",
"content": "Initial content"
},
{
"versionNumber": 2,
"title": "My First Note",
"content": "Updated content"
}
]
}curl -X GET http://localhost:3000/api/v1/notes/1 \
-H "Authorization: Bearer <JWT_TOKEN>"
Soft deletes a note for the authenticated user while preserving its version history.
The note will no longer appear in list or detail APIs after deletion.
This API requires authentication via JWT.
Authorization: Bearer <JWT_TOKEN>
DELETE /api/v1/notes/:id
id– ID of the note to delete
Status Code: 200 OK
{
"message": "Note deleted successfully"
}curl -X DELETE http://localhost:3000/api/v1/notes/1 \
-H "Authorization: Bearer <JWT_TOKEN>"
This API allows users to search for their notes using keywords. It uses MySQL full-text search on the title and content columns of the notes table.
- This only searches whole words and words longer than 3 characters (controlled by MySQL’s ft_min_word_len)
- Short words (length < 4) and partial words (e.g., 'con' instead of 'content') are ignored.
GET /api/v1/notes/search?query=<keyword>
Requires authentication via JWT. Authorization: Bearer <JWT_TOKEN>
curl -X GET "http://localhost:3000/api/v1/notes/search?query=meeting" \
-H "Authorization: Bearer <JWT_TOKEN>"
Updates an existing note for the authenticated user.
This API supports partial updates, meaning either title or content (or both) must be provided.
To prevent concurrent updates, optimistic locking is enforced using a version field.
If the provided version does not match the latest version stored in the database, the update is rejected.
This API requires authentication via JWT.
Authorization: Bearer <JWT_TOKEN>
POST /api/v1/notes/:id
id– ID of the note to delete
{
"title": "Updated Title",
"content": "Updated content",
"version": 2
}- version is mandatory
- At least one of title or content must be provided
Status Code: 200 OK
{
"id": 2,
"user_id": 2,
"title": "lets update",
"content": "note 2 content",
"version": 3,
"createdAt": "2026-01-03T08:56:27.000Z",
"updatedAt": "2026-01-04T10:42:58.532Z",
"deletedAt": null
}
curl -X POST http://localhost:3000/api/v1/notes/1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-d '{
"content": "Updated note content",
"version": 2
}'
Reverts a note to a specified previous version.
This operation does not delete history.
Instead, it creates a new version using the content of the selected historical version.
This API requires authentication via JWT.
Authorization: Bearer <JWT_TOKEN>
POST /api/v1/notes/:id/revert
{
"targetVersion": 1,
"currentVersion": 3
}curl -X POST http://localhost:3000/api/v1/notes/1/revert \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-d '{
"targetVersion": 1,
"currentVersion": 3
}'