Skip to content

Latest commit

 

History

History
1050 lines (861 loc) · 22.9 KB

File metadata and controls

1050 lines (861 loc) · 22.9 KB

StreamSource API Documentation

Base URL

http://localhost:3000/api/v1

Authentication

The API uses JWT (JSON Web Token) authentication. Include the token in the Authorization header:

Authorization: Bearer <your-jwt-token>

Tokens expire after 24 hours.

Rate Limiting

All endpoints are rate limited:

  • General: 100 requests per minute per IP
  • Login: 5 attempts per 20 minutes per IP/email
  • Signup: 3 attempts per hour per IP

Rate limit headers are included in responses:

  • X-RateLimit-Limit: Maximum requests allowed
  • X-RateLimit-Remaining: Requests remaining
  • X-RateLimit-Reset: Time when limit resets (Unix timestamp)

Common Response Codes

  • 200 OK: Success
  • 201 Created: Resource created successfully
  • 204 No Content: Success with no response body
  • 400 Bad Request: Invalid request parameters
  • 401 Unauthorized: Missing or invalid authentication
  • 403 Forbidden: Authenticated but not authorized
  • 404 Not Found: Resource not found
  • 422 Unprocessable Entity: Validation errors
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Server error

Endpoints

Authentication

Sign Up

Create a new user account.

Endpoint: POST /users/signup

Body:

{
  "email": "user@example.com",
  "password": "SecurePass123",
  "role": "default"
}

Parameters:

  • email (required): Valid email address
  • password (required): Minimum 8 characters, must include uppercase, lowercase, and number
  • role (optional): User role - default, editor, or admin (defaults to default)

Response:

{
  "user": {
    "id": 1,
    "email": "user@example.com",
    "role": "default",
    "created_at": "2024-01-01T12:00:00Z",
    "updated_at": "2024-01-01T12:00:00Z"
  },
  "token": "eyJhbGciOiJIUzI1NiJ9..."
}

Login

Authenticate and receive a JWT token.

Endpoint: POST /users/login

Body:

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

Response:

{
  "user": {
    "id": 1,
    "email": "user@example.com",
    "role": "editor",
    "created_at": "2024-01-01T12:00:00Z",
    "updated_at": "2024-01-01T12:00:00Z"
  },
  "token": "eyJhbGciOiJIUzI1NiJ9..."
}

Streams

List Streams

Get a paginated list of streams.

Endpoint: GET /streams

Headers:

  • Authorization: Bearer <token> (required)

Query Parameters:

  • page (optional): Page number (default: 1)
  • per_page (optional): Items per page (default: 25, max: 100)
  • status (optional): Filter by status (active, inactive, live, ended, etc.)
  • notStatus (optional): Exclude streams with this status
  • user_id (optional): Filter by user ID
  • streamer_id (optional): Filter by streamer ID
  • platform (optional): Filter by platform
  • is_pinned (optional): Filter by pin state (true or false)
  • is_archived (optional): Filter by archive state (true or false)

Response:

{
  "streams": [
    {
      "id": 1,
      "title": "Example Stream",
      "source": "YouTube Channel",
      "link": "https://example.com/stream1",
      "city": "New York",
      "state": "NY",
      "platform": "youtube",
      "status": "live",
      "orientation": "landscape",
      "kind": "livestream",
      "is_pinned": false,
      "is_archived": false,
      "started_at": "2024-01-01T11:00:00Z",
      "ended_at": null,
      "created_at": "2024-01-01T12:00:00Z",
      "updated_at": "2024-01-01T12:00:00Z",
      "user": {
        "id": 1,
        "email": "user@example.com",
        "role": "editor"
      },
      "streamer": {
        "id": 1,
        "name": "Example Streamer"
      }
    }
  ],
  "meta": {
    "current_page": 1,
    "total_pages": 5,
    "total_count": 123,
    "per_page": 25
  }
}

Get Stream

Get a specific stream by ID.

Endpoint: GET /streams/:id

Headers:

  • Authorization: Bearer <token> (required)

Response:

{
  "id": 1,
  "title": "Example Stream",
  "source": "YouTube Channel",
  "link": "https://example.com/stream1",
  "city": "New York",
  "state": "NY",
  "platform": "youtube",
  "status": "live",
  "orientation": "landscape",
  "kind": "livestream",
  "is_pinned": false,
  "is_archived": false,
  "started_at": "2024-01-01T11:00:00Z",
  "ended_at": null,
  "created_at": "2024-01-01T12:00:00Z",
  "updated_at": "2024-01-01T12:00:00Z",
  "user": {
    "id": 1,
    "email": "user@example.com",
    "role": "editor"
  },
  "streamer": {
    "id": 1,
    "name": "Example Streamer",
    "description": "A popular content creator"
  }
}

Create Stream

Create a new stream (requires editor or admin role).

Endpoint: POST /streams

Headers:

  • Authorization: Bearer <token> (required)
  • Content-Type: application/json

Body:

{
  "title": "My New Stream",
  "source": "Example Source",
  "link": "https://example.com/new-stream",
  "city": "New York",
  "state": "NY",
  "platform": "youtube",
  "status": "live",
  "orientation": "landscape",
  "kind": "livestream",
  "streamer_id": 1,
}

Parameters:

  • title (required): Stream title (1-255 characters)
  • source (required): Stream source
  • link (required): Valid HTTP or HTTPS URL
  • city (optional): City location
  • state (optional): State/region location
  • platform (optional): Streaming platform
  • status (optional): Stream status - active, inactive, live, ended, etc.
  • orientation (optional): Video orientation - landscape, portrait, square
  • kind (optional): Stream type
  • streamer_id (optional): Associated streamer ID

Response: Same as Get Stream response.


#### Update Stream
Update an existing stream (owner or `admin` only).

**Endpoint:** `PATCH /streams/:id`

**Headers:**
- `Authorization: Bearer <token>` (required)
- `Content-Type: application/json`

**Body:**
```json
{
  "title": "Updated Stream Title",
  "link": "https://example.com/updated-stream",
  "status": "ended",
  "ended_at": "2024-01-01T13:00:00Z"
}

Parameters:

  • title (optional): New stream title
  • source (optional): New stream source
  • link (optional): New stream URL
  • status (optional): New status
  • city (optional): New city
  • state (optional): New state
  • platform (optional): New platform
  • orientation (optional): New orientation
  • kind (optional): New stream type
  • started_at (optional): When stream started
  • ended_at (optional): When stream ended

Response: Same as Get Stream response with updated values.

Delete Stream

Delete a stream (owner or admin only).

Endpoint: DELETE /streams/:id

Headers:

  • Authorization: Bearer <token> (required)

Response: 204 No Content on success

Pin Stream

Pin a stream to highlight it (owner or admin only).

Endpoint: PUT /streams/:id/pin

Headers:

  • Authorization: Bearer <token> (required)

Response: Same as Get Stream response with is_pinned: true

Unpin Stream

Remove pin from a stream (owner or admin only).

Endpoint: DELETE /streams/:id/pin

Headers:

  • Authorization: Bearer <token> (required)

Response: Same as Get Stream response with is_pinned: false

Archive Stream

Archive a stream (owner or admin only).

Endpoint: POST /streams/:id/archive

Headers:

  • Authorization: Bearer <token> (required)

Response: Same as Get Stream response with is_archived: true

Unarchive Stream

Unarchive a stream (owner or admin only).

Endpoint: POST /streams/:id/unarchive

Headers:

  • Authorization: Bearer <token> (required)

Response: Same as Get Stream response with is_archived: false

Stream Analytics (Feature Flagged)

Get analytics data for a stream.

Endpoint: GET /streams/:id/analytics

Headers:

  • Authorization: Bearer <token> (required)

Note: This endpoint requires the stream_analytics feature flag to be enabled for the user.

Response:

{
  "stream_id": 1,
  "views_count": 5432,
  "unique_viewers": 876,
  "average_watch_time": 1823,
  "peak_concurrent_viewers": 234,
  "last_updated": "2024-01-01T12:00:00Z"
}

Bulk Import Streams (Feature Flagged)

Import multiple streams at once.

Endpoint: POST /streams/bulk_import

Headers:

  • Authorization: Bearer <token> (required)
  • Content-Type: application/json

Note: This endpoint requires the stream_bulk_import feature flag to be enabled (default: editors only).

Body:

{
  "streams": [
    {
      "title": "Stream 1",
      "source": "YouTube",
      "link": "https://example.com/stream1",
      "status": "live",
      "platform": "youtube"
    },
    {
      "title": "Stream 2",
      "source": "Twitch",
      "link": "https://example.com/stream2",
      "status": "live",
      "platform": "twitch"
    }
  ]
}

Response:

{
  "imported": 2,
  "total": 2,
  "errors": []
}

Export Streams (Feature Flagged)

Export stream data in JSON format.

Endpoint: GET /streams/export

Headers:

  • Authorization: Bearer <token> (required)

Query Parameters:

  • Same filtering options as List Streams

Note: This endpoint requires the stream_export feature flag to be enabled.

Response:

{
  "exported_at": "2024-01-01T12:00:00Z",
  "count": 25,
  "streams": [
    {
      "title": "Stream Title",
      "source": "YouTube Channel",
      "link": "https://example.com/stream",
      "platform": "youtube",
      "status": "live",
      "is_pinned": false,
      "is_archived": false,
      "created_at": "2024-01-01T10:00:00Z",
      "owner_email": "user@example.com",
      "streamer_name": "Example Streamer"
    }
  ]
}

Streamers

List Streamers

Get a paginated list of streamers.

Endpoint: GET /streamers

Headers:

  • Authorization: Bearer <token> (required)

Query Parameters:

  • page (optional): Page number (default: 1)
  • per_page (optional): Items per page (default: 25, max: 100)

Response:

{
  "streamers": [
    {
      "id": 1,
      "name": "Example Streamer",
      "description": "A popular content creator",
      "created_at": "2024-01-01T12:00:00Z",
      "updated_at": "2024-01-01T12:00:00Z",
      "streams_count": 15,
      "accounts_count": 3
    }
  ],
  "meta": {
    "current_page": 1,
    "total_pages": 5,
    "total_count": 123,
    "per_page": 25
  }
}

Get Streamer

Get a specific streamer by ID.

Endpoint: GET /streamers/:id

Headers:

  • Authorization: Bearer <token> (required)

Response:

{
  "id": 1,
  "name": "Example Streamer",
  "description": "A popular content creator",
  "created_at": "2024-01-01T12:00:00Z",
  "updated_at": "2024-01-01T12:00:00Z",
  "streams": [
    {
      "id": 1,
      "title": "Stream Title",
      "platform": "youtube",
      "status": "live"
    }
  ],
  "accounts": [
    {
      "id": 1,
      "platform": "youtube",
      "username": "examplestreamer",
      "url": "https://youtube.com/@examplestreamer"
    }
  ]
}

Create Streamer

Create a new streamer (requires editor or admin role).

Endpoint: POST /streamers

Headers:

  • Authorization: Bearer <token> (required)
  • Content-Type: application/json

Body:

{
  "name": "New Streamer",
  "description": "Description of the streamer"
}

Response: Same as Get Streamer response.

Update Streamer

Update an existing streamer (requires editor or admin role).

Endpoint: PATCH /streamers/:id

Headers:

  • Authorization: Bearer <token> (required)
  • Content-Type: application/json

Body:

{
  "name": "Updated Name",
  "description": "Updated description"
}

Response: Same as Get Streamer response with updated values.

Delete Streamer

Delete a streamer (requires admin role).

Endpoint: DELETE /streamers/:id

Headers:

  • Authorization: Bearer <token> (required)

Response: 204 No Content on success

WebSocket Connections

ActionCable Connection

Connect to the WebSocket endpoint for real-time updates.

Endpoint: ws://localhost:3000/cable

Authentication: Include the JWT token as a query parameter:

ws://localhost:3000/cable?token=<your-jwt-token>

Channels Available:

  • CollaborativeStreamsChannel: Real-time collaborative editing for streams admin interface

Example (JavaScript):

import { createConsumer } from '@rails/actioncable';

const consumer = createConsumer(`ws://localhost:3000/cable?token=${authToken}`);

// Note: WebSocket channels are primarily used for the admin interface
// The CollaborativeStreamsChannel is used for real-time collaborative editing
const collaborativeChannel = consumer.subscriptions.create('CollaborativeStreamsChannel', {
  received(data) {
    console.log('Collaborative update:', data);
  }
});

Health Checks

Health Status

Basic health check endpoint.

Endpoint: GET /health

Response:

{
  "status": "healthy",
  "timestamp": "2024-01-01T12:00:00Z",
  "version": "1.0.0"
}

Liveness Check

Kubernetes liveness probe endpoint.

Endpoint: GET /health/live

Response:

{
  "status": "ok"
}

Readiness Check

Kubernetes readiness probe endpoint (includes database check).

Endpoint: GET /health/ready

Response (Success):

{
  "status": "ready",
  "database": "connected"
}

Response (Failure):

{
  "status": "not ready",
  "error": "connection error message"
}

Error Responses

All error responses follow a consistent format:

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

Validation Errors

For validation errors, the message includes all validation failures:

{
  "error": "Name can't be blank, Url must be a valid HTTP or HTTPS URL"
}

Rate Limit Errors

When rate limited:

{
  "error": "Too many requests. Please try again later."
}

Roles and Permissions

Default User

  • View all streams
  • Cannot create, update, or delete streams

Editor

  • All default user permissions
  • Create new streams
  • Update/delete own streams
  • Pin/unpin own streams

Admin

  • All editor permissions
  • Update/delete any stream
  • Pin/unpin any stream

Example Workflows

Streamer Management Workflow

  1. Create a streamer:
curl -X POST http://localhost:3000/api/v1/streamers \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"name": "Popular Streamer", "description": "Gaming content creator"}'
  1. Add a stream for the streamer:
curl -X POST http://localhost:3000/api/v1/streams \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Live Gaming Session",
    "source": "YouTube",
    "link": "https://youtube.com/watch?v=xyz",
    "platform": "youtube",
    "status": "live",
    "streamer_id": 1
  }'

Complete Authentication Flow

  1. Sign up:
curl -X POST http://localhost:3000/api/v1/users/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "newuser@example.com", "password": "SecurePass123", "role": "editor"}'
  1. Save the token from the response

  2. Create a stream:

curl -X POST http://localhost:3000/api/v1/streams \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"title": "My Stream", "source": "YouTube", "link": "https://example.com/stream"}'

Stream Management Workflow

  1. List all active streams:
curl -X GET "http://localhost:3000/api/v1/streams?status=active" \
  -H "Authorization: Bearer <token>"
  1. Pin an important stream:
curl -X PUT http://localhost:3000/api/v1/streams/1/pin \
  -H "Authorization: Bearer <token>"
  1. Update stream details:
curl -X PATCH http://localhost:3000/api/v1/streams/1 \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated Title", "status": "ended", "ended_at": "2024-01-01T15:00:00Z"}'

SDK Examples

JavaScript/Node.js

const API_BASE = 'http://localhost:3000/api/v1';
let authToken = '';

// Login
async function login(email, password) {
  const response = await fetch(`${API_BASE}/users/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  });
  
  const data = await response.json();
  authToken = data.token;
  return data;
}

// Get streams
async function getStreams(params = {}) {
  const queryString = new URLSearchParams(params).toString();
  const response = await fetch(`${API_BASE}/streams?${queryString}`, {
    headers: { 'Authorization': `Bearer ${authToken}` }
  });
  
  return response.json();
}

// Create stream
async function createStream(title, source, link, platform = 'youtube') {
  const response = await fetch(`${API_BASE}/streams`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${authToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ title, source, link, platform })
  });
  
  return response.json();
}

Ruby

require 'net/http'
require 'json'

class StreamSourceClient
  API_BASE = 'http://localhost:3000/api/v1'
  
  def initialize
    @token = nil
  end
  
  def login(email, password)
    response = post('/users/login', { email: email, password: password })
    @token = response['token']
    response
  end
  
  def get_streams(params = {})
    get('/streams', params)
  end
  
  def create_stream(title, source, link, platform = 'youtube')
    post('/streams', { title: title, source: source, link: link, platform: platform })
  end
  
  private
  
  def get(path, params = {})
    uri = URI("#{API_BASE}#{path}")
    uri.query = URI.encode_www_form(params) unless params.empty?
    
    request = Net::HTTP::Get.new(uri)
    request['Authorization'] = "Bearer #{@token}" if @token
    
    execute_request(uri, request)
  end
  
  def post(path, body)
    uri = URI("#{API_BASE}#{path}")
    
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request['Authorization'] = "Bearer #{@token}" if @token
    request.body = body.to_json
    
    execute_request(uri, request)
  end
  
  def execute_request(uri, request)
    response = Net::HTTP.start(uri.hostname, uri.port) do |http|
      http.request(request)
    end
    
    JSON.parse(response.body)
  end
end

Python

import requests
import json

class StreamSourceAPI:
    def __init__(self, base_url='http://localhost:3000/api/v1'):
        self.base_url = base_url
        self.token = None
    
    def login(self, email, password):
        response = requests.post(
            f'{self.base_url}/users/login',
            json={'email': email, 'password': password}
        )
        data = response.json()
        self.token = data.get('token')
        return data
    
    def get_streams(self, **params):
        headers = {'Authorization': f'Bearer {self.token}'}
        response = requests.get(
            f'{self.base_url}/streams',
            headers=headers,
            params=params
        )
        return response.json()
    
    def create_stream(self, title, source, link, platform='youtube'):
        headers = {
            'Authorization': f'Bearer {self.token}',
            'Content-Type': 'application/json'
        }
        response = requests.post(
            f'{self.base_url}/streams',
            headers=headers,
            json={'title': title, 'source': source, 'link': link, 'platform': platform}
        )
        return response.json()

# Usage
api = StreamSourceAPI()
api.login('user@example.com', 'SecurePass123')
streams = api.get_streams(status='live', per_page=50)
new_stream = api.create_stream('My Stream', 'YouTube', 'https://example.com/stream', 'youtube')

Postman Collection

Import this collection to test the API in Postman:

{
  "info": {
    "name": "StreamSource API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "base_url",
      "value": "http://localhost:3000/api/v1"
    },
    {
      "key": "token",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Authentication",
      "item": [
        {
          "name": "Sign Up",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"test@example.com\",\n  \"password\": \"TestPass123\",\n  \"role\": \"editor\"\n}"
            },
            "url": "{{base_url}}/users/signup"
          }
        },
        {
          "name": "Login",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "var jsonData = pm.response.json();",
                  "pm.collectionVariables.set(\"token\", jsonData.token);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"test@example.com\",\n  \"password\": \"TestPass123\"\n}"
            },
            "url": "{{base_url}}/users/login"
          }
        }
      ]
    },
    {
      "name": "Streams",
      "item": [
        {
          "name": "List Streams",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{token}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/streams?status=active&per_page=10",
              "host": ["{{base_url}}"],
              "path": ["streams"],
              "query": [
                {
                  "key": "status",
                  "value": "active"
                },
                {
                  "key": "per_page",
                  "value": "10"
                }
              ]
            }
          }
        },
        {
          "name": "Create Stream",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{token}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\": \"Test Stream\",\n  \"source\": \"YouTube\",\n  \"link\": \"https://example.com/test\",\n  \"platform\": \"youtube\"\n}"
            },
            "url": "{{base_url}}/streams"
          }
        }
      ]
    }
  ]
}

Support

For issues or questions:

  • Check the error message for specific validation failures
  • Verify your authentication token is valid and not expired
  • Ensure you have the correct role for the operation
  • Check rate limit headers if receiving 429 errors
  • Review the health endpoints for system status