Error Handling

Comprehensive guide to handling errors in the StreetVerify API. Learn about error codes, response formats, and best practices for robust error handling.

Overview

The StreetVerify API uses standard HTTP response codes and consistent JSON error responses to help you handle errors gracefully. All error responses follow a predictable format, making it easy to implement robust error handling in your applications.

Error Response Format

All API errors return a consistent JSON structure:

{
  "error": "Error message describing what went wrong",
  "code": "ERROR_CODE",
  "details": {
    // Additional context when available
  }
}

Note: Successful responses return data directly without any wrapper. Only error responses use this format.

HTTP Status Codes

StreetVerify uses standard HTTP status codes to indicate the success or failure of requests:

Success Codes

  • 200 OK: Request completed successfully
  • 201 Created: Resource created successfully (e.g., new API key)

Client Error Codes

  • 400 Bad Request: Invalid request parameters or malformed request
  • 401 Unauthorized: Missing or invalid API key
  • 403 Forbidden: Valid API key but insufficient permissions
  • 404 Not Found: Requested resource doesn’t exist
  • 422 Unprocessable Entity: Request understood but contains invalid data
  • 429 Too Many Requests: Rate limit exceeded

Server Error Codes

  • 500 Internal Server Error: Unexpected server error
  • 502 Bad Gateway: Upstream service unavailable
  • 503 Service Unavailable: Service temporarily offline
  • 504 Gateway Timeout: Request timeout

Common Error Codes

Authentication Errors

// Missing API Key
{
  "error": "API key is required",
  "code": "MISSING_API_KEY"
}

// Invalid API Key
{
  "error": "Invalid API key",
  "code": "INVALID_API_KEY"
}

// Expired API Key
{
  "error": "API key has been revoked",
  "code": "API_KEY_REVOKED"
}

Validation Errors

// Missing Required Parameter
{
  "error": "Missing required parameter: address",
  "code": "MISSING_PARAMETER",
  "details": {
    "parameter": "address"
  }
}

// Invalid Address Format
{
  "error": "Invalid address format",
  "code": "INVALID_ADDRESS",
  "details": {
    "provided": "123",
    "hint": "Please provide a complete address"
  }
}

// Invalid Coordinates
{
  "error": "Invalid coordinates",
  "code": "INVALID_COORDINATES",
  "details": {
    "lat": "invalid",
    "lng": "-200.5",
    "errors": ["Latitude must be between -90 and 90", "Longitude must be between -180 and 180"]
  }
}

Rate Limiting Errors

{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "details": {
    "limit": 100,
    "window": "60 seconds",
    "retry_after": 45
  }
}

Service Errors

// Address Not Found
{
  "error": "Unable to verify the provided address",
  "code": "ADDRESS_NOT_FOUND",
  "details": {
    "address": "123 Fake Street, Nowhere, XX 00000",
    "suggestions": []
  }
}

// Geocoding Failed
{
  "error": "Unable to geocode the provided address",
  "code": "GEOCODING_FAILED",
  "details": {
    "reason": "Address too ambiguous"
  }
}

Error Handling Best Practices

1. Always Check Response Status

const response = await fetch(url, options);

if (!response.ok) {
  // Handle error
  const error = await response.json();
  console.error(`API Error: ${error.error} (${error.code})`);
  return;
}

// Process successful response
const data = await response.json();

2. Implement Retry Logic

For transient errors (5xx status codes), implement exponential backoff:

async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      const data = await response.json();
      
      if (response.status >= 500 && i < maxRetries - 1) {
        // Wait before retrying (exponential backoff)
        await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
        continue;
      }
      
      return data;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
    }
  }
}

3. Handle Rate Limits Gracefully

async function handleRateLimit(response, data) {
  if (response.status === 429) {
    const retryAfter = data.details?.retry_after || 60;
    console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);
    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
    // Retry the request
  }
}

4. Provide User-Friendly Messages

function getUserMessage(error) {
  const messages = {
    'INVALID_ADDRESS': 'Please enter a valid address',
    'ADDRESS_NOT_FOUND': 'We couldn\'t find that address. Please check and try again',
    'RATE_LIMIT_EXCEEDED': 'Too many requests. Please wait a moment and try again',
    'INVALID_API_KEY': 'Authentication failed. Please check your API key',
    'NETWORK_ERROR': 'Connection error. Please check your internet and try again'
  };
  
  return messages[error.code] || 'An unexpected error occurred. Please try again.';
}

5. Log Errors for Debugging

function logError(error, context) {
  console.error({
    timestamp: new Date().toISOString(),
    code: error.code,
    message: error.error,
    details: error.details,
    context: context,
    stack: new Error().stack
  });
}

Language-Specific Examples

Python

import requests
from time import sleep

def call_streetverify_api(endpoint, params, api_key):
    headers = {'Authorization': f'Bearer {api_key}'}
    
    try:
        response = requests.get(
            f'https://core.streetverify.com/api/v1/{endpoint}',
            params=params,
            headers=headers
        )
        
        data = response.json()
        
        if not response.ok:
            # Handle API error
            if data.get('code') == 'RATE_LIMIT_EXCEEDED':
                sleep(data.get('details', {}).get('retry_after', 60))
                # Retry the request
            else:
                raise Exception(f"API Error: {data.get('error')} ({data.get('code')})")
        
        return data
        
    except requests.exceptions.RequestException as e:
        # Handle network errors
        raise Exception(f"Network error: {str(e)}")

Node.js

const axios = require('axios');

class StreetVerifyClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseURL = 'https://core.streetverify.com/api/v1';
  }

  async request(endpoint, params) {
    try {
      const response = await axios.get(`${this.baseURL}/${endpoint}`, {
        params,
        headers: {
          'Authorization': `Bearer ${this.apiKey}`
        }
      });

      // Response data is returned directly for successful requests

      return response.data;
    } catch (error) {
      if (error.response) {
        // API returned an error
        throw new APIError(error.response.data);
      } else {
        // Network or other error
        throw new NetworkError(error.message);
      }
    }
  }
}

class APIError extends Error {
  constructor(errorData) {
    super(errorData.error);
    this.code = errorData.code;
    this.details = errorData.details;
  }
}

class NetworkError extends Error {
  constructor(message) {
    super(`Network error: ${message}`);
    this.code = 'NETWORK_ERROR';
  }
}

Testing Error Handling

To test your error handling, you can use these test cases:

  1. Invalid API Key: Use an incorrect API key to test 401 errors
  2. Missing Parameters: Omit required parameters to test 400 errors
  3. Invalid Data: Send malformed data to test validation errors
  4. Rate Limiting: Make rapid requests to test 429 errors
  5. Network Issues: Test timeout and connection errors

Support

If you encounter persistent errors or need help debugging:

  1. Check our API Status page
  2. Review the error code and message carefully
  3. Verify your API key is valid and active
  4. Contact support with the error details and request ID

Remember: Good error handling improves user experience and makes debugging easier. Implement comprehensive error handling from the start!