Skip to content

Latest commit

 

History

History
536 lines (418 loc) · 9.18 KB

File metadata and controls

536 lines (418 loc) · 9.18 KB

API Documentation

Base URL: http://localhost:5000/api

Authentication

Most endpoints require authentication via Bearer token from Supabase Auth.

Include in request headers:

Authorization: Bearer <supabase_access_token>

Roadmaps API

GET /roadmaps

Get all roadmaps with optional filtering and sorting.

Query Parameters:

  • resourceType (optional): free, paid, or mixed
  • targetRole (optional): Filter by target role (e.g., "Frontend Developer")
  • sortBy (optional): trending (default) or newest

Response:

[
  {
    "id": "uuid",
    "title": "Frontend Developer Path 2025",
    "target_role": "Beginner",
    "creator_id": "uuid",
    "upvotes": 15,
    "downvotes": 2,
    "created_at": "2025-10-05T10:00:00Z",
    "updated_at": "2025-10-05T10:00:00Z",
    "learning_steps": [
      {
        "id": "uuid",
        "title": "Learn HTML & CSS",
        "description": "Master the basics",
        "order": 1,
        "resources": [
          {
            "id": "uuid",
            "title": "MDN Web Docs",
            "url": "https://developer.mozilla.org",
            "type": "article",
            "cost": "FREE",
            "description": "Complete guide"
          }
        ]
      }
    ]
  }
]

GET /roadmaps/:id

Get a single roadmap by ID.

Parameters:

  • id: Roadmap UUID

Response:

{
  "id": "uuid",
  "title": "Frontend Developer Path 2025",
  "target_role": "Beginner",
  "creator_id": "uuid",
  "upvotes": 15,
  "downvotes": 2,
  "created_at": "2025-10-05T10:00:00Z",
  "learning_steps": [...],
  "roadmap_tags": [
    {
      "tags": {
        "id": "uuid",
        "name": "React",
        "slug": "react"
      }
    }
  ],
  "user_profiles": {
    "full_name": "John Doe",
    "name": "John",
    "avatar_url": "https://...",
    "email": "user@example.com"
  }
}

Error Responses:

  • 404: Roadmap not found

POST /roadmaps

Create a new roadmap (authentication required).

Request Body:

{
  "title": "Frontend Developer Path 2025",
  "target_role": "Beginner",  // Optional, kept for backward compatibility
  "learning_steps": [
    {
      "title": "Learn HTML & CSS",
      "description": "Master the basics of web development",
      "resources": [
        {
          "title": "MDN Web Docs",
          "url": "https://developer.mozilla.org",
          "type": "article",
          "cost": "FREE",
          "description": "Comprehensive guide"
        }
      ]
    }
  ]
}

Note: After creating a roadmap, use the Tags API to add tags to it.

Response:

  • 201: Created roadmap object
  • 400: Missing required fields
  • 401: Not authenticated
  • 500: Server error

PUT /roadmaps/:id

Update a roadmap (creator only).

Parameters:

  • id: Roadmap UUID

Request Body:

{
  "title": "Updated Title",
  "target_role": "Updated Role"
}

Response:

  • 200: Updated roadmap object
  • 401: Not authenticated
  • 403: Not authorized (not creator)
  • 500: Server error

DELETE /roadmaps/:id

Delete a roadmap (creator only).

Parameters:

  • id: Roadmap UUID

Response:

  • 200: { "message": "Roadmap deleted successfully" }
  • 401: Not authenticated
  • 403: Not authorized (not creator)
  • 500: Server error

Votes API

GET /votes/roadmap/:roadmapId

Get the authenticated user's vote for a roadmap.

Parameters:

  • roadmapId: Roadmap UUID

Authentication: Required

Response:

{
  "id": "uuid",
  "roadmap_id": "uuid",
  "user_id": "uuid",
  "vote_type": "UPVOTE",
  "created_at": "2025-10-05T10:00:00Z"
}

Or null if user hasn't voted.


POST /votes

Cast or update a vote (authentication required).

Request Body:

{
  "roadmap_id": "uuid",
  "vote_type": "UPVOTE"  // or "DOWNVOTE"
}

Behavior:

  • If no vote exists: Creates new vote
  • If same vote type: Removes vote (toggle off)
  • If different vote type: Updates to new vote type

Response:

{
  "message": "Vote created",
  "vote": {
    "id": "uuid",
    "roadmap_id": "uuid",
    "user_id": "uuid",
    "vote_type": "UPVOTE",
    "created_at": "2025-10-05T10:00:00Z"
  },
  "roadmap_votes": {
    "upvotes": 16,
    "downvotes": 2
  }
}

Error Responses:

  • 400: Invalid vote data
  • 401: Not authenticated
  • 500: Server error

DELETE /votes/:roadmapId

Remove a vote (authentication required).

Parameters:

  • roadmapId: Roadmap UUID

Response:

{
  "message": "Vote removed",
  "roadmap_votes": {
    "upvotes": 15,
    "downvotes": 2
  }
}

Comments API

GET /comments/roadmap/:roadmapId

Get all comments for a roadmap.

Parameters:

  • roadmapId: Roadmap UUID

Response:

[
  {
    "id": "uuid",
    "roadmap_id": "uuid",
    "user_id": "uuid",
    "content": "Great roadmap! Very helpful.",
    "created_at": "2025-10-05T10:00:00Z",
    "updated_at": "2025-10-05T10:00:00Z",
    "user_profiles": {
      "full_name": "John Doe",
      "name": "John",
      "avatar_url": "https://...",
      "email": "user@example.com"
    }
  }
]

POST /comments

Create a comment (authentication required).

Request Body:

{
  "roadmap_id": "uuid",
  "content": "Great roadmap! Very helpful."
}

Response:

  • 201: Created comment object
  • 400: Comment content is required
  • 401: Not authenticated
  • 500: Server error

PUT /comments/:id

Update a comment (author only).

Parameters:

  • id: Comment UUID

Request Body:

{
  "content": "Updated comment text"
}

Response:

  • 200: Updated comment object
  • 400: Comment content is required
  • 401: Not authenticated
  • 403: Not authorized (not author)
  • 500: Server error

DELETE /comments/:id

Delete a comment (author only).

Parameters:

  • id: Comment UUID

Response:

  • 200: { "message": "Comment deleted successfully" }
  • 401: Not authenticated
  • 403: Not authorized (not author)
  • 500: Server error

Tags API

GET /tags

Get all tags with optional search.

Query Parameters:

  • limit (optional): Number of tags to return (default: 50)
  • search (optional): Search tags by name

Response:

[
  {
    "id": "uuid",
    "name": "React",
    "slug": "react",
    "usage_count": 25,
    "created_at": "2025-10-05T10:00:00Z"
  }
]

GET /tags/popular

Get popular tags (most used).

Query Parameters:

  • limit (optional): Number of tags to return (default: 20)

Response:

[
  {
    "id": "uuid",
    "name": "React",
    "slug": "react",
    "usage_count": 25,
    "created_at": "2025-10-05T10:00:00Z"
  }
]

POST /tags

Get or create a tag (authentication required).

Request Body:

{
  "name": "React"
}

Behavior:

  • If tag exists (by slug): Returns existing tag
  • If tag doesn't exist: Creates new tag with auto-generated slug
  • Handles race conditions gracefully

Response:

{
  "id": "uuid",
  "name": "React",
  "slug": "react",
  "usage_count": 0,
  "created_at": "2025-10-05T10:00:00Z"
}

Error Responses:

  • 400: Tag name is required
  • 401: Not authenticated
  • 500: Server error

POST /roadmaps/:id/tags

Add tags to a roadmap (roadmap creator only).

Parameters:

  • id: Roadmap UUID

Request Body:

{
  "tag_ids": ["uuid1", "uuid2", "uuid3"]
}

Response:

  • 200: { "message": "Tags added successfully" }
  • 400: tag_ids array is required
  • 401: Not authenticated
  • 403: Not authorized (not creator)
  • 500: Server error

DELETE /roadmaps/:id/tags/:tagId

Remove a tag from a roadmap (roadmap creator only).

Parameters:

  • id: Roadmap UUID
  • tagId: Tag UUID

Response:

  • 200: { "message": "Tag removed successfully" }
  • 401: Not authenticated
  • 403: Not authorized (not creator)
  • 500: Server error

Tag System Usage

Frontend Implementation

The TagInput component (frontend/src/components/TagInput.jsx) provides:

  • Free-form text input (Enter, comma, or space to add tags)
  • Popular tag suggestions
  • Duplicate prevention
  • Temporary tag objects with isNew: true flag

Creating Roadmap with Tags

Flow:

  1. User types tags in TagInput component
  2. Tags are stored locally with temporary IDs and isNew: true flag
  3. On form submission:
    • Create roadmap
    • For each tag with isNew: true, call POST /api/tags to get/create tag
    • Collect all tag IDs
    • Call POST /api/roadmaps/:id/tags to link tags

Example:

const handleSubmit = async (e) => {
  const roadmap = await roadmapsAPI.create(roadmapData);

  if (selectedTags.length > 0) {
    const tagIds = await Promise.all(
      selectedTags.map(async (tag) => {
        if (tag.isNew) {
          const createdTag = await tagsAPI.create(tag.name);
          return createdTag.id;
        }
        return tag.id;
      })
    );

    await tagsAPI.addToRoadmap(roadmap.id, tagIds);
  }
};

Error Response Format

All errors return JSON in this format:

{
  "error": "Error message description"
}

HTTP Status Codes

  • 200 - Success
  • 201 - Created
  • 400 - Bad Request (invalid data)
  • 401 - Unauthorized (not authenticated)
  • 403 - Forbidden (not authorized)
  • 404 - Not Found
  • 500 - Internal Server Error