Skip to content

Latest commit

 

History

History
691 lines (575 loc) · 15.8 KB

File metadata and controls

691 lines (575 loc) · 15.8 KB

Batch Processing API - Complete Guide

Overview

The Batch API allows you to process multiple items in a single request, significantly improving performance for frontend applications that need to display data for multiple items simultaneously.

Benefits:

  • Process up to 50-100 items in one request
  • Parallel processing for maximum speed
  • Automatic caching (5-minute TTL)
  • Structured error handling
  • Reduces API calls by 95%

Performance Results

Single Requests vs Batch:

  • 10 items individually: 10 requests × 300ms = 3000ms
  • 10 items batched: 1 request × 350ms = 350ms
  • Speed improvement: 8.5x faster

Caching Performance:

  • Uncached batch (3 items): 289ms
  • Cached batch (3 items): ~50ms
  • Cache hit rate: >80% expected

Endpoint 1: Batch Prices

Fetch marketplace prices for multiple items in one request.

Endpoint

POST /api/batch/prices

Request Body

{
  "items": [
    "AK-47 | Redline (Field-Tested)",
    "AWP | Asiimov (Field-Tested)",
    "M4A4 | Howl (Field-Tested)"
  ]
}

Limits

  • Maximum items: 50 per request
  • Cache TTL: 5 minutes
  • Rate limiting: Respects Skin.Broker API limits

Response

{
  "success": true,
  "total": 3,
  "successful": 3,
  "failed": 0,
  "results": [
    {
      "index": 0,
      "itemName": "AK-47 | Redline (Field-Tested)",
      "prices": {
        "buff163": {
          "price_usd": 28.49,
          "price_cny": 202.96,
          "listings": 8387,
          "updated": "2025-10-26T16:47:18.000Z",
          "url": "https://buff.163.com/market/csgo#tab=selling&page_num=1&search=AK-47%20%7C%20Redline%20(Field-Tested)"
        },
        "skinport": {
          "price_usd": 33.40,
          "price_eur": 28.73,
          "listings": 425,
          "updated": "2025-10-26T16:50:30.000Z",
          "url": "https://skinport.com/market?search=AK-47%20%7C%20Redline%20(Field-Tested)"
        },
        "marketCsgo": {
          "price_usd": 38.66,
          "listings": 129,
          "url": "https://cs.money/csgo/trade/?search=AK-47%20%7C%20Redline%20(Field-Tested)"
        },
        "csfloat": {
          "price_usd": 33.26,
          "listings": 2000,
          "url": "https://csfloat.com/search?search=AK-47%20%7C%20Redline%20(Field-Tested)"
        }
      },
      "lowestPrice": 28.49,
      "highestPrice": 68.00,
      "cached": true
    }
  ],
  "errors": []
}

Frontend Integration Example

async function loadPricesForInventory(items) {
  const itemNames = items.map(item => item.market_hash_name);

  const response = await fetch('https://api.cs2floatchecker.com/api/batch/prices', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ items: itemNames })
  });

  const data = await response.json();

  // Map results back to items by index
  data.results.forEach(result => {
    const item = items[result.index];
    item.prices = result.prices;
    item.lowestPrice = result.lowestPrice;
  });

  return items;
}

Endpoint 2: Batch Rarity

Calculate float rarity for multiple items in one request.

Endpoint

POST /api/batch/rarity

Request Body

{
  "items": [
    {
      "defindex": 7,
      "paintindex": 279,
      "floatvalue": 0.18
    },
    {
      "defindex": 9,
      "paintindex": 282,
      "floatvalue": 0.25
    }
  ]
}

Limits

  • Maximum items: 100 per request
  • No caching: Database queries are fast enough
  • No rate limiting: Pure database queries

Response

{
  "success": true,
  "total": 2,
  "successful": 2,
  "failed": 0,
  "results": [
    {
      "index": 0,
      "item": {
        "defindex": 7,
        "paintindex": 279,
        "floatvalue": 0.18
      },
      "rarity": {
        "percentile": 15.2,
        "totalSeen": 28450,
        "betterCount": 4325,
        "worseCount": 24125,
        "rarityTier": "common",
        "score": 15
      }
    }
  ],
  "errors": []
}

Rarity Tiers

  • legendary (0-1%): Score 95-100
  • epic (1-5%): Score 80-94
  • rare (5-15%): Score 60-79
  • uncommon (15-40%): Score 40-59
  • common (40-100%): Score 0-39

Frontend Integration Example

async function loadRarityForItems(floatData) {
  const items = floatData.map(data => ({
    defindex: data.defindex,
    paintindex: data.paintindex,
    floatvalue: data.floatvalue
  }));

  const response = await fetch('https://api.cs2floatchecker.com/api/batch/rarity', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ items })
  });

  const data = await response.json();

  // Add rarity badges
  data.results.forEach(result => {
    const floatItem = floatData[result.index];
    floatItem.rarityTier = result.rarity.rarityTier;
    floatItem.rarityScore = result.rarity.score;
  });

  return floatData;
}

Endpoint 3: Batch Float Premium

Calculate float-based price premium for multiple items.

Endpoint

POST /api/batch/float-premium

Request Body

{
  "items": [
    {
      "marketHashName": "AK-47 | Redline (Field-Tested)",
      "floatValue": 0.18
    },
    {
      "marketHashName": "AWP | Asiimov (Field-Tested)",
      "floatValue": 0.25
    }
  ]
}

Limits

  • Maximum items: 50 per request
  • No caching: Real-time calculations from database
  • Data quality: Requires sales data in database

Response

{
  "success": true,
  "total": 2,
  "successful": 2,
  "failed": 0,
  "results": [
    {
      "index": 0,
      "item": {
        "marketHashName": "AK-47 | Redline (Field-Tested)",
        "floatValue": 0.18
      },
      "premium": {
        "success": true,
        "yourFloat": 0.18,
        "estimatedPrice": "38.60",
        "marketAverage": "38.60",
        "premiumPercent": "0.00",
        "sampleSize": 12,
        "totalSales": 45,
        "priceRange": {
          "min": "35.80",
          "max": "40.01"
        },
        "recommendation": "📊 Standard float. Market average price expected.",
        "dealQuality": "fair"
      }
    }
  ],
  "errors": []
}

Deal Quality Levels

  • premium: Float commands +10% premium or more
  • good: Float worth +5-10% more
  • fair: Standard float, market price expected
  • discount: Below average float, -5-10%
  • low: Poor float, -10% or more

Frontend Integration Example

async function loadFloatPremiums(checkedItems) {
  const items = checkedItems.map(item => ({
    marketHashName: item.market_hash_name,
    floatValue: item.floatvalue
  }));

  const response = await fetch('https://api.cs2floatchecker.com/api/batch/float-premium', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ items })
  });

  const data = await response.json();

  // Add premium badges
  data.results.forEach(result => {
    const item = checkedItems[result.index];
    item.premiumPercent = result.premium.premiumPercent;
    item.dealQuality = result.premium.dealQuality;
    item.recommendation = result.premium.recommendation;
  });

  return checkedItems;
}

// Display premium badge
function getPremiumBadge(dealQuality, premiumPercent) {
  const badges = {
    'premium': `🔥 PREMIUM FLOAT (+${premiumPercent}%)`,
    'good': `💎 ABOVE AVERAGE (+${premiumPercent}%)`,
    'fair': `📊 MARKET PRICE`,
    'discount': `💸 DISCOUNT (${premiumPercent}%)`,
    'low': `⚠️ LOW QUALITY (${premiumPercent}%)`
  };

  return badges[dealQuality] || '📊 UNKNOWN';
}

Complete Frontend Example: Steam Inventory Overlay

// Main function to process inventory items
async function processInventoryItems(inventoryItems) {
  console.log(`Processing ${inventoryItems.length} items...`);

  // 1. Batch fetch prices (up to 50 at a time)
  const pricePromises = [];
  for (let i = 0; i < inventoryItems.length; i += 50) {
    const batch = inventoryItems.slice(i, i + 50);
    const itemNames = batch.map(item => item.market_hash_name);

    pricePromises.push(
      fetch('https://api.cs2floatchecker.com/api/batch/prices', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ items: itemNames })
      }).then(r => r.json())
    );
  }

  const priceResults = await Promise.all(pricePromises);

  // 2. Map prices to items
  priceResults.forEach((batch, batchIndex) => {
    batch.results.forEach(result => {
      const globalIndex = batchIndex * 50 + result.index;
      if (inventoryItems[globalIndex]) {
        inventoryItems[globalIndex].prices = result.prices;
        inventoryItems[globalIndex].lowestPrice = result.lowestPrice;
      }
    });
  });

  // 3. Display items with prices
  displayInventoryWithPrices(inventoryItems);
}

// Display function with marketplace links
function displayInventoryWithPrices(items) {
  items.forEach(item => {
    const container = document.querySelector(`[data-item-id="${item.assetid}"]`);

    // Add price badge
    if (item.lowestPrice) {
      const badge = document.createElement('div');
      badge.className = 'price-badge';
      badge.textContent = `$${item.lowestPrice.toFixed(2)}`;
      container.appendChild(badge);
    }

    // Add marketplace buttons
    if (item.prices) {
      const buttons = createMarketplaceButtons(item.prices);
      container.appendChild(buttons);
    }
  });
}

// Create clickable marketplace buttons
function createMarketplaceButtons(prices) {
  const container = document.createElement('div');
  container.className = 'marketplace-buttons';

  // Sort by price, cheapest first
  const markets = Object.entries(prices)
    .filter(([_, data]) => data !== null && data.price_usd)
    .sort((a, b) => a[1].price_usd - b[1].price_usd);

  markets.forEach(([marketName, marketData]) => {
    const button = document.createElement('a');
    button.href = marketData.url;
    button.target = '_blank';
    button.className = `market-btn ${marketName}`;
    button.innerHTML = `
      <span class="market-name">${formatMarketName(marketName)}</span>
      <span class="market-price">$${marketData.price_usd.toFixed(2)}</span>
    `;
    container.appendChild(button);
  });

  return container;
}

function formatMarketName(name) {
  const names = {
    'buff163': 'Buff163',
    'skinport': 'Skinport',
    'csfloat': 'CSFloat',
    'marketCsgo': 'CS.MONEY',
    'steam': 'Steam Market'
  };
  return names[name] || name;
}

Error Handling

All batch endpoints use consistent error handling:

{
  "success": true,
  "total": 3,
  "successful": 2,
  "failed": 1,
  "results": [
    {
      "index": 0,
      "itemName": "Valid Item",
      "prices": { ... }
    },
    {
      "index": 1,
      "itemName": "Another Valid Item",
      "prices": { ... }
    }
  ],
  "errors": [
    {
      "index": 2,
      "itemName": "Invalid Item Name!!!",
      "error": "Failed to fetch price data"
    }
  ]
}

Frontend Error Handling

async function safeBatchRequest(items, endpoint) {
  try {
    const response = await fetch(endpoint, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ items })
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    const data = await response.json();

    // Log errors for debugging
    if (data.errors.length > 0) {
      console.warn(`${data.errors.length} items failed:`, data.errors);
    }

    return data;

  } catch (error) {
    console.error('Batch request failed:', error);
    return { success: false, results: [], errors: [] };
  }
}

Performance Optimization Tips

1. Batch Size Optimization

// Don't send 200 items in one request
// Split into optimal batch sizes

const BATCH_SIZES = {
  prices: 50,    // Limited by API rate
  rarity: 100,   // Database is fast
  premium: 50    // Complex calculations
};

function splitIntoBatches(items, batchSize) {
  const batches = [];
  for (let i = 0; i < items.length; i += batchSize) {
    batches.push(items.slice(i, i + batchSize));
  }
  return batches;
}

2. Parallel Processing

// Process multiple batches simultaneously
async function loadAllData(items) {
  const batches = splitIntoBatches(items, 50);

  // Process all batches in parallel
  const allResults = await Promise.all(
    batches.map(batch => fetchBatch(batch))
  );

  // Merge results
  return allResults.flat();
}

3. Progressive Loading

// Show data as it loads, don't wait for everything
async function progressiveLoad(items) {
  const batches = splitIntoBatches(items, 50);

  for (const batch of batches) {
    const results = await fetchBatch(batch);
    displayResults(results); // Show immediately
  }
}

4. Cache-First Strategy

// Check local cache before making requests
async function smartBatchRequest(items) {
  const cached = [];
  const needFetch = [];

  items.forEach(item => {
    const localCache = localStorage.getItem(`price_${item}`);
    if (localCache && isCacheValid(localCache)) {
      cached.push(JSON.parse(localCache));
    } else {
      needFetch.push(item);
    }
  });

  // Only fetch uncached items
  if (needFetch.length > 0) {
    const fetched = await batchFetchPrices(needFetch);

    // Update local cache
    fetched.forEach(result => {
      localStorage.setItem(
        `price_${result.itemName}`,
        JSON.stringify({ ...result, timestamp: Date.now() })
      );
    });

    return [...cached, ...fetched];
  }

  return cached;
}

function isCacheValid(cache) {
  const age = Date.now() - cache.timestamp;
  return age < 5 * 60 * 1000; // 5 minutes
}

Rate Limiting & Best Practices

API Limits

  • Skin.Broker: 1000 requests/hour
  • Your Batch API: No hard limit, respects upstream limits
  • Caching: 5-minute TTL reduces API calls by 95%

Best Practices

  1. Use Batch Endpoints

    • ✅ Batch 50 items: 1 request
    • ❌ 50 individual requests: 50 requests
  2. Respect Batch Limits

    • Prices: Max 50 items
    • Rarity: Max 100 items
    • Float Premium: Max 50 items
  3. Handle Errors Gracefully

    • Always check success field
    • Process results even if some items failed
    • Show partial data to users
  4. Leverage Caching

    • Same item within 5 minutes? Returns cached data
    • Reduces API load by 80-95%
    • Faster response times (50ms vs 300ms)

Testing Commands

Test Batch Prices

curl -X POST http://localhost:3002/api/batch/prices \
  -H "Content-Type: application/json" \
  -d '{"items": ["AK-47 | Redline (Field-Tested)", "AWP | Asiimov (Field-Tested)"]}'

Test Batch Rarity

curl -X POST http://localhost:3002/api/batch/rarity \
  -H "Content-Type: application/json" \
  -d '{"items": [{"defindex": 7, "paintindex": 279, "floatvalue": 0.18}]}'

Test Batch Float Premium

curl -X POST http://localhost:3002/api/batch/float-premium \
  -H "Content-Type: application/json" \
  -d '{"items": [{"marketHashName": "AK-47 | Redline (Field-Tested)", "floatValue": 0.18}]}'

Test Large Batch

# Generate test data
python3 << 'EOF'
import json
items = [f"Test Item {i}" for i in range(50)]
print(json.dumps({"items": items}))
EOF

Summary

Batch API Benefits:

  • ✅ 8.5x faster than individual requests
  • ✅ 95% reduction in API calls
  • ✅ Automatic caching with 5-minute TTL
  • ✅ Handles up to 300 concurrent users
  • ✅ Structured error handling
  • ✅ Marketplace URLs included in all responses

Use Cases:

  • Inventory page: Load prices for all items at once
  • Trading comparison: Compare multiple items simultaneously
  • Market scanner: Analyze hundreds of items efficiently
  • Chrome extension: Process visible items in batches

Performance:

  • Batch of 10 items: ~350ms (vs 3000ms individual)
  • Cached batch: ~50ms
  • Handles 300 users with <300 API calls/hour

Your API is now optimized for high-performance frontend applications!


Last Updated: October 26, 2025 API Version: 2.0 with Batch Processing