Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/api_v2/postman_collection/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ class CollectionKey:
EXECUTE_PIPELINE_API_KEY = "Process pipeline"
STATUS_API_KEY = "Execution status"
STATUS_EXEC_ID_DEFAULT = "REPLACE_WITH_EXECUTION_ID"
EXEC_ID_VARIABLE_NAME = "execution_id"
STATUS_EXEC_ID_VARIABLE = "{{execution_id}}"
AUTH_QUERY_PARAM_DEFAULT = "REPLACE_WITH_API_KEY"
72 changes: 69 additions & 3 deletions backend/api_v2/postman_collection/dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ class HeaderItem:
value: str


@dataclass
class ScriptItem:
exec: list[str]
type: str = "text/javascript"


@dataclass
class EventItem:
listen: str
script: ScriptItem


@dataclass
class VariableItem:
key: str
value: str


@dataclass
class FormDataItem:
key: str
Expand Down Expand Up @@ -55,6 +73,7 @@ class RequestItem:
class PostmanItem:
name: str
request: RequestItem
event: list[EventItem] | None = None


@dataclass
Expand All @@ -69,6 +88,12 @@ class APIBase(ABC):
def get_form_data_items(self) -> list[FormDataItem]:
pass

def get_collection_variables(self) -> list["VariableItem"]:
"""Collection-level variables; only needed when a request
references them.
"""
return []

@abstractmethod
def get_api_endpoint(self) -> str:
pass
Expand Down Expand Up @@ -137,20 +162,52 @@ def get_api_endpoint(self) -> str:
def _get_status_api_request(self) -> RequestItem:
header_list = [HeaderItem(key="Authorization", value=f"Bearer {self.api_key}")]
status_query_param = {
"execution_id": CollectionKey.STATUS_EXEC_ID_DEFAULT,
"execution_id": CollectionKey.STATUS_EXEC_ID_VARIABLE,
ApiExecution.INCLUDE_METADATA: "False",
ApiExecution.INCLUDE_METRICS: "False",
}
status_query_str = urlencode(status_query_param)
# Keep {{...}} unescaped so Postman resolves the collection variable
status_query_str = urlencode(status_query_param, safe="{}")
abs_api_endpoint = urljoin(settings.WEB_APP_ORIGIN_URL, self.api_endpoint)
status_url = urljoin(abs_api_endpoint, "?" + status_query_str)
return RequestItem(method=HTTPMethod.GET, header=header_list, url=status_url)

def get_collection_variables(self) -> list[VariableItem]:
return [
VariableItem(
key=CollectionKey.EXEC_ID_VARIABLE_NAME,
value=CollectionKey.STATUS_EXEC_ID_DEFAULT,
)
]

def _get_execute_capture_event(self) -> EventItem:
"""Post-response script that stores the execution_id from the execute
response into a collection variable, so the status request can use it
without manual copy-pasting.
"""
return EventItem(
listen="test",
script=ScriptItem(
exec=[
"let response = null;",
"try {",
" response = pm.response.json();",
"} catch (error) {",
" // Non-JSON response (e.g. gateway error); nothing to capture",
"}",
"if (response && response.message && response.message.execution_id) {", # noqa: E501
f' pm.collectionVariables.set("{CollectionKey.EXEC_ID_VARIABLE_NAME}", response.message.execution_id);', # noqa: E501
Comment thread
greptile-apps[bot] marked this conversation as resolved.
"}",
]
),
Comment thread
greptile-apps[bot] marked this conversation as resolved.
)

def get_postman_items(self) -> list[PostmanItem]:
postman_item_list = [
PostmanItem(
name=CollectionKey.EXECUTE_API_KEY,
request=self.get_create_api_request(),
event=[self._get_execute_capture_event()],
),
PostmanItem(
name=CollectionKey.STATUS_API_KEY,
Expand Down Expand Up @@ -192,6 +249,7 @@ def get_postman_items(self) -> list[PostmanItem]:
class PostmanCollection:
info: PostmanInfo
item: list[PostmanItem] = field(default_factory=list)
variable: list[VariableItem] = field(default_factory=list)

@classmethod
def create(
Expand Down Expand Up @@ -228,7 +286,11 @@ def create(
)
postman_info: PostmanInfo = data_object.get_postman_info()
postman_item_list = data_object.get_postman_items()
return cls(info=postman_info, item=postman_item_list)
return cls(
info=postman_info,
item=postman_item_list,
variable=data_object.get_collection_variables(),
)

def to_dict(self) -> dict[str, Any]:
"""Convert PostmanCollection instance to a dict.
Expand All @@ -237,4 +299,8 @@ def to_dict(self) -> dict[str, Any]:
dict[str, Any]: PostmanCollection as a dict
"""
collection_dict = asdict(self)
# Drop null event blocks; Postman expects "event" to be a list
for item in collection_dict.get("item", []):
if item.get("event") is None:
item.pop("event", None)
return collection_dict
1 change: 1 addition & 0 deletions backend/api_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ class DeploymentResponseSerializer(Serializer):


class APIExecutionResponseSerializer(Serializer):
execution_id = CharField()
execution_status = CharField()
status_api = CharField()
error = CharField()
Expand Down
Loading