$ cat node-template.py

HTTP API Caller

// Makes HTTP requests to external APIs with support for various methods, headers, authentication, and response processing. Useful for integrating external services and fetching data from APIs.

Process
Integration
template.py
1import os2import sys3import traceback4import json5from typing import Dict, List, Any, Optional6from datetime import datetime7import time89# Execution context10EXECUTION_CONTEXT = {11    "workspace_id": os.getenv("WORKSPACE_ID"),12    "node_id": os.getenv("NODE_ID"),13    "execution_id": os.getenv("EXECUTION_ID"),14}151617def make_http_request(18    url: str,19    method: str = "GET",20    headers: Optional[Dict[str, str]] = None,21    body: Optional[Dict[str, Any]] = None,22    query_params: Optional[Dict[str, str]] = None,23    timeout: int = 30,24    retry_attempts: int = 0,25) -> Dict[str, Any]:26    """Make HTTP request with retry logic"""27    import requests28    from urllib.parse import urlencode2930    # Build URL with query parameters31    if query_params:32        url = f"{url}?{urlencode(query_params)}"3334    # Setup headers35    request_headers = headers or {}3637    # Prepare request kwargs38    request_kwargs = {39        "headers": request_headers,40        "timeout": timeout,41    }4243    if body and method in ["POST", "PUT", "PATCH"]:44        request_kwargs["json"] = body4546    # Make request with retry logic47    last_error = None48    for attempt in range(retry_attempts + 1):49        try:50            response = requests.request(method, url, **request_kwargs)5152            # Check for HTTP errors53            response.raise_for_status()5455            return {56                "status_code": response.status_code,57                "headers": dict(response.headers),58                "body": response.text,59                "success": True,60            }6162        except requests.exceptions.RequestException as e:63            last_error = e6465            # If this is not the last attempt, wait before retrying66            if attempt < retry_attempts:67                wait_time = 2 ** attempt  # Exponential backoff68                time.sleep(wait_time)69            else:70                # Last attempt failed71                return {72                    "status_code": getattr(e.response, "status_code", None) if hasattr(e, "response") else None,73                    "headers": dict(getattr(e.response, "headers", {})) if hasattr(e, "response") else {},74                    "body": str(e),75                    "success": False,76                    "error": str(e),77                }7879    # Should never reach here, but just in case80    return {81        "status_code": None,82        "headers": {},83        "body": str(last_error),84        "success": False,85        "error": str(last_error),86    }878889def parse_response(90    response: Dict[str, Any],91    response_format: str,92    extract_path: Optional[str] = None,93) -> Any:94    """Parse and extract data from response"""9596    if not response["success"]:97        raise Exception(f"Request failed: {response.get('error')}")9899    body = response["body"]100101    # Parse based on format102    if response_format == "json":103        try:104            data = json.loads(body)105        except json.JSONDecodeError as e:106            raise Exception(f"Failed to parse JSON response: {str(e)}")107108        # Extract specific path if provided109        if extract_path:110            for key in extract_path.split("."):111                if isinstance(data, dict) and key in data:112                    data = data[key]113                elif isinstance(data, list) and key.isdigit():114                    data = data[int(key)]115                else:116                    raise Exception(f"Extract path '{extract_path}' not found in response")117118        return data119120    elif response_format == "text":121        return body122123    else:  # raw124        return {125            "body": body,126            "headers": response["headers"],127            "status_code": response["status_code"],128        }129130131def main():132    """Main execution function"""133    try:134        # Read execution input from stdin135        input_json = sys.stdin.read()136        execution_input = json.loads(input_json)137138        # Extract inputs (from widgets or connections)139        inputs = execution_input.get("inputs", {})140141        url = inputs.get("url")142        if not url:143            raise ValueError("url input is required")144145        method = inputs.get("method", "GET")146        timeout = inputs.get("timeout", 30)147        retry_attempts = inputs.get("retryAttempts", 0)148        response_format = inputs.get("responseFormat", "json")149        extract_path = inputs.get("extractPath")150151        # Parse JSON inputs that may come as strings from widget152        def parse_json_input(value):153            if value is None:154                return None155            if isinstance(value, dict):156                return value157            if isinstance(value, str):158                value = value.strip()159                if not value:160                    return None161                try:162                    return json.loads(value)163                except json.JSONDecodeError:164                    return None165            return None166167        headers = parse_json_input(inputs.get("headers"))168        body = parse_json_input(inputs.get("body"))169        query_params = parse_json_input(inputs.get("queryParams"))170171        # Make HTTP request172        response = make_http_request(173            url,174            method,175            headers,176            body,177            query_params,178            timeout,179            retry_attempts,180        )181182        # Parse response183        data = parse_response(response, response_format, extract_path)184185        # Flat output — keys match OUTPUT_SCHEMA186        output = {187            "data": data,188            "statusCode": response["status_code"],189            "success": response["success"],190        }191        print(json.dumps(output, indent=2))192193    except Exception as e:194        # Write error to stderr195        error_output = {196            "error": str(e),197            "errorType": type(e).__name__,198            "traceback": traceback.format_exc(),199            "executionContext": EXECUTION_CONTEXT,200        }201        print(json.dumps(error_output), file=sys.stderr)202        sys.exit(1)203204205if __name__ == "__main__":206    main()