-
Notifications
You must be signed in to change notification settings - Fork 1k
Expose response headers in DocsService
#6191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
d2e617a
ed925b2
0c5f150
d788723
23fac82
9b9921c
718f68e
9705ab2
296645f
08f344b
56e3d2c
46af150
8306d0c
62839b8
add4c40
5e1fa52
690f573
61f864c
abdad9b
a9b8f6e
5836119
a9bab84
e0cef46
aa14f38
a7dbee2
8f2f600
5260cee
295debf
b4309dc
67bf1fd
7f8a887
d1ac966
52f2271
355f172
d0d668e
0f1501c
25614a5
8763d92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -149,6 +149,9 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| const [requestBody, setRequestBody] = useState(''); | ||||||||||||||||||||||||
| const [debugResponse, setDebugResponse] = useState(''); | ||||||||||||||||||||||||
| const [additionalQueries, setAdditionalQueries] = useState(''); | ||||||||||||||||||||||||
| const [debugResponseHeaders, setDebugResponseHeaders] = useState< | ||||||||||||||||||||||||
| [string, string[]][] | ||||||||||||||||||||||||
| >([]); | ||||||||||||||||||||||||
| const [additionalPath, setAdditionalPath] = useState(''); | ||||||||||||||||||||||||
| const [additionalHeaders, setAdditionalHeaders] = useState(''); | ||||||||||||||||||||||||
| const [stickyHeaders, toggleStickyHeaders] = useReducer(toggle, false); | ||||||||||||||||||||||||
|
|
@@ -159,13 +162,36 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| false, | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const [currentApiId, setCurrentApiId] = useState<string>( | ||||||||||||||||||||||||
| method.id || method.name, | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| const [responseCache, setResponseCache] = useState< | ||||||||||||||||||||||||
| Record<string, { body: string; headers: Map<string, string[]> }> | ||||||||||||||||||||||||
| >({}); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const classes = useStyles(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const transport = TRANSPORTS.getDebugTransport(method); | ||||||||||||||||||||||||
| if (!transport) { | ||||||||||||||||||||||||
| throw new Error("This method doesn't have a debug transport."); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||
| const apiId = method.id || method.name; | ||||||||||||||||||||||||
| if (apiId !== currentApiId) { | ||||||||||||||||||||||||
| setCurrentApiId(apiId); | ||||||||||||||||||||||||
| if (responseCache[apiId]) { | ||||||||||||||||||||||||
| setDebugResponse(responseCache[apiId].body); | ||||||||||||||||||||||||
| setDebugResponseHeaders( | ||||||||||||||||||||||||
| Array.from(responseCache[apiId].headers.entries()), | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||
| setDebugResponse(''); | ||||||||||||||||||||||||
| setDebugResponseHeaders([]); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| }, [method, currentApiId, responseCache]); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||
| const urlParams = new URLSearchParams(location.search); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -202,6 +228,7 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if (!keepDebugResponse) { | ||||||||||||||||||||||||
| setDebugResponse(''); | ||||||||||||||||||||||||
| setDebugResponseHeaders([]); | ||||||||||||||||||||||||
| toggleKeepDebugResponse(false); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| setSnackbarOpen(false); | ||||||||||||||||||||||||
|
|
@@ -307,23 +334,23 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| escapeSingleQuote(requestBody), | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const headers = new Headers(); | ||||||||||||||||||||||||
| headers.set('content-type', transport.getDebugMimeType()); | ||||||||||||||||||||||||
| const headersObj = new Headers(); | ||||||||||||||||||||||||
|
hyunw9 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||
| headersObj.set('content-type', transport.getDebugMimeType()); | ||||||||||||||||||||||||
| if (process.env.WEBPACK_DEV === 'true') { | ||||||||||||||||||||||||
| headers.set(docServiceDebug, 'true'); | ||||||||||||||||||||||||
| headersObj.set(docServiceDebug, 'true'); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| if (serviceType === ServiceType.GRAPHQL) { | ||||||||||||||||||||||||
| headers.set('accept', 'application/json'); | ||||||||||||||||||||||||
| headersObj.set('accept', 'application/json'); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| if (additionalHeaders) { | ||||||||||||||||||||||||
| const entries = Object.entries(JSON.parse(additionalHeaders)); | ||||||||||||||||||||||||
| entries.forEach(([key, value]) => { | ||||||||||||||||||||||||
| headers.set(key, String(value)); | ||||||||||||||||||||||||
| headersObj.set(key, String(value)); | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const headerOptions: string[] = []; | ||||||||||||||||||||||||
| headers.forEach((value, key) => { | ||||||||||||||||||||||||
| headersObj.forEach((value, key) => { | ||||||||||||||||||||||||
| headerOptions.push(`-H '${key}: ${value}'`); | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -364,6 +391,7 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const onClear = useCallback(() => { | ||||||||||||||||||||||||
| setDebugResponse(''); | ||||||||||||||||||||||||
| setDebugResponseHeaders([]); | ||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const executeRequest = useCallback( | ||||||||||||||||||||||||
|
|
@@ -390,24 +418,29 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| const headersText = params.get('headers'); | ||||||||||||||||||||||||
| const headers = headersText ? JSON.parse(headersText) : {}; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| let executedDebugResponse; | ||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||
| executedDebugResponse = await transport.send( | ||||||||||||||||||||||||
| const { body, headers: responseHeaders } = await transport.send( | ||||||||||||||||||||||||
| method, | ||||||||||||||||||||||||
| headers, | ||||||||||||||||||||||||
| parseServerRootPath(docServiceRoute), | ||||||||||||||||||||||||
| executedRequestBody, | ||||||||||||||||||||||||
| executedEndpointPath, | ||||||||||||||||||||||||
| queries, | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| setDebugResponse(body); | ||||||||||||||||||||||||
| setDebugResponseHeaders(Array.from(responseHeaders.entries())); | ||||||||||||||||||||||||
| setResponseCache((prev) => ({ | ||||||||||||||||||||||||
| ...prev, | ||||||||||||||||||||||||
| [currentApiId]: { | ||||||||||||||||||||||||
| body, | ||||||||||||||||||||||||
| headers: responseHeaders, | ||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be more useful if we could record the execution time and display it in the debug console. Some may want to know whether the response is outdated or up-to-date.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think showing the execution time on the debug page could improve the user experience! If we decide to display it, where would be the best place to show the execution time?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It sounds good to me. Could you prototype your idea? I’d like to see how it looks and feels.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In modern API Testing tools, they display Response status, execution time, and ResponseData size. So i was thinking what if we displayed those three information on the right section of response page Util. Examples :
Prototype :
More specifically, I thought of two possible versions :
--- Updated ---
Executed time should be rounded tho :)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The prototype looks great! Since the results are cached, would you mind also adding the timestamp of when the request was executed?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! It’s necessary when we’re caching ResponseData.
Here are some examples pictures:
|
||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||
| if (e instanceof Object) { | ||||||||||||||||||||||||
| executedDebugResponse = e.toString(); | ||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||
| executedDebugResponse = '<unknown>'; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| const message = e instanceof Object ? e.toString() : '<unknown>'; | ||||||||||||||||||||||||
| setDebugResponse(message); | ||||||||||||||||||||||||
| setDebugResponseHeaders([]); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| setDebugResponse(executedDebugResponse); | ||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||
| useRequestBody, | ||||||||||||||||||||||||
|
|
@@ -416,6 +449,7 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| method, | ||||||||||||||||||||||||
| transport, | ||||||||||||||||||||||||
| docServiceRoute, | ||||||||||||||||||||||||
| currentApiId, | ||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -505,6 +539,22 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| transport, | ||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||
| const newApiId = method.id || method.name; | ||||||||||||||||||||||||
|
hyunw9 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||
| if (newApiId !== currentApiId) { | ||||||||||||||||||||||||
| setCurrentApiId(newApiId); | ||||||||||||||||||||||||
| if (responseCache[newApiId]) { | ||||||||||||||||||||||||
| setDebugResponse(responseCache[newApiId].body); | ||||||||||||||||||||||||
| setDebugResponseHeaders( | ||||||||||||||||||||||||
| Array.from(responseCache[newApiId].headers.entries()), | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||
| setDebugResponse(''); | ||||||||||||||||||||||||
| setDebugResponseHeaders([]); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| }, [method, currentApiId, responseCache]); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const supportedExamplePaths = useMemo(() => { | ||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||
| serviceType === ServiceType.HTTP || | ||||||||||||||||||||||||
|
|
@@ -572,7 +622,7 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| <Grid item xs={12} sm={6}> | ||||||||||||||||||||||||
| <Grid container spacing={1}> | ||||||||||||||||||||||||
| <Grid item xs="auto"> | ||||||||||||||||||||||||
| <Tooltip title="Copy response"> | ||||||||||||||||||||||||
| <Tooltip title="Copy response body"> | ||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||
| <IconButton | ||||||||||||||||||||||||
| onClick={onCopy} | ||||||||||||||||||||||||
|
|
@@ -596,13 +646,45 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||
| </Grid> | ||||||||||||||||||||||||
| </Grid> | ||||||||||||||||||||||||
| <SyntaxHighlighter | ||||||||||||||||||||||||
| language="json" | ||||||||||||||||||||||||
| style={githubGist} | ||||||||||||||||||||||||
| wrapLines={false} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| {debugResponse} | ||||||||||||||||||||||||
| </SyntaxHighlighter> | ||||||||||||||||||||||||
| {debugResponse && ( | ||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||
| {Object.keys(debugResponseHeaders).length > 0 && ( | ||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||
| <Typography | ||||||||||||||||||||||||
| variant="subtitle1" | ||||||||||||||||||||||||
| style={{ marginTop: '1rem' }} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| Response Headers: | ||||||||||||||||||||||||
| </Typography> | ||||||||||||||||||||||||
| <SyntaxHighlighter | ||||||||||||||||||||||||
| language="json" | ||||||||||||||||||||||||
| style={githubGist} | ||||||||||||||||||||||||
| wrapLines={false} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| {JSON.stringify( | ||||||||||||||||||||||||
| Object.fromEntries( | ||||||||||||||||||||||||
| Array.from(debugResponseHeaders).map( | ||||||||||||||||||||||||
| ([key, values]) => [key, values.join(', ')], | ||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||
| null, | ||||||||||||||||||||||||
| 2, | ||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||
| </SyntaxHighlighter> | ||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||
|
hyunw9 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||
| <Typography variant="subtitle1" style={{ marginTop: '1rem' }}> | ||||||||||||||||||||||||
| Response Body: | ||||||||||||||||||||||||
| </Typography> | ||||||||||||||||||||||||
| <SyntaxHighlighter | ||||||||||||||||||||||||
| language="json" | ||||||||||||||||||||||||
| style={githubGist} | ||||||||||||||||||||||||
| wrapLines={false} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| {debugResponse} | ||||||||||||||||||||||||
| </SyntaxHighlighter> | ||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||
| </Grid> | ||||||||||||||||||||||||
| </Grid> | ||||||||||||||||||||||||
| <Snackbar | ||||||||||||||||||||||||
|
|
@@ -684,6 +766,34 @@ const DebugPage: React.FunctionComponent<Props> = ({ | |||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||
| </Grid> | ||||||||||||||||||||||||
| </Grid> | ||||||||||||||||||||||||
| {Object.keys(debugResponseHeaders).length > 0 && ( | ||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||
| <Typography | ||||||||||||||||||||||||
| variant="subtitle1" | ||||||||||||||||||||||||
| style={{ marginTop: '1rem' }} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| Response Headers: | ||||||||||||||||||||||||
| </Typography> | ||||||||||||||||||||||||
| <SyntaxHighlighter | ||||||||||||||||||||||||
| language="json" | ||||||||||||||||||||||||
| style={githubGist} | ||||||||||||||||||||||||
| wrapLines={false} | ||||||||||||||||||||||||
| > | ||||||||||||||||||||||||
| {JSON.stringify( | ||||||||||||||||||||||||
| Object.fromEntries( | ||||||||||||||||||||||||
| Array.from(debugResponseHeaders).map( | ||||||||||||||||||||||||
| ([key, values]) => [key, values.join(', ')], | ||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||
| null, | ||||||||||||||||||||||||
| 2, | ||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||
| </SyntaxHighlighter> | ||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||
| <Typography variant="subtitle1" style={{ marginTop: '1rem' }}> | ||||||||||||||||||||||||
| Response Body: | ||||||||||||||||||||||||
| </Typography> | ||||||||||||||||||||||||
| <SyntaxHighlighter | ||||||||||||||||||||||||
| language="json" | ||||||||||||||||||||||||
| style={githubGist} | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||











Uh oh!
There was an error while loading. Please reload this page.