/* ============================================================================ * Copyright (c) Palo Alto Networks * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * ========================================================================== */ // @ts-nocheck import React, { useState, useId } from "react"; import { useDoc } from "@docusaurus/plugin-content-docs/client"; import { translate } from "@docusaurus/Translate"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Accept from "@theme/ApiExplorer/Accept"; import Authorization from "@theme/ApiExplorer/Authorization"; import Body from "@theme/ApiExplorer/Body"; import buildPostmanRequest from "@theme/ApiExplorer/buildPostmanRequest"; import ContentType from "@theme/ApiExplorer/ContentType"; import ParamOptions from "@theme/ApiExplorer/ParamOptions"; import { setResponse, setCode, clearCode, setHeaders, clearHeaders, } from "@theme/ApiExplorer/Response/slice"; import Server from "@theme/ApiExplorer/Server"; import { useResolvedEncoding } from "@theme/ApiExplorer/EncodingSelection/useResolvedEncoding"; import { useTypedDispatch, useTypedSelector } from "@theme/ApiItem/hooks"; import { OPENAPI_REQUEST } from "@theme/translationIds"; import type { ParameterObject } from "docusaurus-plugin-openapi-docs/src/openapi/types"; import type { ApiItem } from "docusaurus-plugin-openapi-docs/src/types"; import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types"; import * as sdk from "postman-collection"; import { FormProvider, useForm } from "react-hook-form"; import makeRequest, { RequestError, RequestErrorType } from "./makeRequest"; function Request({ item }: { item: ApiItem }) { const postman = new sdk.Request(item.postman); const metadata = useDoc(); const { proxy: frontMatterProxy, hide_send_button: hideSendButton } = metadata.frontMatter; const { siteConfig } = useDocusaurusContext(); const themeConfig = siteConfig.themeConfig as ThemeConfig; const requestTimeout = themeConfig.api?.requestTimeout; const requestCredentials = themeConfig.api?.requestCredentials; // Frontmatter proxy (per-spec) takes precedence over theme config proxy (site-wide) const proxy = frontMatterProxy ?? themeConfig.api?.proxy; const pathParams = useTypedSelector((state: any) => state.params.path); const queryParams = useTypedSelector((state: any) => state.params.query); const cookieParams = useTypedSelector((state: any) => state.params.cookie); const contentType = useTypedSelector((state: any) => state.contentType.value); const headerParams = useTypedSelector((state: any) => state.params.header); const body = useTypedSelector((state: any) => state.body); const accept = useTypedSelector((state: any) => state.accept.value); const acceptOptions = useTypedDispatch((state: any) => state.accept.options); const authSelected = useTypedSelector((state: any) => state.auth.selected); const server = useTypedSelector((state: any) => state.server.value); const serverOptions = useTypedSelector((state: any) => state.server.options); const auth = useTypedSelector((state: any) => state.auth); const dispatch = useTypedDispatch(); const [expandAccept, setExpandAccept] = useState(true); const [expandAuth, setExpandAuth] = useState(true); const [expandBody, setExpandBody] = useState(true); const [expandParams, setExpandParams] = useState(true); const [expandServer, setExpandServer] = useState(true); const serverLabelId = useId(); const allParams = [ ...pathParams, ...queryParams, ...cookieParams, ...headerParams, ]; const encoding = useResolvedEncoding(item.requestBody); const postmanRequest = buildPostmanRequest(postman, { queryParams, pathParams, cookieParams, contentType, accept, headerParams, body, server, auth, encoding, }); const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const paramsObject = { path: [] as ParameterObject[], query: [] as ParameterObject[], header: [] as ParameterObject[], cookie: [] as ParameterObject[], }; item.parameters?.forEach( (param: { in: "path" | "query" | "header" | "cookie" }) => { const paramType = param.in; const paramsArray: ParameterObject[] = paramsObject[paramType]; paramsArray?.push(param as ParameterObject); } ); const methods = useForm({ shouldFocusError: false }); const handleEventStream = async (res) => { res.headers && dispatch(setHeaders(Object.fromEntries(res.headers))); dispatch(setCode(res.status)); const reader = res.body.getReader(); const decoder = new TextDecoder(); let result = ""; while (true) { const { done, value } = await reader.read(); if (done) break; result += decoder.decode(value, { stream: true }); dispatch(setResponse(result)); } }; const handleResponse = async (res) => { dispatch(setResponse(await res.text())); dispatch(setCode(res.status)); res.headers && dispatch(setHeaders(Object.fromEntries(res.headers))); }; const getErrorMessage = (errorType: RequestErrorType): string => { switch (errorType) { case "timeout": return translate({ id: OPENAPI_REQUEST.ERROR_TIMEOUT, message: "The request timed out waiting for the server to respond. Please try again. If the issue persists, try using a different client (e.g., curl) with a longer timeout.", }); case "network": return translate({ id: OPENAPI_REQUEST.ERROR_NETWORK, message: "Unable to reach the server. Please check your network connection and verify the server URL is correct. If the server is running, this may be a CORS issue.", }); case "cors": return translate({ id: OPENAPI_REQUEST.ERROR_CORS, message: "The request was blocked, possibly due to CORS restrictions. Ensure the server allows requests from this origin, or try using a proxy.", }); case "unknown": default: return translate({ id: OPENAPI_REQUEST.ERROR_UNKNOWN, message: "An unexpected error occurred while making the request. Please try again.", }); } }; const onSubmit = async (data) => { dispatch( setResponse( translate({ id: OPENAPI_REQUEST.FETCHING_MESSAGE, message: "Fetching...", }) ) ); try { await delay(1200); const res = await makeRequest( postmanRequest, proxy, body, requestTimeout, requestCredentials, encoding ); if (res.headers.get("content-type")?.includes("text/event-stream")) { await handleEventStream(res); } else { await handleResponse(res); } } catch (e) { console.log(e); let errorMessage: string; if (e instanceof RequestError) { errorMessage = getErrorMessage(e.type); } else { errorMessage = translate({ id: OPENAPI_REQUEST.CONNECTION_FAILED, message: "Connection failed", }); } dispatch(setResponse(errorMessage)); dispatch(clearCode()); dispatch(clearHeaders()); } }; const showServerOptions = serverOptions.length > 0; const showAcceptOptions = acceptOptions.length > 1; const showRequestBody = contentType !== undefined; const showRequestButton = (item.servers || proxy) && !hideSendButton; const showAuth = authSelected !== undefined; const showParams = allParams.length > 0; const requestBodyRequired = item.requestBody?.required; if ( !showAcceptOptions && !showAuth && !showParams && !showRequestBody && !showServerOptions && !showRequestButton ) { return null; } const expandAllDetails = () => { setExpandAccept(true); setExpandAuth(true); setExpandBody(true); setExpandParams(true); setExpandServer(true); }; const collapseAllDetails = () => { setExpandAccept(false); setExpandAuth(false); setExpandBody(false); setExpandParams(false); setExpandServer(false); }; const allDetailsExpanded = expandParams && expandBody && expandServer && expandAuth && expandAccept; return (
{translate({ id: OPENAPI_REQUEST.REQUEST_TITLE, message: "Request", })} {allDetailsExpanded ? ( ) : ( )}
{showServerOptions && item.method !== "event" && (
{ e.preventDefault(); setExpandServer(!expandServer); }} > {translate({ id: OPENAPI_REQUEST.BASE_URL_TITLE, message: "Base URL", })}
)} {showAuth && (
{ e.preventDefault(); setExpandAuth(!expandAuth); }} > {translate({ id: OPENAPI_REQUEST.AUTH_TITLE, message: "Auth" })}
)} {showParams && (
{ e.preventDefault(); setExpandParams(!expandParams); }} > {translate({ id: OPENAPI_REQUEST.PARAMETERS_TITLE, message: "Parameters", })}
)} {showRequestBody && (
{ e.preventDefault(); setExpandBody(!expandBody); }} > {translate({ id: OPENAPI_REQUEST.BODY_TITLE, message: "Body" })} {requestBodyRequired && (   {translate({ id: OPENAPI_REQUEST.REQUIRED_LABEL, message: "required", })} )} <>
)} {showAcceptOptions && (
{ e.preventDefault(); setExpandAccept(!expandAccept); }} > {translate({ id: OPENAPI_REQUEST.ACCEPT_TITLE, message: "Accept", })}
)} {showRequestButton && item.method !== "event" && ( )}
); } export default Request;