Coverage for graphqler / utils / request_utils.py: 74%
57 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-20 10:09 -0400
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-20 10:09 -0400
1from urllib3.exceptions import InsecureRequestWarning
2from urllib3 import disable_warnings
3from typing import Callable
4from graphqler import config
6import time
7import requests
8import json
11# The last time a request was made so that we can wait between requests
12last_request_time = time.time()
13session = None
16def get_headers() -> dict:
17 """Get the headers for the request.
18 Authorization will be used from the AUTHORIZATION variable first, then from the CUSTOM_HEADERS variable.
20 Returns:
21 dict: The headers for the request
22 """
23 headers = {"Content-Type": "application/json"}
24 if config.CUSTOM_HEADERS:
25 headers.update(config.CUSTOM_HEADERS)
27 if config.AUTHORIZATION:
28 headers["Authorization"] = f"{config.AUTHORIZATION}"
30 return headers
33def get_proxies() -> dict:
34 """Get the proxies for the request
36 Returns:
37 dict: The proxies for the request
38 """
39 if config.PROXY and "http:" in config.PROXY:
40 return {"http": config.PROXY}
41 elif config.PROXY and "https:" in config.PROXY:
42 return {"https": config.PROXY}
43 elif config.PROXY:
44 return {"http": config.PROXY, "https": config.PROXY}
45 else:
46 return {}
49def send_graphql_request(url: str, payload: str | dict | list, next: Callable[[dict], dict] | None = None) -> tuple[dict, requests.Response]:
50 """Send GraphQL request to the specified endpoint
52 Args:
53 url (str): URL of the graphql server
54 payload (str | dict | list): The payload to send to the GraphQL API. If dict or string, must provide the query and variables keys
55 next (Callable[[dict], dict], optional): Callback function in case there is action to be done after. Defaults to None.
57 Returns:
58 tuple[dict, requests.Response]: Dictionary of the graphql response, and the request's response
59 """
60 global last_request_time
62 # Make the body (if it's a string, add the key, if it's dict or list, assume the creator of the request knows what they are doing
63 # (ie. added the query / variable keys themselves))
64 if isinstance(payload, str):
65 body = {"query": payload}
66 else:
67 body = payload
69 # If the last request was made recently, wait for a bit
70 time_since_last_request = time.time() - last_request_time
71 if time_since_last_request < config.TIME_BETWEEN_REQUESTS:
72 time.sleep(config.TIME_BETWEEN_REQUESTS - time_since_last_request)
74 # Make the request and set the last request time
75 session = get_or_create_session()
76 response = session.post(
77 url=url,
78 json=body,
79 timeout=config.REQUEST_TIMEOUT,
80 )
81 last_request_time = time.time()
83 if response.status_code != 200:
84 return parse_response(response.text), response
86 # if next:
87 # return next(json.loads(response.text))
89 return parse_response(response.text), response
92def parse_response(response_text: str) -> dict:
93 """Parse the response and try to jsonify it
95 Args:
96 response_text (str): The response text
98 Returns:
99 dict: A dictionary of the response
100 """
101 json_text = ""
102 try:
103 json_text = json.loads(response_text)
104 return json_text
105 except Exception:
106 return {"errors": [response_text]}
109def get_or_create_session() -> requests.Session:
110 """Gets an existing session or creates a new one
112 Returns:
113 requests.Session: The session
114 """
115 global session
117 if session and isinstance(session, requests.Session):
118 return session
119 else:
120 session = create_new_session()
121 return session
124def create_new_session() -> requests.Session:
125 """Create a new session
127 Returns:
128 requests.Session: The session
129 """
130 session = requests.Session()
131 session.headers.update(get_headers())
133 # Set proxy if available
134 if config.PROXY:
135 session.proxies.update(get_proxies())
136 disable_warnings(InsecureRequestWarning)
137 session.verify = False
138 return session