Implement Sprint 1: Notebook Management CRUD
- Add NotebookService with full CRUD operations
- Add POST /api/v1/notebooks (create notebook)
- Add GET /api/v1/notebooks (list with pagination)
- Add GET /api/v1/notebooks/{id} (get by ID)
- Add PATCH /api/v1/notebooks/{id} (partial update)
- Add DELETE /api/v1/notebooks/{id} (delete)
- Add Pydantic models for requests/responses
- Add custom exceptions (ValidationError, NotFoundError, NotebookLMError)
- Add comprehensive unit tests (31 tests, 97% coverage)
- Add API integration tests (26 tests)
- Fix router prefix duplication
- Fix JSON serialization in error responses
BREAKING CHANGE: None
513 lines
9.8 KiB
Markdown
513 lines
9.8 KiB
Markdown
# API Endpoints Documentation
|
|
|
|
> NotebookLM Agent API - Endpoint Reference
|
|
|
|
**Version**: 0.1.0
|
|
**Base URL**: `http://localhost:8000`
|
|
**OpenAPI**: `/docs` (Swagger UI)
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
All API requests require an API key in the `X-API-Key` header:
|
|
|
|
```bash
|
|
X-API-Key: your-api-key-here
|
|
```
|
|
|
|
### Example
|
|
|
|
```bash
|
|
curl http://localhost:8000/api/v1/notebooks \
|
|
-H "X-API-Key: your-api-key"
|
|
```
|
|
|
|
### Error Response (401 Unauthorized)
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "AUTH_ERROR",
|
|
"message": "API key required",
|
|
"details": null
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-04-06T10:30:00Z",
|
|
"request_id": "550e8400-e29b-41d4-a716-446655440000"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Notebooks
|
|
|
|
### Create Notebook
|
|
|
|
Create a new notebook.
|
|
|
|
**Endpoint**: `POST /api/v1/notebooks`
|
|
|
|
#### Request
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/v1/notebooks \
|
|
-H "X-API-Key: your-api-key" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"title": "My Research Notebook",
|
|
"description": "A collection of AI research papers"
|
|
}'
|
|
```
|
|
|
|
**Request Body**:
|
|
|
|
```json
|
|
{
|
|
"title": "string (required, min: 3, max: 100)",
|
|
"description": "string (optional, max: 500)"
|
|
}
|
|
```
|
|
|
|
#### Success Response (201 Created)
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"title": "My Research Notebook",
|
|
"description": "A collection of AI research papers",
|
|
"created_at": "2026-04-06T10:30:00Z",
|
|
"updated_at": "2026-04-06T10:30:00Z"
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-04-06T10:30:00Z",
|
|
"request_id": "550e8400-e29b-41d4-a716-446655440000"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Error Responses
|
|
|
|
**400 Bad Request** - Validation Error
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Invalid input data",
|
|
"details": [
|
|
{
|
|
"field": "title",
|
|
"error": "Title must be at least 3 characters"
|
|
}
|
|
]
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-04-06T10:30:00Z",
|
|
"request_id": "550e8400-e29b-41d4-a716-446655440000"
|
|
}
|
|
}
|
|
```
|
|
|
|
**401 Unauthorized** - Missing/Invalid API Key
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "AUTH_ERROR",
|
|
"message": "API key required"
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
**502 Bad Gateway** - NotebookLM API Error
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "NOTEBOOKLM_ERROR",
|
|
"message": "External API error: rate limit exceeded"
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### List Notebooks
|
|
|
|
List all notebooks with pagination.
|
|
|
|
**Endpoint**: `GET /api/v1/notebooks`
|
|
|
|
#### Request
|
|
|
|
```bash
|
|
# Basic request
|
|
curl http://localhost:8000/api/v1/notebooks \
|
|
-H "X-API-Key: your-api-key"
|
|
|
|
# With pagination
|
|
curl "http://localhost:8000/api/v1/notebooks?limit=10&offset=0&sort=created_at&order=desc" \
|
|
-H "X-API-Key: your-api-key"
|
|
|
|
# Sort by title ascending
|
|
curl "http://localhost:8000/api/v1/notebooks?sort=title&order=asc" \
|
|
-H "X-API-Key: your-api-key"
|
|
```
|
|
|
|
**Query Parameters**:
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `limit` | integer | 20 | Max items per page (1-100) |
|
|
| `offset` | integer | 0 | Items to skip |
|
|
| `sort` | string | "created_at" | Sort field: `created_at`, `updated_at`, `title` |
|
|
| `order` | string | "desc" | Sort order: `asc`, `desc` |
|
|
|
|
#### Success Response (200 OK)
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"items": [
|
|
{
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"title": "My Research Notebook",
|
|
"description": "A collection of AI research papers",
|
|
"created_at": "2026-04-06T10:00:00Z",
|
|
"updated_at": "2026-04-06T10:30:00Z"
|
|
},
|
|
{
|
|
"id": "550e8400-e29b-41d4-a716-446655440001",
|
|
"title": "Another Notebook",
|
|
"description": null,
|
|
"created_at": "2026-04-06T09:00:00Z",
|
|
"updated_at": "2026-04-06T09:00:00Z"
|
|
}
|
|
],
|
|
"pagination": {
|
|
"total": 100,
|
|
"limit": 20,
|
|
"offset": 0,
|
|
"has_more": true
|
|
}
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-04-06T10:30:00Z",
|
|
"request_id": "550e8400-e29b-41d4-a716-446655440000"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Error Responses
|
|
|
|
**401 Unauthorized** - Missing/Invalid API Key
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "AUTH_ERROR",
|
|
"message": "API key required"
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Get Notebook
|
|
|
|
Get a single notebook by ID.
|
|
|
|
**Endpoint**: `GET /api/v1/notebooks/{notebook_id}`
|
|
|
|
#### Request
|
|
|
|
```bash
|
|
curl http://localhost:8000/api/v1/notebooks/550e8400-e29b-41d4-a716-446655440000 \
|
|
-H "X-API-Key: your-api-key"
|
|
```
|
|
|
|
**Path Parameters**:
|
|
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `notebook_id` | UUID | Notebook unique identifier |
|
|
|
|
#### Success Response (200 OK)
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"title": "My Research Notebook",
|
|
"description": "A collection of AI research papers",
|
|
"created_at": "2026-04-06T10:00:00Z",
|
|
"updated_at": "2026-04-06T10:30:00Z"
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-04-06T10:30:00Z",
|
|
"request_id": "550e8400-e29b-41d4-a716-446655440000"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Error Responses
|
|
|
|
**404 Not Found** - Notebook doesn't exist
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "NOT_FOUND",
|
|
"message": "Notebook with id '550e8400-e29b-41d4-a716-446655440000' not found"
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
**400 Bad Request** - Invalid UUID format
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Invalid notebook ID format"
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Update Notebook
|
|
|
|
Update an existing notebook (partial update).
|
|
|
|
**Endpoint**: `PATCH /api/v1/notebooks/{notebook_id}`
|
|
|
|
#### Request
|
|
|
|
```bash
|
|
# Update title only
|
|
curl -X PATCH http://localhost:8000/api/v1/notebooks/550e8400-e29b-41d4-a716-446655440000 \
|
|
-H "X-API-Key: your-api-key" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"title": "Updated Title"
|
|
}'
|
|
|
|
# Update description only
|
|
curl -X PATCH http://localhost:8000/api/v1/notebooks/550e8400-e29b-41d4-a716-446655440000 \
|
|
-H "X-API-Key: your-api-key" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"description": "Updated description"
|
|
}'
|
|
|
|
# Update both
|
|
curl -X PATCH http://localhost:8000/api/v1/notebooks/550e8400-e29b-41d4-a716-446655440000 \
|
|
-H "X-API-Key: your-api-key" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"title": "Updated Title",
|
|
"description": "Updated description"
|
|
}'
|
|
```
|
|
|
|
**Request Body**:
|
|
|
|
```json
|
|
{
|
|
"title": "string (optional, min: 3, max: 100)",
|
|
"description": "string (optional, max: 500)"
|
|
}
|
|
```
|
|
|
|
**Note**: Only provided fields are updated. At least one field must be provided.
|
|
|
|
#### Success Response (200 OK)
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"title": "Updated Title",
|
|
"description": "Updated description",
|
|
"created_at": "2026-04-06T10:00:00Z",
|
|
"updated_at": "2026-04-06T11:00:00Z"
|
|
},
|
|
"meta": {
|
|
"timestamp": "2026-04-06T11:00:00Z",
|
|
"request_id": "550e8400-e29b-41d4-a716-446655440000"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Error Responses
|
|
|
|
**400 Bad Request** - Validation Error
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Invalid input data",
|
|
"details": [
|
|
{
|
|
"field": "title",
|
|
"error": "Title must be at least 3 characters"
|
|
}
|
|
]
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
**404 Not Found** - Notebook doesn't exist
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "NOT_FOUND",
|
|
"message": "Notebook with id '...' not found"
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Delete Notebook
|
|
|
|
Delete a notebook permanently.
|
|
|
|
**Endpoint**: `DELETE /api/v1/notebooks/{notebook_id}`
|
|
|
|
#### Request
|
|
|
|
```bash
|
|
curl -X DELETE http://localhost:8000/api/v1/notebooks/550e8400-e29b-41d4-a716-446655440000 \
|
|
-H "X-API-Key: your-api-key"
|
|
```
|
|
|
|
#### Success Response (204 No Content)
|
|
|
|
Empty body.
|
|
|
|
#### Error Responses
|
|
|
|
**404 Not Found** - Notebook doesn't exist
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "NOT_FOUND",
|
|
"message": "Notebook with id '...' not found"
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
**Note**: This operation is idempotent. Deleting the same notebook twice returns 404 on the second attempt.
|
|
|
|
---
|
|
|
|
## Common Workflows
|
|
|
|
### Create and List Notebooks
|
|
|
|
```bash
|
|
# 1. Create a notebook
|
|
NOTEBOOK=$(curl -s -X POST http://localhost:8000/api/v1/notebooks \
|
|
-H "X-API-Key: your-key" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"title": "AI Research"}' | jq -r '.data.id')
|
|
|
|
# 2. List all notebooks
|
|
curl http://localhost:8000/api/v1/notebooks \
|
|
-H "X-API-Key: your-key"
|
|
|
|
# 3. Get specific notebook
|
|
curl http://localhost:8000/api/v1/notebooks/$NOTEBOOK \
|
|
-H "X-API-Key: your-key"
|
|
```
|
|
|
|
### Update and Delete
|
|
|
|
```bash
|
|
NOTEBOOK_ID="550e8400-e29b-41d4-a716-446655440000"
|
|
|
|
# Update title
|
|
curl -X PATCH http://localhost:8000/api/v1/notebooks/$NOTEBOOK_ID \
|
|
-H "X-API-Key: your-key" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"title": "New Title"}'
|
|
|
|
# Delete notebook
|
|
curl -X DELETE http://localhost:8000/api/v1/notebooks/$NOTEBOOK_ID \
|
|
-H "X-API-Key: your-key"
|
|
```
|
|
|
|
---
|
|
|
|
## Error Codes
|
|
|
|
| Code | HTTP Status | Description |
|
|
|------|-------------|-------------|
|
|
| `VALIDATION_ERROR` | 400 | Input validation failed |
|
|
| `AUTH_ERROR` | 401 | Authentication failed (missing/invalid API key) |
|
|
| `NOT_FOUND` | 404 | Resource not found |
|
|
| `RATE_LIMITED` | 429 | Rate limit exceeded |
|
|
| `NOTEBOOKLM_ERROR` | 502 | External NotebookLM API error |
|
|
|
|
---
|
|
|
|
## Rate Limiting
|
|
|
|
API requests are rate-limited to prevent abuse. Rate limit headers are included in responses:
|
|
|
|
```http
|
|
X-RateLimit-Limit: 100
|
|
X-RateLimit-Remaining: 95
|
|
X-RateLimit-Reset: 1712400000
|
|
```
|
|
|
|
If you exceed the rate limit, you'll receive a `429 Too Many Requests` response:
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "RATE_LIMITED",
|
|
"message": "Rate limit exceeded. Try again in 60 seconds.",
|
|
"details": [{"retry_after": 60}]
|
|
},
|
|
"meta": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
*Documentazione generata automaticamente da @api-designer*
|
|
*Data: 2026-04-06*
|
|
*Versione API: 0.1.0*
|