Files
looking-monorepo/backend/API.md
2025-12-28 13:52:25 -03:00

1030 lines
17 KiB
Markdown

# Looking API Reference
> **Complete REST API documentation for the Looking backend**
This document provides detailed information about all API endpoints, including request/response formats, authentication requirements, and error codes.
---
## 📋 Table of Contents
- [Base URL](#base-url)
- [Authentication](#authentication)
- [Common Response Codes](#common-response-codes)
- [Authentication Endpoints](#authentication-endpoints)
- [Profile Endpoints](#profile-endpoints)
- [User Endpoints](#user-endpoints)
- [Geocache Endpoints](#geocache-endpoints)
- [Error Handling](#error-handling)
---
## 🌐 Base URL
**Development**: `http://localhost:3069`
**Production**: `https://api.pfosi.mifi.dev`
All endpoints are prefixed with the base URL.
---
## 🔐 Authentication
Most endpoints require JWT authentication via the `Authorization` header.
### Header Format
```
Authorization: Bearer <jwt_token>
```
### Permission Levels
| Permission | Description |
| ---------- | ----------------------------------- |
| **view** | Read-only access to profiles |
| **add** | Create new profiles |
| **edit** | Modify existing profiles |
| **update** | Update profile details |
| **delete** | Remove profiles |
| **manage** | Approve submissions, manage content |
| **super** | Full admin access, user management |
### Obtaining a Token
Use the `/auth/login` endpoint (see [Authentication Endpoints](#authentication-endpoints)).
---
## 📊 Common Response Codes
| Code | Status | Description |
| ------- | --------------------- | ----------------------------- |
| **200** | OK | Request successful |
| **201** | Created | Resource created successfully |
| **400** | Bad Request | Invalid request data |
| **401** | Unauthorized | Missing or invalid token |
| **403** | Forbidden | Insufficient permissions |
| **404** | Not Found | Resource not found |
| **500** | Internal Server Error | Server error |
---
## 🔑 Authentication Endpoints
### POST `/auth/login`
Authenticate user and receive JWT token.
**Request:**
```json
POST /auth/login
Content-Type: application/json
{
"username": "admin",
"password": "password123"
}
```
**Success Response (200):**
```json
{
"status": 200,
"authorized": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "507f1f77bcf86cd799439011",
"username": "admin",
"name": {
"first": "John",
"last": "Doe"
},
"email": "admin@example.com",
"can": ["add", "edit", "delete", "manage", "super", "update", "view"]
}
}
```
**Failure Response (401):**
```json
{
"status": 401,
"authorized": false,
"message": "Invalid username or password"
}
```
---
### POST `/auth/logout`
Logout user (client-side token removal, no server-side action needed).
**Request:**
```json
POST /auth/logout
Authorization: Bearer <token>
```
**Response (200):**
```json
{
"message": "Logged out successfully"
}
```
---
### GET `/auth/session`
Validate existing JWT token and get user info.
**Request:**
```
GET /auth/session
Authorization: Bearer <token>
```
**Success Response (200):**
```json
{
"valid": true,
"decoded": {
"uid": "507f1f77bcf86cd799439011",
"username": "admin",
"can": ["add", "edit", "delete", "manage", "super", "update", "view"],
"iat": 1640000000,
"exp": 1640003600
}
}
```
**Failure Response (401):**
```json
{
"valid": false,
"message": "Token expired or invalid"
}
```
---
### POST `/auth/session`
Create anonymous session token (limited permissions).
**Request:**
```json
POST /auth/session
```
**Response (200):**
```json
{
"status": 200,
"authorized": false,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
---
### PUT `/auth/session`
Refresh existing JWT token (extend expiration).
**Request:**
```
PUT /auth/session
Authorization: Bearer <token>
```
**Response (200):**
```json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": "15m"
}
```
---
### POST `/auth/reset`
Request password reset email.
**Request:**
```json
POST /auth/reset
Content-Type: application/json
{
"username": "admin"
}
```
**Response (200):**
```json
{
"message": "Password reset email sent",
"email": "ad***@example.com"
}
```
---
### GET `/auth/reset/:id/:token`
Verify password reset token validity.
**Request:**
```
GET /auth/reset/507f1f77bcf86cd799439011/abc123def456
```
**Response (200):**
```json
{
"valid": true,
"userId": "507f1f77bcf86cd799439011",
"expires": "2024-01-15T12:00:00Z"
}
```
---
### PUT `/auth/reset/:id/:token`
Reset password with valid token.
**Request:**
```json
PUT /auth/reset/507f1f77bcf86cd799439011/abc123def456
Content-Type: application/json
{
"password": "newPassword123",
"confirmPassword": "newPassword123"
}
```
**Response (200):**
```json
{
"message": "Password updated successfully",
"success": true
}
```
---
## 👤 Profile Endpoints
### GET `/profiles`
Get all approved profiles.
**Request:**
```
GET /profiles
```
**Response (200):**
```json
[
{
"_id": "507f1f77bcf86cd799439011",
"order": 1,
"details": {
"name": "John",
"age": 28,
"location": "San Francisco, CA",
"about": "User's story about dating...",
"pic": {
"thumb": "profile/john_thumbnail.png",
"detail": "profile/john_detail.png"
},
"position": ["Top", "Versatile"],
"looking": ["Dates", "Friends"],
"tribes": ["Geek", "Jock"],
"ethnos": ["White", "Latino"]
},
"messages": [
{
"_id": "507f191e810c19729de860ea",
"text": "What brought you to dating apps?",
"isUser": false,
"timestamp": "2024-01-15T10:30:00Z"
},
{
"_id": "507f191e810c19729de860eb",
"text": "I moved to a new city...",
"isUser": true,
"timestamp": "2024-01-15T10:32:00Z"
}
],
"submitted": true,
"approved": true
}
]
```
---
### GET `/profiles/submitted`
Get all submitted (pending approval) profiles.
**Authentication**: Required (`view` permission)
**Request:**
```
GET /profiles/submitted
Authorization: Bearer <token>
```
**Response (200):**
```json
[
{
"_id": "507f1f77bcf86cd799439012",
"details": { ... },
"submitted": true,
"approved": false
}
]
```
---
### GET `/profiles/verified`
Alias for approved profiles.
**Request:**
```
GET /profiles/verified
```
**Response**: Same as `GET /profiles`
---
### GET `/profiles/:id`
Get single profile by ID.
**Request:**
```
GET /profiles/507f1f77bcf86cd799439011
```
**Response (200):**
```json
{
"_id": "507f1f77bcf86cd799439011",
"order": 1,
"details": { ... },
"messages": [ ... ],
"submitted": true,
"approved": true
}
```
**Error (404):**
```json
{
"message": "Profile not found"
}
```
---
### POST `/profiles`
Create new profile.
**Authentication**: Required (`add` permission)
**Request:**
```json
POST /profiles
Authorization: Bearer <token>
Content-Type: application/json
{
"order": 10,
"details": {
"name": "Alex",
"age": 25,
"location": "New York, NY",
"about": "My story...",
"pic": {
"thumb": "data:image/png;base64,iVBORw0KG...", // Base64 or path
"detail": "data:image/png;base64,iVBORw0KG..."
}
},
"messages": [
{
"text": "Question text",
"isUser": false
}
],
"submitted": true,
"approved": false
}
```
**Response (201):**
```json
{
"_id": "507f1f77bcf86cd799439013",
"message": "Profile created successfully",
"profile": { ... }
}
```
---
### PUT `/profiles/:id`
Update existing profile.
**Authentication**: Required (`update` permission)
**Request:**
```json
PUT /profiles/507f1f77bcf86cd799439011
Authorization: Bearer <token>
Content-Type: application/json
{
"details": {
"about": "Updated story..."
}
}
```
**Response (200):**
```json
{
"message": "Profile updated successfully",
"profile": { ... }
}
```
---
### DELETE `/profiles/:id`
Delete profile by ID.
**Authentication**: Required (`delete` permission)
**Request:**
```
DELETE /profiles/507f1f77bcf86cd799439011
Authorization: Bearer <token>
```
**Response (200):**
```json
{
"message": "Profile deleted successfully",
"id": "507f1f77bcf86cd799439011"
}
```
---
### GET `/profiles/approve/:id`
Approve submitted profile.
**Authentication**: Required (`manage` permission)
**Request:**
```
GET /profiles/approve/507f1f77bcf86cd799439012
Authorization: Bearer <token>
```
**Response (200):**
```json
{
"message": "Profile approved",
"profile": {
"_id": "507f1f77bcf86cd799439012",
"approved": true
}
}
```
---
### POST `/profiles/submission`
Submit new profile (public endpoint, no auth required).
**Request:**
```json
POST /profiles/submission
Content-Type: application/json
{
"details": {
"name": "Anonymous",
"age": 30,
"location": "Los Angeles, CA",
"about": "My dating story...",
"pic": {
"thumb": "data:image/png;base64,...",
"detail": "data:image/png;base64,..."
}
},
"messages": [
{
"text": "Tell us your story",
"isUser": false
},
{
"text": "I've been using apps for 3 years...",
"isUser": true
}
]
}
```
**Response (200):**
```json
{
"message": "Story submitted successfully. It will be reviewed before publishing.",
"profile": {
"_id": "507f1f77bcf86cd799439014",
"submitted": true,
"approved": false
}
}
```
---
### GET `/profiles/find/:limit?/:skip?/:min?/:max?/:pos?/:lkng?/:tribes?/:ethnos?`
Advanced profile search with filters.
**Authentication**: Required (`view` permission)
**Parameters:**
- `limit` - Number of results (default: all)
- `skip` - Number to skip for pagination
- `min` - Minimum age
- `max` - Maximum age
- `pos` - Position filter (pipe-separated: "Top|Bottom|Versatile")
- `lkng` - Looking for filter (pipe-separated: "Dates|Friends|Relationship")
- `tribes` - Tribes filter (pipe-separated: "Geek|Jock|Bear|Otter")
- `ethnos` - Ethnicity filter (pipe-separated: "White|Black|Latino|Asian")
**Request:**
```
GET /profiles/find/10/0/25/35/Top|Versatile/Dates|Friends/Geek/null
Authorization: Bearer <token>
```
**Response (200):**
```json
[
{
"_id": "507f1f77bcf86cd799439011",
"details": {
"age": 28,
"position": ["Top", "Versatile"],
"looking": ["Dates", "Friends"],
"tribes": ["Geek"]
}
}
]
```
---
### GET `/profiles/list/:limit?/:skip?/:min?/:max?/:pos?/:lkng?/:tribes?/:ethnos?`
List profiles with minimal data (name, thumbnail only).
**Authentication**: Required (`view` permission)
**Response (200):**
```json
[
{
"_id": "507f1f77bcf86cd799439011",
"order": 1,
"details": {
"name": "John",
"pic": {
"thumb": "profile/john_thumbnail.png"
}
}
}
]
```
---
### PUT `/profiles/:profileId/message/:messageId`
Update specific message in profile thread.
**Authentication**: Required (`update` permission)
**Request:**
```json
PUT /profiles/507f1f77bcf86cd799439011/message/507f191e810c19729de860ea
Authorization: Bearer <token>
Content-Type: application/json
{
"text": "Updated question text",
"image": "data:image/png;base64,..."
}
```
**Response (200):**
```json
{
"message": "Message updated successfully",
"profile": { ... }
}
```
---
## 👥 User Endpoints
### GET `/users`
Get all users.
**Authentication**: Required (`super` permission)
**Request:**
```
GET /users
Authorization: Bearer <token>
```
**Response (200):**
```json
[
{
"_id": "507f1f77bcf86cd799439011",
"username": "admin",
"name": {
"first": "John",
"last": "Doe"
},
"email": "admin@example.com",
"can": ["add", "edit", "delete", "manage", "super", "update", "view"],
"forceReset": false
}
]
```
---
### GET `/users/:id`
Get user by ID.
**Authentication**: Required (`super` permission)
**Response (200):**
```json
{
"_id": "507f1f77bcf86cd799439011",
"username": "admin",
"name": { "first": "John", "last": "Doe" },
"email": "admin@example.com",
"can": ["super"]
}
```
---
### POST `/users`
Create new user.
**Authentication**: Required (`super` permission)
**Request:**
```json
POST /users
Authorization: Bearer <token>
Content-Type: application/json
{
"username": "newuser",
"password": "password123",
"confirmPassword": "password123",
"name": {
"first": "Jane",
"last": "Smith"
},
"email": "jane@example.com",
"can": ["view", "add"]
}
```
**Response (201):**
```json
{
"message": "User created successfully",
"user": {
"_id": "507f1f77bcf86cd799439015",
"username": "newuser"
}
}
```
---
### PUT `/users/:id`
Update user information.
**Authentication**: Required (`super` permission or own user)
**Request:**
```json
PUT /users/507f1f77bcf86cd799439011
Authorization: Bearer <token>
Content-Type: application/json
{
"name": {
"first": "John",
"last": "Updated"
},
"email": "newemail@example.com",
"password": "newPassword123",
"confirmPassword": "newPassword123",
"currentPassword": "oldPassword123"
}
```
**Response (200):**
```json
{
"message": "User updated successfully",
"user": { ... }
}
```
---
### DELETE `/users/:id`
Delete user.
**Authentication**: Required (`super` permission)
**Request:**
```
DELETE /users/507f1f77bcf86cd799439011
Authorization: Bearer <token>
```
**Response (200):**
```json
{
"message": "User deleted successfully"
}
```
---
## 🗺️ Geocache Endpoints
### GET `/geocache/populate/:field`
Populate geocache for a specific field (e.g., location).
**Authentication**: Required (`manageAppPreferences` permission)
**Request:**
```
GET /geocache/populate/location
Authorization: Bearer <token>
```
**Response (200):**
```json
{
"message": "Geocache populated",
"count": 42,
"results": [
{
"key": "San Francisco, CA",
"formatted": "San Francisco, California, USA",
"loc": {
"type": "Point",
"coordinates": [-122.4194, 37.7749]
}
}
]
}
```
---
### PUT `/geocache/:id`
Update geocache entry.
**Authentication**: Required (`manageAppPreferences` permission)
**Request:**
```json
PUT /geocache/507f1f77bcf86cd799439011
Authorization: Bearer <token>
Content-Type: application/json
{
"key": "New York, NY",
"formatted": "New York, New York, USA",
"loc": {
"type": "Point",
"coordinates": [-74.0060, 40.7128]
}
}
```
**Response (200):**
```json
{
"message": "Geocache updated",
"geocache": { ... }
}
```
---
## ⚠️ Error Handling
### Error Response Format
All errors follow this structure:
```json
{
"message": "Human-readable error message",
"err": {
"code": "ERROR_CODE",
"details": "Additional error information"
}
}
```
### Common Error Messages
| Error | Code | Cause |
| ---------------------------------------------- | ---- | ------------------------------ |
| **User not authorized to perform this action** | 403 | Missing required permission |
| **Token expired or invalid** | 401 | JWT validation failed |
| **Profile not found** | 404 | Invalid profile ID |
| **Invalid username or password** | 401 | Login failed |
| **Could not update profile** | 500 | Database error during update |
| **There was an error processing the image** | 500 | Image upload/processing failed |
| **No profile id or data specified** | 500 | Missing required request data |
### Authentication Errors
**Missing Token:**
```json
{
"message": "No authorization token provided",
"err": null
}
```
**Invalid Token:**
```json
{
"message": "User not authorized to perform this action",
"err": {
"name": "JsonWebTokenError",
"message": "invalid signature"
}
}
```
**Expired Token:**
```json
{
"message": "User not authorized to perform this action",
"err": {
"name": "TokenExpiredError",
"message": "jwt expired",
"expiredAt": "2024-01-15T12:00:00Z"
}
}
```
### Validation Errors
**Password Mismatch:**
```json
{
"success": false,
"message": "There was an error saving the updated password."
}
```
**Duplicate Username:**
```json
{
"message": "There was a duplicate key error",
"err": {
"code": 11000,
"keyPattern": { "username": 1 }
}
}
```
---
## 📚 Related Documentation
- **[Backend README](README.md)** - Server setup and development
- **[Database Schema](SCHEMA.md)** - MongoDB collection schemas
- **[Environment Variables](.env.example)** - Configuration
- **[Root README](../README.md)** - Project overview
- **[Deployment Guide](../DEPLOYMENT.md)** - Production deployment
---
**Need Help?** Check the backend [troubleshooting section](README.md#troubleshooting) for common API issues.