A comprehensive RESTful API for a Missing Pets application built with Node.js, Express.js, MongoDB, and Socket.io. This backend enables users to register, manage pets, and report missing or found pets with real-time updates and geospatial search capabilities.
- User Management: Registration, authentication (JWT), profile management (including admin routes).
- Pet CRUD: Create, read, update, delete pet records with detailed characteristics.
- Report System: Lost, found, and reunited pet reports with geospatial location.
- Real-time Updates: Socket.io integration for live notifications on report creation and updates within subscribed regions.
- File Uploads: Photo upload support for pets and reports, served via a CDN-like path.
- Geospatial Search: Radius-based search for nearby reports.
- Security: JWT authentication, password hashing (bcryptjs), rate limiting, input validation, CORS.
- Logging: Comprehensive logging with Winston.
- Health Check: Endpoint to monitor application status.
- Runtime: Node.js (as specified in
package.json) - Framework: Express.js
- Database: MongoDB Atlas via Mongoose
- Real-Time: Socket.io
- Authentication: JSON Web Tokens (jsonwebtoken)
- Password Hashing: bcryptjs
- File Uploads: Multer
- Validation: express-validator
- Logging: Winston
- Environment Management: dotenv
- CORS: cors package
- HTTP Server: Node.js
httpmodule
- Node.js (version as per
package.jsonor higher) - MongoDB Atlas account (or local MongoDB instance)
- npm or yarn package manager
-
Clone the repository
git clone <repository-url> cd missing_pets
-
Install dependencies
npm install
-
Set up environment variables Create a
.envfile in the root directory by copying.env.example(if available) or by creating a new one.# Database Configuration MONGO_USER=your-mongo-username MONGO_PASSWORD=your-mongo-password DEFAULT_DATABASE=MissingPets # Or your preferred database name # Server Configuration PORT=3000 HOST=0.0.0.0 # Binds to all available network interfaces NODE_ENV=development # or production # Authentication JWT_SECRET=your-super-secret-jwt-key-change-this-in-production # CORS Configuration CLIENT_URL=http://localhost:3001 # Frontend URL, or "*" for all # CDN Configuration (Base URL for served attachments) CDN_BASE_URL=http://localhost:3000 # Should match your server's public URL # Logging LOG_LEVEL=info # e.g., error, warn, info, http, verbose, debug, silly
-
Start the development server
npm start
The server will typically start on
http://localhost:3000(or your configuredPORTandHOST).
All API endpoints requiring authentication must include an Authorization header with a Bearer token: Authorization: Bearer <your-jwt-token>.
Register a new user account. Request Body:
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123",
"phone": "+1234567890"
}Response (Success 201):
{
"message": "User created successfully",
"token": "jwt-token-here",
"user": {
"_id": "user-id",
"name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890"
}
}Authenticate user and get an access token. Request Body:
{
"email": "john@example.com",
"password": "password123"
}Response (Success 200):
{
"message": "Logged in successfully",
"token": "jwt-token-here",
"user": {
"_id": "user-id",
"name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890"
}
}Get the profile of the currently authenticated user. Response (Success 200): User object.
Update the profile of the currently authenticated user. Request Body: Fields to update (e.g., name, phone, password). Response (Success 200): Updated user object.
Delete the account of the currently authenticated user. Response (Success 200): Confirmation message.
List all users (pagination available). Query Parameters:
page(number, optional): Page number for pagination.limit(number, optional): Number of items per page. Response (Success 200): Array of user objects.
Get a specific user by ID. Response (Success 200): User object.
Update a specific user by ID. Request Body: Fields to update. Response (Success 200): Updated user object.
Delete a specific user by ID. Response (Success 200): Confirmation message.
Create a new pet record.
Request Body (multipart/form-data):
name(String)breed(String, optional)height(Number, optional)weight(Number, optional)color(String, optional)attachments(File, optional): Pet photo(s). Response (Success 201): Created pet object.
List pets (pagination and filters available). Query Parameters:
page(number, optional)limit(number, optional)name(String, optional): Filter by pet name.breed(String, optional): Filter by pet breed.color(String, optional): Filter by pet color.hasOwner(Boolean, optional): Filter pets that have an owner. Response (Success 200): Array of pet objects.
Get a specific pet by ID. Response (Success 200): Pet object.
Update a specific pet by ID.
Request Body (multipart/form-data): Fields to update (same as POST).
Response (Success 200): Updated pet object.
Delete a specific pet by ID. Response (Success 200): Confirmation message.
Create a new missing/found pet report.
Request Body (multipart/form-data):
pet(String, Pet ID)status(String, enum:lost,found,reunited)description(String, optional)location(Object): GeoJSON Point (e.g.,{ "type": "Point", "coordinates": [longitude, latitude] })attachments(File, optional): Report photo(s). Response (Success 201): Created report object.
List reports (pagination, filters, geospatial search available). Query Parameters:
page(number, optional)limit(number, optional)status(String, optional, enum:lost,found,reunited): Filter by report status.petId(String, optional): Filter by Pet ID.reporterId(String, optional): Filter by User ID of the reporter.dateFrom(String, optional, ISO Date): Filter reports from this date.dateTo(String, optional, ISO Date): Filter reports up to this date.lat(Number, optional): Latitude for geospatial search.lng(Number, optional): Longitude for geospatial search.radius(Number, optional): Search radius in meters (used withlatandlng). Response (Success 200): Array of report objects.
Get a specific report by ID. Response (Success 200): Report object.
Update a specific report by ID.
Request Body (multipart/form-data): Fields to update (same as POST).
Response (Success 200): Updated report object.
Mark a specific report's pet as found (sets status to reunited or similar).
Response (Success 200): Updated report object.
Delete a specific report by ID. Response (Success 200): Confirmation message.
- Files are uploaded via
multipart/form-data. - The field name for file(s) should be
attachments. - Uploaded files are stored in the
/attachmentsdirectory on the server and accessible via/attachments/:filename(e.g.,http://localhost:3000/attachments/yourfile.jpg). TheCDN_BASE_URLis used to construct the full URL in API responses.
Provides the health status of the server. Response (Success 200):
{
"status": "OK",
"timestamp": "YYYY-MM-DDTHH:mm:ss.sssZ",
"uptime": 1234.56 // seconds
}The API uses Socket.io for real-time communication, primarily for report updates.
- Namespace:
/reports - Authentication: Connect to the namespace with a JWT token in the
authobject:const socket = io('http://your-server-url/reports', { auth: { token: 'your-jwt-token' } });
newReport- Payload: The newly created report object.
- Description: Emitted when a new report is successfully created and matches a client's subscribed region.
updateReport- Payload: The updated report object.
- Description: Emitted when an existing report is updated and matches a client's subscribed region.
subscribeRegion- Payload:
{ "lat": 40.7128, // Latitude of the center of the region "lng": -74.0060, // Longitude of the center of the region "radius": 5000 // Radius in meters } - Description: Allows a client to subscribe to real-time updates for reports within a specific geographical area. The server will then only send
newReportandupdateReportevents relevant to this region.
- Payload:
All models include createdAt and updatedAt timestamps by default.
name(String, required)email(String, required, unique, lowercase, trim)password(String, required, minlength: 6) - Stored hashed.phone(String, optional, trim)isAdmin(Boolean, default: false)
owner(ObjectId, ref: 'User', optional, index: true) - The user who owns the pet.createdBy(ObjectId, ref: 'User', required, index: true) - The user who created the pet record.name(String, required, trim)breed(String, optional, trim)height(Number, optional, min: 0) - In cm.weight(Number, optional, min: 0) - In kg.color(String, optional, trim)photos(Array of String URLs, default: []) - URLs of pet photos.isOwnedByCreator(Boolean, default: true) - Indicates if the creator is the current owner.
pet(ObjectId, ref: 'Pet', required, index: true) - The pet this report is about.reporter(ObjectId, ref: 'User', required, index: true) - The user who filed the report.status(String, required, enum: ['lost', 'found', 'reunited'], default: 'lost', index: true)description(String, optional, trim)photos(Array of String URLs, default: []) - URLs of report-specific photos.location(Object, required) - GeoJSON Point for the report's location.type(String, enum: ['Point'], required)coordinates(Array of Number, required, index: '2dsphere') - [longitude, latitude]
resolvedAt(Date, optional) - When the report was marked as 'reunited'.
To run tests (if test scripts are configured in package.json, e.g., npm test):
npm test
# or specific test files if using a test runner like Jest or MochaThe provided test-api.js seems to be a custom script. You can run it using:
node test-api.jsEnsure the server is running and configured correctly before executing test-api.js.
- JWT Authentication: Stateless authentication using JSON Web Tokens.
- Password Hashing:
bcryptjsis used to hash passwords before storing. - Rate Limiting:
express-rate-limitis implemented to protect against brute-force attacks on various routes (general, authentication, uploads). - Input Validation:
express-validatoris used to validate and sanitize request data. - CORS: Configured using the
corspackage to control cross-origin requests. - Error Handling: Centralized error handling middleware provides consistent error responses.
- HTTPS: Recommended for production (typically handled by a reverse proxy like Nginx).
missing_pets/
βββ app.js # Main application file, sets up Express, DB, Socket.io
βββ package.json # Project dependencies and scripts
βββ nodemon.json # Configuration for nodemon (if used)
βββ .env # Environment variables (ignored by Git)
βββ .env.example # Template for environment variables
βββ README.md # This file
βββ test-api.js # Example API test script
βββ attachments/ # Directory for uploaded files (ensure it's writable)
βββ config/
β βββ socket.js # Socket.io configuration
βββ controllers/ # Route handlers (business logic)
β βββ authController.js
β βββ petController.js
β βββ reportController.js
β βββ userController.js
βββ docs/ # API documentation files
β βββ attachment-upload-documentation.html
β βββ complete-api-documentation.html
β βββ index.html
βββ logs/ # Log files (ensure it's writable)
β βββ combined.log
β βββ error.log
βββ middleware/ # Custom Express middleware
β βββ attachment-upload.js # Handles file uploads with Multer
β βββ is-auth.js # JWT authentication verification
β βββ rate-limiter.js # Request rate limiting
βββ models/ # Mongoose data models (schemas)
β βββ Pet.js
β βββ Report.js
β βββ User.js
βββ routes/ # Express route definitions
β βββ auth.js
β βββ pets.js
β βββ reports.js
β βββ users.js
βββ utils/ # Utility functions and helpers
βββ helpers.js
βββ logger.js # Winston logger configuration
βββ validation.js # Reusable validation schemas/rules
The API returns structured JSON error responses: Example (Validation Error):
{
"status": 422, // Or other appropriate HTTP status code
"message": "Validation failed.",
"data": [ // Array of validation errors from express-validator
{
"type": "field",
"value": "invalid_email",
"msg": "Please enter a valid email.",
"path": "email",
"location": "body"
}
]
}Example (General Error):
{
"status": 500,
"message": "Internal server error",
// stack trace included in development mode
"stack": "Error: ... at ..."
}- Logs are managed by Winston.
- Configuration is in
utils/logger.js. - Default log files (in the
logs/directory):combined.log: All logs (based onLOG_LEVEL).error.log: Only error logs.
- Console output is also active, especially in development.
- Fork the repository.
- Create a new branch (
git checkout -b feature/your-feature-name). - Make your changes.
- Commit your changes (
git commit -m 'Add some feature'). - Push to the branch (
git push origin feature/your-feature-name). - Open a Pull Request.
This project is likely under a common open-source license (e.g., MIT, ISC). Check package.json or for a LICENSE file if one exists. (Assuming ISC if not specified, common for Node.js projects).
- MongoDB Connection Issues:
- Verify
MONGO_USER,MONGO_PASSWORD, andDEFAULT_DATABASEin.env. - Ensure your IP address is whitelisted in MongoDB Atlas if applicable.
- Check MongoDB server status.
- Verify
- JWT Errors:
- Ensure
JWT_SECRETis correctly set in.envand is a strong, unique key. - Verify the token is not expired and is being sent correctly in the
Authorizationheader.
- Ensure
- File Uploads:
- Ensure the
attachments/directory exists at the root of the project and is writable by the Node.js process. - Check
CDN_BASE_URLin.envto ensure generated file URLs are correct. - Verify the client is sending
multipart/form-datawith the correct field name (attachments).
- Ensure the
- CORS Errors:
- Check
CLIENT_URLin.env. For multiple origins or more complex setups, you might need to adjust thecorsmiddleware options inapp.js.
- Check
- Rate Limiting: If you're getting blocked, you might be hitting rate limits. This is expected behavior to prevent abuse.
- Set
NODE_ENV=productionin your environment variables. - Use a strong, unique
JWT_SECRET. - Configure
CLIENT_URLspecifically for your production frontend. - Use a process manager like PM2 or Supervisor to keep the application running.
- Set up a reverse proxy (e.g., Nginx, Apache) to handle incoming traffic, SSL termination (HTTPS), and potentially serve static files or load balance.
- Implement robust monitoring and alerting.
- Ensure database backups are regularly performed.
- Consider log rotation and management for production environments.