Rock-Spotter

Rock Spotter API Documentation

Complete API reference for the Rock Spotter platform.

Base URL

http://localhost:3000/api

For production, replace with your deployed API URL.

Authentication

Most endpoints require authentication using JWT tokens. Include the token in the Authorization header:

Authorization: Bearer <your-jwt-token>

Tokens are obtained through the login or register endpoints and expire after 7 days.

Status Codes

Endpoints

Users & Authentication

Register User

Create a new user account.

POST /api/users/register
Content-Type: application/json

{
  "username": "rockfan123",
  "email": "user@example.com",
  "password": "securepassword"
}

Response:

{
  "message": "User registered successfully",
  "user": {
    "_id": "user_id",
    "username": "rockfan123",
    "email": "user@example.com",
    "profilePicture": "",
    "bio": "",
    "rockCount": 0,
    "huntCount": 0,
    "achievements": []
  },
  "token": "jwt_token_here"
}

Login

Authenticate and receive a JWT token.

POST /api/users/login
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "securepassword"
}

Response:

{
  "message": "Login successful",
  "user": { /* user object */ },
  "token": "jwt_token_here"
}

Get My Profile

Get the authenticated user’s profile.

GET /api/users/profile/me
Authorization: Bearer <token>

Response:

{
  "user": {
    "_id": "user_id",
    "username": "rockfan123",
    "email": "user@example.com",
    "profilePicture": "https://example.com/avatar.jpg",
    "bio": "Rock enthusiast since 2025",
    "rockCount": 15,
    "huntCount": 3,
    "achievements": [/* achievement objects */]
  }
}

Update Profile

Update the authenticated user’s profile.

PUT /api/users/profile/me
Authorization: Bearer <token>
Content-Type: application/json

{
  "username": "newusername",
  "bio": "Updated bio",
  "profilePicture": "https://example.com/new-avatar.jpg"
}

Get User by ID

Get a specific user’s public profile.

GET /api/users/:id

Rocks

Get All Rocks

Retrieve a paginated list of rocks with optional filters.

GET /api/rocks?page=1&limit=20&rockType=igneous&userId=user_id

Query Parameters:

Response:

{
  "rocks": [
    {
      "_id": "rock_id",
      "title": "Beautiful Granite",
      "description": "Found this amazing specimen",
      "photo": "https://example.com/rock.jpg",
      "location": {
        "type": "Point",
        "coordinates": [-122.4194, 37.7749],
        "address": "San Francisco, CA"
      },
      "rockType": "igneous",
      "user": {
        "_id": "user_id",
        "username": "rockfan123",
        "profilePicture": "https://example.com/avatar.jpg"
      },
      "likes": ["user_id_1", "user_id_2"],
      "comments": [],
      "tags": ["granite", "pink"],
      "isPublic": true,
      "createdAt": "2025-10-16T12:00:00Z"
    }
  ],
  "totalPages": 5,
  "currentPage": 1
}

Get Nearby Rocks

Find rocks near a specific location.

GET /api/rocks/nearby?longitude=-122.4194&latitude=37.7749&maxDistance=5000

Query Parameters:

Get Rock by ID

Retrieve a specific rock with full details.

GET /api/rocks/:id

Response:

{
  "rock": {
    "_id": "rock_id",
    "title": "Beautiful Granite",
    "description": "Found this amazing specimen",
    "photo": "https://example.com/rock.jpg",
    "location": {
      "type": "Point",
      "coordinates": [-122.4194, 37.7749],
      "address": "San Francisco, CA"
    },
    "rockType": "igneous",
    "user": { /* user object */ },
    "likes": ["user_id_1"],
    "comments": [
      {
        "_id": "comment_id",
        "user": { /* user object */ },
        "text": "Amazing find!",
        "createdAt": "2025-10-16T12:30:00Z"
      }
    ],
    "tags": ["granite", "pink"],
    "isPublic": true,
    "createdAt": "2025-10-16T12:00:00Z"
  }
}

Create Rock

Share a new rock photo.

POST /api/rocks
Authorization: Bearer <token>
Content-Type: application/json

{
  "title": "Beautiful Granite",
  "description": "Found this amazing specimen near the river",
  "photo": "https://example.com/rock.jpg",
  "location": {
    "type": "Point",
    "coordinates": [-122.4194, 37.7749],
    "address": "San Francisco, CA"
  },
  "rockType": "igneous",
  "tags": ["granite", "pink", "sparkly"],
  "isPublic": true
}

Response:

{
  "message": "Rock posted successfully",
  "rock": { /* rock object */ }
}

Update Rock

Update a rock post (only by owner).

PUT /api/rocks/:id
Authorization: Bearer <token>
Content-Type: application/json

{
  "title": "Updated Title",
  "description": "Updated description",
  "rockType": "metamorphic",
  "tags": ["updated", "tags"],
  "isPublic": false
}

Delete Rock

Delete a rock post (only by owner).

DELETE /api/rocks/:id
Authorization: Bearer <token>

Like/Unlike Rock

Toggle like on a rock post.

POST /api/rocks/:id/like
Authorization: Bearer <token>

Response:

{
  "message": "Rock liked",
  "likes": 5
}

Add Comment

Add a comment to a rock post.

POST /api/rocks/:id/comment
Authorization: Bearer <token>
Content-Type: application/json

{
  "text": "Amazing find! Where exactly did you find this?"
}

Hunts

Get All Hunts

Retrieve a paginated list of hunts with optional filters.

GET /api/hunts?page=1&limit=20&isActive=true&difficulty=medium

Query Parameters:

Response:

{
  "hunts": [
    {
      "_id": "hunt_id",
      "title": "Downtown Rock Hunt",
      "description": "Find 5 hidden rocks in downtown!",
      "creator": { /* user object */ },
      "rocks": [
        {
          "rock": { /* rock object */ },
          "hint": "Look near the fountain",
          "order": 1
        }
      ],
      "difficulty": "medium",
      "participants": [],
      "startDate": "2025-10-20T00:00:00Z",
      "endDate": "2025-10-27T23:59:59Z",
      "isActive": true,
      "maxParticipants": 100
    }
  ],
  "totalPages": 3,
  "currentPage": 1
}

Get Hunt by ID

Retrieve a specific hunt with full details.

GET /api/hunts/:id

Create Hunt

Create a new rock hunt.

POST /api/hunts
Authorization: Bearer <token>
Content-Type: application/json

{
  "title": "Downtown Rock Hunt",
  "description": "Find 5 hidden rocks in downtown area!",
  "rocks": [
    {
      "rock": "rock_id_1",
      "hint": "Look near the fountain in the park",
      "order": 1
    },
    {
      "rock": "rock_id_2",
      "hint": "Hidden behind the library",
      "order": 2
    }
  ],
  "difficulty": "medium",
  "startDate": "2025-10-20T00:00:00.000Z",
  "endDate": "2025-10-27T23:59:59.999Z",
  "maxParticipants": 100
}

Update Hunt

Update a hunt (only by creator).

PUT /api/hunts/:id
Authorization: Bearer <token>
Content-Type: application/json

{
  "title": "Updated Title",
  "description": "Updated description",
  "difficulty": "hard",
  "isActive": false
}

Delete Hunt

Delete a hunt (only by creator).

DELETE /api/hunts/:id
Authorization: Bearer <token>

Join Hunt

Join an active hunt.

POST /api/hunts/:id/join
Authorization: Bearer <token>

Response:

{
  "message": "Joined hunt successfully",
  "hunt": { /* hunt object with your participation */ }
}

Mark Rock as Found

Mark a rock as found in a hunt you’re participating in.

POST /api/hunts/:huntId/rocks/:rockId/found
Authorization: Bearer <token>

Response:

{
  "message": "Rock marked as found",
  "completed": false,
  "progress": {
    "found": 3,
    "total": 5
  }
}

When all rocks are found:

{
  "message": "Rock marked as found",
  "completed": true,
  "progress": {
    "found": 5,
    "total": 5
  }
}

Get My Hunt Progress

Get your progress in all hunts you’re participating in.

GET /api/hunts/my/progress
Authorization: Bearer <token>

Response:

{
  "hunts": [
    {
      "hunt": {
        "_id": "hunt_id",
        "title": "Downtown Rock Hunt",
        "description": "Find 5 hidden rocks",
        "difficulty": "medium",
        "totalRocks": 5,
        "creator": { /* user object */ }
      },
      "progress": {
        "rocksFound": 3,
        "totalRocks": 5,
        "completed": false,
        "completedAt": null,
        "startedAt": "2025-10-20T10:00:00Z"
      }
    }
  ]
}

Achievements

Get All Achievements

Retrieve all available achievements with optional filters.

GET /api/achievements?type=rocks&rarity=rare

Query Parameters:

Response:

{
  "achievements": [
    {
      "_id": "achievement_id",
      "name": "First Rock",
      "description": "Share your first rock photo",
      "icon": "🪨",
      "type": "rocks",
      "criteria": {
        "type": "count",
        "target": 1
      },
      "rarity": "common"
    }
  ]
}

Get Achievement by ID

Retrieve a specific achievement.

GET /api/achievements/:id

Create Achievement

Create a new achievement.

POST /api/achievements
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Rock Collector",
  "description": "Share 10 rock photos",
  "icon": "📸",
  "type": "rocks",
  "criteria": {
    "type": "count",
    "target": 10
  },
  "rarity": "rare"
}

Award Achievement

Award an achievement to the authenticated user.

POST /api/achievements/award
Authorization: Bearer <token>
Content-Type: application/json

{
  "achievementId": "achievement_id"
}

Get User’s Achievements

Get achievements earned by a specific user.

GET /api/achievements/user/:userId

Get your own achievements:

GET /api/achievements/user/me/achievements
Authorization: Bearer <token>

Error Responses

All error responses follow this format:

{
  "error": "Error message describing what went wrong"
}

Common Errors

401 Unauthorized:

{
  "error": "Authentication required"
}

404 Not Found:

{
  "error": "Resource not found"
}

403 Forbidden:

{
  "error": "Not authorized"
}

400 Bad Request:

{
  "error": "Invalid request parameters"
}

Rate Limiting

Currently, there are no rate limits implemented. In production, rate limiting should be added to prevent abuse.

CORS

The API supports Cross-Origin Resource Sharing (CORS) for web clients.

Data Validation

All endpoints validate input data. Invalid data will return a 400 Bad Request with details about validation errors.


Examples

Complete Flow: Register, Create Rock, Join Hunt

  1. Register:
    curl -X POST http://localhost:3000/api/users/register \
      -H "Content-Type: application/json" \
      -d '{"username":"rockfan","email":"fan@rocks.com","password":"rocks123"}'
    
  2. Create a rock post:
    curl -X POST http://localhost:3000/api/rocks \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -d '{
     "title":"Granite Boulder",
     "description":"Huge granite boulder",
     "photo":"https://example.com/granite.jpg",
     "location":{"type":"Point","coordinates":[-122.4,37.7],"address":"SF"},
     "rockType":"igneous",
     "tags":["granite","big"],
     "isPublic":true
      }'
    
  3. Join a hunt:
    curl -X POST http://localhost:3000/api/hunts/HUNT_ID/join \
      -H "Authorization: Bearer YOUR_TOKEN"
    
  4. Mark rock as found:
    curl -X POST http://localhost:3000/api/hunts/HUNT_ID/rocks/ROCK_ID/found \
      -H "Authorization: Bearer YOUR_TOKEN"