-
Notifications
You must be signed in to change notification settings - Fork 0
API Documentation
Complete REST API reference for Photo Map MVP - endpoints, request/response schemas, authentication, and interactive Swagger UI.
- Swagger UI
- Authentication Flow
- Authentication Endpoints
- Photo Endpoints
- Admin Endpoints
- DTOs & Validation
- Error Responses
- Example Requests
Interactive API Documentation and Testing
After starting the backend:
URL: http://localhost:8080/swagger-ui/index.html
OpenAPI JSON: http://localhost:8080/v3/api-docs
- β Interactive API testing (send requests directly from browser)
- β JWT authentication support (Bearer token)
- β All REST endpoints documented automatically
- β Request/response schemas with validation rules
- β Try-it-out functionality for each endpoint
-
Start backend:
./scripts/start-dev.sh -
Open Swagger UI: http://localhost:8080/swagger-ui/index.html
-
Login to get JWT token:
- Scroll to
/api/auth/loginendpoint - Click "Try it out"
- Enter credentials in request body:
{ "email": "admin@example.com", "password": "<check ADMIN_PASSWORD in .env file>" } - Click "Execute"
-
Copy JWT token from response body (the long string after
"token":)
- Scroll to
-
Authorize with token:
- Click "Authorize" button (π icon at top right)
- Enter:
Bearer <your-token>(include "Bearer " prefix) - Click "Authorize"
- Click "Close"
-
Now you can test any authenticated endpoint (marked with π lock icon)
Flow:
1. User logs in
β
2. POST /api/auth/login (email + password)
β
3. Backend validates credentials (BCrypt)
β
4. Backend generates JWT token (signed with JWT_SECRET)
β
5. Frontend stores token in localStorage
β
6. Frontend includes token in all requests:
Authorization: Bearer <token>
β
7. Backend validates token on each request
β
8. Request proceeds if valid
Token Structure:
{
"sub": "user@example.com",
"roles": ["USER", "ADMIN"],
"permissions": ["VIEW_PHOTOS", "RATE_PHOTOS"],
"iat": 1234567890,
"exp": 1234571490
}Token Expiration:
- Tokens expire after configurable period (default: 24 hours)
- User must log in again after expiration
- No refresh token in MVP (planned for post-MVP)
Description: Login with email and password, receive JWT token.
Request:
POST /api/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123"
}Response (Success - 200 OK):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"email": "user@example.com",
"role": "USER",
"permissions": ["VIEW_PHOTOS", "RATE_PHOTOS"]
}Response (Error - 401 Unauthorized):
{
"timestamp": "2025-11-10T12:34:56.789Z",
"status": 401,
"error": "Unauthorized",
"message": "Invalid credentials"
}Validation:
-
email- Required, valid email format -
password- Required, min 6 characters
Description: Register new user account (requires manual activation by admin).
Request:
POST /api/auth/register
Content-Type: application/json
{
"email": "newuser@example.com",
"password": "password123",
"confirmPassword": "password123",
"name": "John Doe"
}Response (Success - 201 Created):
{
"message": "Registration successful! You can now log in. Contact the administrator to request permissions.",
"email": "newuser@example.com",
"isActive": true
}Response (Error - 400 Bad Request):
{
"timestamp": "2025-11-10T12:34:56.789Z",
"status": 400,
"error": "Bad Request",
"message": "Email already exists"
}Validation:
-
email- Required, valid email format, unique -
password- Required, min 6 characters -
confirmPassword- Required, must match password -
name- Optional, max 100 characters
Description: List all photos (with optional filters).
Authentication: Required (JWT token)
Query Parameters:
-
startDate(optional) - Filter by start date (ISO 8601:2025-01-01) -
endDate(optional) - Filter by end date (ISO 8601:2025-12-31) -
minRating(optional) - Minimum rating (1-5) -
hasGps(optional) - Filter by GPS data presence (trueorfalse) -
page(optional) - Page number (default: 0) -
size(optional) - Page size (default: 20)
Request:
GET /api/photos?startDate=2025-01-01&minRating=4&hasGps=true
Authorization: Bearer <token>
Response (Success - 200 OK):
{
"content": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"filename": "photo1.jpg",
"latitude": 52.2297,
"longitude": 21.0122,
"takenAt": "2025-01-15T10:30:00Z",
"uploadedAt": "2025-01-20T14:00:00Z",
"mediumPath": "/uploads/medium/photo1.jpg",
"overallRating": 4.5,
"myRating": 5,
"ratingCount": 10
}
],
"page": 0,
"size": 20,
"totalElements": 1,
"totalPages": 1
}Permissions Required: VIEW_PHOTOS
Description: Get photo by ID.
Authentication: Required (JWT token)
Request:
GET /api/photos/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer <token>
Response (Success - 200 OK):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"filename": "photo1.jpg",
"latitude": 52.2297,
"longitude": 21.0122,
"takenAt": "2025-01-15T10:30:00Z",
"uploadedAt": "2025-01-20T14:00:00Z",
"originalPath": "/uploads/original/photo1.jpg",
"mediumPath": "/uploads/medium/photo1.jpg",
"uploader": {
"id": "user-uuid",
"email": "user@example.com",
"name": "John Doe"
},
"overallRating": 4.5,
"myRating": 5,
"ratingCount": 10
}Response (Error - 404 Not Found):
{
"timestamp": "2025-11-10T12:34:56.789Z",
"status": 404,
"error": "Not Found",
"message": "Photo not found"
}Permissions Required: VIEW_PHOTOS
Description: Upload one or more photos.
Authentication: Required (JWT token)
Request:
POST /api/photos/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data
files: [photo1.jpg, photo2.jpg]
Response (Success - 200 OK):
{
"uploaded": 2,
"failed": 0,
"photos": [
{
"id": "photo1-uuid",
"filename": "photo1.jpg",
"status": "success"
},
{
"id": "photo2-uuid",
"filename": "photo2.jpg",
"status": "success"
}
]
}Response (Partial Success - 207 Multi-Status):
{
"uploaded": 1,
"failed": 1,
"photos": [
{
"id": "photo1-uuid",
"filename": "photo1.jpg",
"status": "success"
},
{
"filename": "photo2.jpg",
"status": "failed",
"error": "Invalid file format"
}
]
}Validation:
-
files- Required, multipart/form-data - File size limit: 10MB (default)
- Supported formats: JPEG, PNG
Note: Upload available to all logged-in users in MVP
Description: Rate a photo (1-5 stars).
Authentication: Required (JWT token)
Request:
POST /api/photos/550e8400-e29b-41d4-a716-446655440000/rate
Authorization: Bearer <token>
Content-Type: application/json
{
"rating": 5
}Response (Success - 200 OK):
{
"photoId": "550e8400-e29b-41d4-a716-446655440000",
"myRating": 5,
"overallRating": 4.5,
"ratingCount": 11
}Validation:
-
rating- Required, integer 1-5 - One rating per user per photo (update if exists)
Permissions Required: RATE_PHOTOS
Description: Get all ratings for a photo.
Authentication: Required (JWT token)
Request:
GET /api/photos/550e8400-e29b-41d4-a716-446655440000/ratings
Authorization: Bearer <token>
Response (Success - 200 OK):
{
"photoId": "550e8400-e29b-41d4-a716-446655440000",
"overallRating": 4.5,
"ratingCount": 10,
"ratings": [
{
"userId": "user1-uuid",
"userName": "John Doe",
"rating": 5,
"createdAt": "2025-01-20T15:00:00Z"
},
{
"userId": "user2-uuid",
"userName": "Jane Smith",
"rating": 4,
"createdAt": "2025-01-21T10:00:00Z"
}
]
}Permissions Required: VIEW_PHOTOS
Description: List all users.
Authentication: Required (JWT token with ADMIN role)
Request:
GET /api/admin/users
Authorization: Bearer <token>
Response (Success - 200 OK):
[
{
"id": "user1-uuid",
"email": "admin@example.com",
"name": "Admin User",
"role": "ADMIN",
"isActive": true,
"permissions": ["VIEW_PHOTOS", "RATE_PHOTOS"],
"createdAt": "2025-01-01T00:00:00Z"
},
{
"id": "user2-uuid",
"email": "user@example.com",
"name": "John Doe",
"role": "USER",
"isActive": true,
"permissions": [],
"createdAt": "2025-01-20T12:00:00Z"
}
]Role Required: ADMIN
Description: Update user permissions.
Authentication: Required (JWT token with ADMIN role)
Request:
PUT /api/admin/users/user2-uuid/permissions
Authorization: Bearer <token>
Content-Type: application/json
{
"permissions": ["VIEW_PHOTOS", "RATE_PHOTOS"]
}Response (Success - 200 OK):
{
"id": "user2-uuid",
"email": "user@example.com",
"permissions": ["VIEW_PHOTOS", "RATE_PHOTOS"],
"message": "Permissions updated successfully"
}Available Permissions:
-
VIEW_PHOTOS- View photos in Gallery and Map -
RATE_PHOTOS- Rate photos (1-5 stars)
Role Required: ADMIN
LoginRequest:
{
"email": "user@example.com", // @Email, @NotBlank
"password": "password123" // @NotBlank, @Size(min=6)
}RegisterRequest:
{
"email": "user@example.com", // @Email, @NotBlank
"password": "password123", // @NotBlank, @Size(min=6)
"confirmPassword": "password123", // Must match password
"name": "John Doe" // @Size(max=100)
}RatingRequest:
{
"rating": 5 // @Min(1), @Max(5)
}AuthResponse:
{
"token": "jwt-token",
"email": "user@example.com",
"role": "USER",
"permissions": ["VIEW_PHOTOS"]
}PhotoResponse:
{
"id": "uuid",
"filename": "photo.jpg",
"latitude": 52.2297,
"longitude": 21.0122,
"takenAt": "2025-01-15T10:30:00Z",
"uploadedAt": "2025-01-20T14:00:00Z",
"mediumPath": "/uploads/medium/photo.jpg",
"overallRating": 4.5,
"myRating": 5,
"ratingCount": 10
}ErrorResponse:
{
"timestamp": "2025-11-10T12:34:56.789Z",
"status": 400,
"error": "Bad Request",
"message": "Validation failed",
"details": [
"email: must be a valid email address",
"password: must be at least 6 characters"
]
}| Status | Description |
|---|---|
| 200 OK | Request successful |
| 201 Created | Resource created successfully |
| 400 Bad Request | Validation error or invalid input |
| 401 Unauthorized | Missing or invalid JWT token |
| 403 Forbidden | Insufficient permissions |
| 404 Not Found | Resource not found |
| 500 Internal Server Error | Server error |
{
"timestamp": "2025-11-10T12:34:56.789Z",
"status": 400,
"error": "Bad Request",
"message": "Validation failed",
"path": "/api/auth/login",
"details": [
"email: must be a valid email address"
]
}401 Unauthorized - Missing Token:
{
"status": 401,
"error": "Unauthorized",
"message": "JWT token is missing"
}401 Unauthorized - Invalid Credentials:
{
"status": 401,
"error": "Unauthorized",
"message": "Invalid credentials"
}403 Forbidden - Insufficient Permissions:
{
"status": 403,
"error": "Forbidden",
"message": "You do not have permission to upload photos"
}404 Not Found:
{
"status": 404,
"error": "Not Found",
"message": "Photo not found"
}Login:
# Read admin password from .env
ADMIN_PWD=$(grep ADMIN_PASSWORD .env | cut -d'=' -f2)
# Login
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d "{\"email\":\"admin@example.com\",\"password\":\"$ADMIN_PWD\"}"List Photos (with token):
# Save token from login response
TOKEN="your-jwt-token"
# List photos
curl -X GET http://localhost:8080/api/photos \
-H "Authorization: Bearer $TOKEN"Upload Photo:
curl -X POST http://localhost:8080/api/photos/upload \
-H "Authorization: Bearer $TOKEN" \
-F "files=@/path/to/photo.jpg"Rate Photo:
PHOTO_ID="550e8400-e29b-41d4-a716-446655440000"
curl -X POST "http://localhost:8080/api/photos/$PHOTO_ID/rate" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"rating": 5}'- Open http://localhost:8080/swagger-ui/index.html
- Click "Authorize" button
- Login via
/api/auth/loginto get token - Enter
Bearer <token>in authorization dialog - Click "Authorize"
- Test any endpoint using "Try it out" button
Related Pages:
- Architecture - REST API design, JWT authentication
- Development Setup - Environment configuration
- Quick Start - First login and verification
External Documentation:
Last Updated: 2025-11-10
Sources:
-
README.md(API Documentation section) -
05-Architecture.md(REST API Design, JWT Authentication) - Swagger UI (http://localhost:8080/swagger-ui/index.html)