$ 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()