Generate code to integrate with external APIs
Workflow Description: Generate code to integrate with external APIs.
Step: collab → generate_code
This deliverable provides comprehensive, production-ready code for integrating with an external API. As part of the "API Integration Builder" workflow, this step focuses on generating a robust, well-structured, and easily customizable API client in Python.
For demonstration purposes, we've designed this code to interact with a hypothetical "Product Management API." This allows us to showcase common API integration patterns such as GET (fetching data), POST (creating data), PUT (updating data), and DELETE (removing data), along with essential features like authentication, error handling, and logging.
The generated code is designed to be a strong foundation that you can adapt to your specific API and business logic.
Before diving into the code, it's important to understand the fundamental principles guiding robust API integration:
To provide a concrete example, we've structured the generated code around a hypothetical RESTful API for managing products.
Hypothetical API Details:
https://api.example.com/v1 (configurable)X-API-KEY header.Key Endpoints & Operations:
| Operation | HTTP Method | Endpoint | Description | Request Body (Example) | Response Body (Example) |
| :----------------- | :---------- | :----------------- | :--------------------------------------------- | :--------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Get All Products | GET | /products | Retrieves a list of all products. | None | [{"id": "prod_123", "name": "Laptop", "price": 1200.00, "category": "Electronics"}, ...] |
| Get Product by ID | GET | /products/{id} | Retrieves a single product by its ID. | None | {"id": "prod_123", "name": "Laptop", "price": 1200.00, "category": "Electronics"} |
| Create Product | POST | /products | Creates a new product. | {"name": "New Product", "price": 99.99, "category": "General"} | {"id": "prod_456", "name": "New Product", "price": 99.99, "category": "General"} |
| Update Product | PUT | /products/{id} | Updates an existing product. | {"name": "Updated Product Name", "price": 109.99} | {"id": "prod_123", "name": "Updated Product Name", "price": 109.99, "category": "Electronics"} |
| Delete Product | DELETE | /products/{id} | Deletes a product by its ID. | None | {"message": "Product prod_123 deleted successfully"} (or HTTP 204 No Content) |
| Error Response | N/A | N/A | Generic error structure. | N/A | {"status": 404, "error": "Not Found", "message": "Product with ID prod_xyz not found."} or {"status": 400, "error": "Bad Request", "message": "Invalid input data."} (Note: This is a common pattern, but actual API error structures vary.) |
Below is the Python code for a ProductAPIClient class, which encapsulates the logic for interacting with our hypothetical Product Management API.
import requests
import json
import logging
import os
from typing import Dict, Any, List, Optional
# --- Configuration ---
# It's recommended to manage sensitive information like API keys via environment variables
# or a secure configuration management system (e.g., AWS Secrets Manager, HashiCorp Vault).
# For demonstration, we'll try to load from environment or use a placeholder.
API_BASE_URL = os.getenv("PRODUCT_API_BASE_URL", "https://api.example.com/v1")
API_KEY = os.getenv("PRODUCT_API_KEY", "YOUR_SECRET_API_KEY") # REPLACE WITH YOUR ACTUAL API KEY
# --- Logging Setup ---
# Configure logging for better visibility into API interactions and potential issues.
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# --- Custom Exception for API Errors ---
class APIIntegrationError(Exception):
"""Custom exception for API-related errors."""
def __init__(self, message: str, status_code: Optional[int] = None, api_response: Optional[Dict] = None):
super().__init__(message)
self.status_code = status_code
self.api_response = api_response
def __str__(self):
details = f"Status Code: {self.status_code}" if self.status_code else "N/A"
if self.api_response:
details += f", API Response: {json.dumps(self.api_response)}"
return f"APIIntegrationError: {self.args[0]} ({details})"
# --- API Client Class ---
class ProductAPIClient:
"""
A client for interacting with the Product Management API.
Handles API requests, responses, authentication, and error handling.
"""
def __init__(self, base_url: str, api_key: str, timeout: int = 30):
"""
Initializes the ProductAPIClient.
Args:
base_url (str): The base URL of the Product Management API (e.g., "https://api.example.com/v1").
api_key (str): The API key for authentication.
timeout (int): Default timeout for API requests in seconds.
"""
if not base_url or not api_key:
raise ValueError("Base URL and API Key must be provided.")
self.base_url = base_url
self.api_key = api_key
self.timeout = timeout
self.headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"X-API-KEY": self.api_key # Example: API Key in a custom header
}
logger.info(f"ProductAPIClient initialized with base_url: {self.base_url}")
def _make_request(self, method: str, endpoint: str, params: Optional[Dict] = None, data: Optional[Dict] = None) -> Any:
"""
Internal helper method to make an HTTP request to the API.
Args:
method (str): HTTP method (GET, POST, PUT, DELETE).
endpoint (str): The API endpoint relative to the base URL (e.g., "/products").
params (Optional[Dict]): Dictionary of query parameters.
data (Optional[Dict]): Dictionary of request body data (for POST/PUT).
Returns:
Any: Parsed JSON response from the API.
Raises:
APIIntegrationError: If the API request fails or returns an error status.
"""
url = f"{self.base_url}{endpoint}"
logger.debug(f"Making {method} request to: {url}")
logger.debug(f"Headers: {self.headers}")
if params:
logger.debug(f"Params: {params}")
if data:
logger.debug(f"Payload: {json.dumps(data)}")
try:
response = requests.request(
method,
url,
headers=self.headers,
params=params,
json=data, # Use 'json' parameter for automatic JSON serialization
timeout=self.timeout
)
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
# Attempt to parse JSON, even for successful responses that might be empty or non-JSON
try:
if response.content: # Check if there's content before trying to parse JSON
return response.json()
else:
return None # No content, e.g., for 204 No Content
except json.JSONDecodeError:
logger.warning(f"Response content is not valid JSON for {url}. Content: {response.text}")
return response.text # Return raw text if not JSON
except requests.exceptions.HTTPError as e:
error_details = {"status": e.response.status_code, "error": str(e)}
try:
api_response_json = e.response.json()
error_details.update(api_response_json) # Merge API's error details
error_message = api_response_json.get("message", f"API error for {endpoint}")
except json.JSONDecodeError:
error_message = f"API error for {endpoint}: {e.response.text}"
logger.error(f"HTTP Error {e.response.status_code} for {url}: {error_message}")
raise APIIntegrationError(
message=error_message,
status_code=e.response.status_code,
api_response=error_details
) from e
except requests.exceptions.ConnectionError as e:
logger.error(f"Connection Error to {url}: {e}")
raise APIIntegrationError(f"Network connection error: {e}") from e
except requests.exceptions.Timeout as e:
logger.error(f"Timeout Error for {url}: {e}")
raise APIIntegrationError(f"Request timed out after {self.timeout} seconds: {e}") from e
except requests.exceptions.RequestException as e:
logger.error(f"An unexpected request error occurred for {url}: {e}")
raise APIIntegrationError(f"An unexpected request error occurred: {e}") from e
except Exception as e:
logger.critical(f"An unhandled error occurred during API request for {url}: {e}", exc_info=True)
raise APIIntegrationError(f"An unhandled internal error occurred: {e}") from e
# --- Product-specific API Methods ---
def get_all_products(self, limit: Optional[int] = None, offset: Optional[int] = None) -> List[Dict]:
"""
Retrieves a list of all products.
Args:
limit (Optional[int]): Max number of products to return.
offset (Optional[int]): Number of products to skip.
Returns:
List[Dict]: A list of product dictionaries.
"""
endpoint = "/products"
params = {}
if limit is not None:
params["limit"] = limit
if offset is not None:
params["offset"] = offset
logger.info("Fetching all products...")
response = self._make_request("GET", endpoint, params=params)
return response if isinstance(response, list) else [] # Ensure it's a list
def get_product_by_id(self, product_id: str) -> Dict:
"""
Retrieves a single product by its ID.
Args:
product_id (str): The ID of the product to retrieve.
Returns:
Dict: A dictionary representing the product.
Raises:
APIIntegrationError: If the product is not found or another API error occurs.
"""
endpoint = f"/products/{product_id}"
logger.info(f"Fetching product with ID: {product_id}")
response = self._make_request("GET", endpoint)
return response if isinstance(response, dict) else {} # Ensure it's a dict
def create_product(self, product_data: Dict) -> Dict:
"""
Creates a new product.
Args:
product_data (Dict): A dictionary containing the product's details
(e.g., {"name": "Laptop", "price": 1200.00, "category": "Electronics"}).
Returns:
Dict: A dictionary representing the newly created product, including its ID.
"""
endpoint = "/products"
logger.info(f"Creating product: {product_data.get('name', 'N/A')}")
response = self._make_request("POST", endpoint, data=product_data)
return response if isinstance(response, dict) else {}
def update_product(self, product_id: str, product_data: Dict) -> Dict:
"""
Updates an existing product.
Args:
product_id (str): The ID of the product to update.
product_data (Dict): A dictionary containing the updated product details.
Only fields to be updated need to be included.
Returns:
Dict: A dictionary representing the updated product.
"""
endpoint = f"/products/{product_id}"
logger.info(f"Updating product ID {product_id} with data: {product_data}")
response = self._make_request("PUT", endpoint, data=product_data)
return response if isinstance(response, dict) else {}
def delete_product(self, product_id: str) -> None:
"""
Deletes a product by its ID.
Args:
product_id (str): The ID of the
Project Status: Initiated
Workflow Step: projectmanager → create_project
Description: API Integration Project Setup
We are pleased to confirm that your API Integration Project has been successfully initiated. This foundational step marks the beginning of leveraging external APIs to enhance your systems, automate workflows, and unlock new capabilities.
This document outlines the scope of this project, the immediate next steps required from your end, and how we will proceed to generate the specific code for your desired API integration.
The "API Integration Builder" project is designed to provide you with robust, scalable, and maintainable code for integrating with various external APIs. Our goal is to streamline the development process, minimize manual effort, and ensure a secure and efficient connection between your applications and third-party services.
Key Benefits of this Project:
While your specific integration will have unique requirements, the overall process typically follows these structured phases:
* Identify the target API (e.g., Salesforce, Stripe, Shopify, custom REST API).
* Define specific integration goals (e.g., create a customer, fetch order details, sync product inventory).
* Understand the API's authentication, rate limits, and data structures.
* Architectural considerations (e.g., direct integration, middleware, event-driven).
* Error handling strategies, logging, and monitoring.
* Security best practices.
* Generate API client code based on specified requirements.
* Implement logic for data transformation, request/response handling, and error management.
* Integrate with your existing application codebase.
* Unit tests for individual API calls.
* Integration tests to ensure end-to-end functionality.
* Performance and load testing (if applicable).
* Deployment to development, staging, and production environments.
* Implement monitoring tools for API health, performance, and error tracking.
* Handle API version changes, deprecations, and new features.
* Ongoing support and enhancements.
To move forward from project initiation to generating the specific integration code, we require detailed information about your target API and integration objectives. Please provide the following:
https://api.example.com/v1).Example 1:* "Create a new customer (POST /customers)"
Example 2:* "Retrieve an order by ID (GET /orders/{id})"
Example 3:* "Update product inventory (PUT /products/{id}/inventory)"
Example 4:* "Listen for webhook events (POST /webhooks/stripe)"
At this stage, we have successfully:
To proceed with the development of your API integration code, please compile and submit the information requested in Section 3: Immediate Next Steps.
You can reply to this message with the details, or if you prefer a more interactive session, please let us know your availability to schedule a dedicated requirements gathering call.
Should you have any questions or require clarification on any of the requested information, please do not hesitate to reach out to your dedicated project manager or our support team. We are here to assist you every step of the way.
We look forward to receiving your input and moving to the next exciting phase of building your API integration!