fix: API Request to use new fields and add DataInputs for Body,Header and Query
This commit is contained in:
parent
3d492db3d9
commit
3b6060b243
1 changed files with 65 additions and 32 deletions
|
|
@ -1,20 +1,26 @@
|
|||
import asyncio
|
||||
import json
|
||||
from typing import Any, List, Optional
|
||||
from urllib.parse import urlencode, urlparse, parse_qsl, urlunparse
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from langflow.base.curl.parse import parse_context
|
||||
from langflow.custom import Component
|
||||
from langflow.io import DropdownInput, IntInput, NestedDictInput, Output, TextInput
|
||||
from langflow.io import DropdownInput, IntInput, NestedDictInput, Output, TextInput, DataInput
|
||||
from langflow.schema import Data
|
||||
from langflow.schema.dotdict import dotdict
|
||||
|
||||
|
||||
class APIRequestComponent(Component):
|
||||
display_name = "API Request"
|
||||
description = "Make HTTP requests given one or more URLs."
|
||||
description = (
|
||||
"This component allows you to make HTTP requests to one or more URLs. "
|
||||
"You can provide headers and body as either dictionaries or Data objects. "
|
||||
"Additionally, you can append query parameters to the URLs.\n\n"
|
||||
"**Note:** Check advanced options for more settings."
|
||||
)
|
||||
icon = "Globe"
|
||||
|
||||
inputs = [
|
||||
|
|
@ -27,7 +33,7 @@ class APIRequestComponent(Component):
|
|||
TextInput(
|
||||
name="curl",
|
||||
display_name="Curl",
|
||||
info="Paste a curl command to populate the fields.",
|
||||
info="Paste a curl command to populate the fields. This will fill in the dictionary fields for headers and body.",
|
||||
advanced=False,
|
||||
refresh_button=True,
|
||||
),
|
||||
|
|
@ -36,17 +42,34 @@ class APIRequestComponent(Component):
|
|||
display_name="Method",
|
||||
options=["GET", "POST", "PATCH", "PUT"],
|
||||
value="GET",
|
||||
info="The HTTP method to use.",
|
||||
info="The HTTP method to use (GET, POST, PATCH, PUT).",
|
||||
),
|
||||
NestedDictInput(
|
||||
DataInput(
|
||||
name="headers",
|
||||
display_name="Headers",
|
||||
info="The headers to send with the request.",
|
||||
display_name="Headers Data",
|
||||
info="The headers to send with the request as a Data object.",
|
||||
),
|
||||
NestedDictInput(
|
||||
name="headers_dict",
|
||||
display_name="Headers Dictionary",
|
||||
info="The headers to send with the request as a dictionary. This is populated when using the CURL field.",
|
||||
advanced=True,
|
||||
),
|
||||
DataInput(
|
||||
name="body",
|
||||
display_name="Body",
|
||||
info="The body to send with the request (for POST, PATCH, PUT).",
|
||||
display_name="Body Data",
|
||||
info="The body to send with the request as a Data object (for POST, PATCH, PUT).",
|
||||
),
|
||||
NestedDictInput(
|
||||
name="body_dict",
|
||||
display_name="Body Dictionary",
|
||||
info="The body to send with the request as a dictionary (for POST, PATCH, PUT). This is populated when using the CURL field.",
|
||||
advanced=True,
|
||||
),
|
||||
DataInput(
|
||||
name="query_params",
|
||||
display_name="Query Parameters",
|
||||
info="The query parameters to append to the URL.",
|
||||
),
|
||||
IntInput(
|
||||
name="timeout",
|
||||
|
|
@ -65,13 +88,16 @@ class APIRequestComponent(Component):
|
|||
parsed = parse_context(curl)
|
||||
build_config["urls"]["value"] = [parsed.url]
|
||||
build_config["method"]["value"] = parsed.method.upper()
|
||||
build_config["headers"]["value"] = dict(parsed.headers)
|
||||
build_config["headers_dict"]["value"] = dict(parsed.headers)
|
||||
|
||||
try:
|
||||
json_data = json.loads(parsed.data)
|
||||
build_config["body"]["value"] = json_data
|
||||
except json.JSONDecodeError as e:
|
||||
print(e)
|
||||
if parsed.data:
|
||||
try:
|
||||
json_data = json.loads(parsed.data)
|
||||
build_config["body_dict"]["value"] = json_data
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Error decoding JSON data: {e}")
|
||||
else:
|
||||
build_config["body_dict"]["value"] = None
|
||||
except Exception as exc:
|
||||
logger.error(f"Error parsing curl: {exc}")
|
||||
raise ValueError(f"Error parsing curl: {exc}")
|
||||
|
|
@ -80,6 +106,11 @@ class APIRequestComponent(Component):
|
|||
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
||||
if field_name == "curl" and field_value:
|
||||
build_config = self.parse_curl(field_value, build_config)
|
||||
# Apply the parsed values to the component fields
|
||||
self.urls = build_config["urls"]["value"]
|
||||
self.method = build_config["method"]["value"]
|
||||
self.headers_dict = build_config["headers"]["value"]
|
||||
self.body_dict = build_config["body"]["value"]
|
||||
return build_config
|
||||
|
||||
async def make_request(
|
||||
|
|
@ -96,7 +127,7 @@ class APIRequestComponent(Component):
|
|||
raise ValueError(f"Unsupported method: {method}")
|
||||
|
||||
data = body if body else None
|
||||
payload = json.dumps(data)
|
||||
payload = json.dumps(data) if data else None
|
||||
try:
|
||||
response = await client.request(method, url, headers=headers, content=payload, timeout=timeout)
|
||||
try:
|
||||
|
|
@ -130,36 +161,38 @@ class APIRequestComponent(Component):
|
|||
},
|
||||
)
|
||||
|
||||
def add_query_params(self, url: str, params: dict) -> str:
|
||||
url_parts = list(urlparse(url))
|
||||
query = dict(parse_qsl(url_parts[4]))
|
||||
query.update(params)
|
||||
url_parts[4] = urlencode(query)
|
||||
return urlunparse(url_parts)
|
||||
|
||||
async def make_requests(self) -> List[Data]:
|
||||
method = self.method
|
||||
urls = [url.strip() for url in self.urls if url.strip()]
|
||||
curl = self.curl
|
||||
headers = self.headers or {}
|
||||
body = self.body or {}
|
||||
headers = self.headers if self.headers else (self.headers_dict or {})
|
||||
body = self.body if self.body else (self.body_dict or {})
|
||||
timeout = self.timeout
|
||||
query_params = self.query_params.data if self.query_params else {}
|
||||
|
||||
if curl:
|
||||
self._build_config = self.parse_curl(curl)
|
||||
self._build_config = self.parse_curl(curl, dotdict())
|
||||
|
||||
if isinstance(headers, Data):
|
||||
headers_dict = headers.data
|
||||
else:
|
||||
headers_dict = headers
|
||||
headers = headers.data
|
||||
|
||||
bodies = []
|
||||
if body:
|
||||
if not isinstance(body, list):
|
||||
bodies = [body]
|
||||
else:
|
||||
bodies = body
|
||||
bodies = [b.data if isinstance(b, Data) else b for b in bodies]
|
||||
if isinstance(body, Data):
|
||||
body = body.data
|
||||
|
||||
if len(urls) != len(bodies):
|
||||
bodies += [None] * (len(urls) - len(bodies))
|
||||
bodies = [body] * len(urls)
|
||||
|
||||
urls = [self.add_query_params(url, query_params) for url in urls]
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
results = await asyncio.gather(
|
||||
*[self.make_request(client, method, u, headers_dict, rec, timeout) for u, rec in zip(urls, bodies)]
|
||||
*[self.make_request(client, method, u, headers, rec, timeout) for u, rec in zip(urls, bodies)]
|
||||
)
|
||||
self.status = results
|
||||
return results
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue