Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d2e617a
feat : expose response headers in DocsService
hyunw9 Apr 5, 2025
ed925b2
fix : restore removed comments
hyunw9 Apr 5, 2025
0c5f150
fix: Define Header type for better clarity
hyunw9 Apr 9, 2025
d788723
feat : define responseData
hyunw9 Apr 13, 2025
23fac82
feat : modify response
hyunw9 Apr 13, 2025
9b9921c
feat : modify responseData
hyunw9 Apr 13, 2025
718f68e
feat : remove unused method : extractHeaders()
hyunw9 Apr 14, 2025
9705ab2
feat : edit response Form
hyunw9 Apr 14, 2025
296645f
Merge pull request #2 from hyunw9/feat-define-ResponseData
hyunw9 Apr 14, 2025
08f344b
feat : Update unnecessary useEffect
hyunw9 Apr 16, 2025
56e3d2c
feat : Deduplicate render logic
hyunw9 Apr 16, 2025
46af150
faet : Revert header variable name
hyunw9 Apr 16, 2025
8306d0c
feat : Delete fallback parameter
hyunw9 Apr 16, 2025
62839b8
feat : Deduplicate header build logic
hyunw9 Apr 16, 2025
add4c40
Merge pull request #4 from hyunw9/feat/update-review
hyunw9 Apr 16, 2025
5e1fa52
feat : Declare list available header types
hyunw9 Apr 19, 2025
690f573
feat : Change headers type from Map to Array
hyunw9 Apr 19, 2025
61f864c
feat : Delete parsing logic
hyunw9 Apr 19, 2025
abdad9b
feat : Redesign header extracting logic
hyunw9 Apr 19, 2025
a9b8f6e
feat : Change method name
hyunw9 Apr 19, 2025
5836119
feat : Delete json parse logic
hyunw9 Apr 19, 2025
a9bab84
feat : Update header type
hyunw9 Apr 19, 2025
e0cef46
Merge pull request #6 from hyunw9/feat/update-review
hyunw9 Apr 19, 2025
aa14f38
feat : Expand ResponseData
hyunw9 Apr 29, 2025
a7dbee2
feat : Add Status, ExecutionTime, ResponseSize, TimeStamp
hyunw9 Apr 29, 2025
8f2f600
feat : Apply additional Component to DebugPage
hyunw9 Apr 29, 2025
5260cee
feat : Update Cache, Error handling logic
hyunw9 Apr 29, 2025
295debf
feat : Deduplicate preparing `ResponseData`
hyunw9 Apr 29, 2025
b4309dc
feat : Deduplicate responseData status bar logic
hyunw9 May 12, 2025
67bf1fd
feat : Update docs-client/src/lib/json-util.ts
hyunw9 May 13, 2025
7f8a887
feat : Delete static header set
hyunw9 May 13, 2025
d1ac966
Merge branch 'add-Response-Header' of https://github.com/hyunw9/armer…
hyunw9 May 13, 2025
52f2271
Merge branch 'main' into add-Response-Header
hyunw9 May 29, 2025
355f172
Merge branch 'main' into add-Response-Header
hyunw9 Jun 15, 2025
d0d668e
Merge branch 'main' into add-Response-Header
hyunw9 Jun 17, 2025
0f1501c
chore : Remove unused import pharase
hyunw9 Jun 17, 2025
25614a5
Merge branch 'add-Response-Header' of https://github.com/hyunw9/armer…
hyunw9 Jun 17, 2025
8763d92
fix : Adjust header info layout
hyunw9 Jun 22, 2025
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
244 changes: 205 additions & 39 deletions docs-client/src/containers/MethodPage/DebugPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import {
ServiceType,
} from '../../lib/specification';
import { TRANSPORTS } from '../../lib/transports';
import { SelectOption } from '../../lib/types';
import { ResponseData, SelectOption } from '../../lib/types';
import DebugInputs from './DebugInputs';

const useStyles = makeStyles((theme: Theme) =>
Expand Down Expand Up @@ -147,8 +147,8 @@ const DebugPage: React.FunctionComponent<Props> = ({
docServiceRoute,
}) => {
const [requestBody, setRequestBody] = useState('');
const [debugResponse, setDebugResponse] = useState('');
const [additionalQueries, setAdditionalQueries] = useState('');
const [responseData, setResponseData] = useState<ResponseData | null>(null);
const [additionalPath, setAdditionalPath] = useState('');
const [additionalHeaders, setAdditionalHeaders] = useState('');
const [stickyHeaders, toggleStickyHeaders] = useReducer(toggle, false);
Expand All @@ -159,13 +159,30 @@ const DebugPage: React.FunctionComponent<Props> = ({
false,
);

const [currentApiId, setCurrentApiId] = useState<string>(method.id);
const [responseCache, setResponseCache] = useState<
Record<string, ResponseData>
>({});

const classes = useStyles();

const transport = TRANSPORTS.getDebugTransport(method);
if (!transport) {
throw new Error("This method doesn't have a debug transport.");
}

useEffect(() => {
Comment thread
hyunw9 marked this conversation as resolved.
const apiId = method.id;
if (apiId !== currentApiId) {
setCurrentApiId(apiId);
if (responseCache[apiId]) {
setResponseData(responseCache[apiId]);
} else {
setResponseData(null);
}
}
}, [method, currentApiId, responseCache]);

useEffect(() => {
const urlParams = new URLSearchParams(location.search);

Expand Down Expand Up @@ -201,7 +218,7 @@ const DebugPage: React.FunctionComponent<Props> = ({
serviceType === ServiceType.HTTP ? urlParams.get('queries') ?? '' : '';

if (!keepDebugResponse) {
setDebugResponse('');
setResponseData(null);
toggleKeepDebugResponse(false);
}
setSnackbarOpen(false);
Expand Down Expand Up @@ -335,9 +352,16 @@ const DebugPage: React.FunctionComponent<Props> = ({
showSnackbar('The curl command has been copied to the clipboard.');
} catch (e) {
if (e instanceof Object) {
setDebugResponse(e.toString());
setResponseData({
body: e.toString?.() ?? '<unknown>',
headers: [],
status: undefined,
executionTime: 0,
size: 0,
timestamp: new Date().toLocaleString(),
});
} else {
setDebugResponse('<unknown>');
setResponseData(null);
}
}
}, [
Expand All @@ -355,15 +379,15 @@ const DebugPage: React.FunctionComponent<Props> = ({
]);

const onCopy = useCallback(() => {
const response = debugResponse;
const response = responseData?.body ?? '';
if (response.length > 0) {
copyTextToClipboard(response);
showSnackbar('The response has been copied to the clipboard.');
}
}, [debugResponse, showSnackbar]);
}, [responseData, showSnackbar]);

const onClear = useCallback(() => {
setDebugResponse('');
setResponseData(null);
}, []);

const executeRequest = useCallback(
Expand All @@ -390,24 +414,23 @@ const DebugPage: React.FunctionComponent<Props> = ({
const headersText = params.get('headers');
const headers = headersText ? JSON.parse(headersText) : {};

let executedDebugResponse;
try {
executedDebugResponse = await transport.send(
const debugResponseData = await transport.send(
method,
headers,
parseServerRootPath(docServiceRoute),
executedRequestBody,
executedEndpointPath,
queries,
);
setResponseData(debugResponseData);
setResponseCache((prev) => ({
...prev,
[currentApiId]: debugResponseData,
}));
} catch (e) {
if (e instanceof Object) {
executedDebugResponse = e.toString();
} else {
executedDebugResponse = '<unknown>';
}
setResponseData(null);
}
setDebugResponse(executedDebugResponse);
},
[
useRequestBody,
Expand All @@ -416,12 +439,11 @@ const DebugPage: React.FunctionComponent<Props> = ({
method,
transport,
docServiceRoute,
currentApiId,
],
);

const onSubmit = useCallback(async () => {
setDebugResponse('');

const queries = additionalQueries;
const headers = additionalHeaders;
const params = new URLSearchParams(location.search);
Expand Down Expand Up @@ -468,9 +490,16 @@ const DebugPage: React.FunctionComponent<Props> = ({
}
} catch (e) {
if (e instanceof Object) {
setDebugResponse(e.toString());
setResponseData({
body: e.toString?.() ?? '<unknown>',
headers: [],
status: undefined,
executionTime: 0,
size: 0,
timestamp: new Date().toLocaleString(),
});
} else {
setDebugResponse('<unknown>');
setResponseData(null);
}
return;
}
Expand Down Expand Up @@ -520,6 +549,18 @@ const DebugPage: React.FunctionComponent<Props> = ({
});
}, [serviceType, transport, method, examplePaths]);

const getStatusColor = (status?: number): string | undefined => {
if (typeof status !== 'number') return undefined;
return status >= 200 && status < 300 ? 'green' : 'red';
};

const statusColor = getStatusColor(responseData?.status);
const modalStatusColor = getStatusColor(responseData?.status);
const responseBody = responseData?.body;
const responseHeadersString =
Array.isArray(responseData?.headers) && responseData.headers.length > 0
? responseData.headers.join('\n')
: '';
return (
<>
<Section>
Expand Down Expand Up @@ -572,11 +613,11 @@ 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}
disabled={debugResponse.length === 0}
disabled={!responseData?.body}
>
<FileCopyIcon />
</IconButton>
Expand All @@ -588,21 +629,82 @@ const DebugPage: React.FunctionComponent<Props> = ({
<div>
<IconButton
onClick={onClear}
disabled={debugResponse.length === 0}
disabled={!responseData?.body}
>
<DeleteSweepIcon />
</IconButton>
</div>
</Tooltip>
</Grid>
<Grid
item
xs
style={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
}}
>
{responseData && (
<Typography
variant="body2"
style={{ whiteSpace: 'nowrap' }}
>
<span
style={{
marginLeft: 16,
color: statusColor,
}}
>
<strong>Status</strong>: {responseData.status ?? '–'}
</span>
<span style={{ marginLeft: 16 }}>
<strong>Execution Time</strong>:{' '}
{responseData.executionTime ?? '–'} ms
</span>
<span style={{ marginLeft: 16 }}>
<strong>Response Size</strong>:{' '}
{responseData.size ?? '–'} B
</span>
<span style={{ marginLeft: 16 }}>
<strong>Execution Timestamp</strong> :{' '}
{responseData.timestamp ?? '-'}
</span>
</Typography>
)}
</Grid>
</Grid>
<SyntaxHighlighter
language="json"
style={githubGist}
wrapLines={false}
>
{debugResponse}
</SyntaxHighlighter>
{responseBody && (
<>
{responseHeadersString && (
<>
<Typography
variant="subtitle1"
style={{ marginTop: '1rem' }}
>
Response Headers:
</Typography>
<SyntaxHighlighter
language="text"
style={githubGist}
wrapLines={false}
>
{responseHeadersString}
</SyntaxHighlighter>
</>
)}
<Typography variant="subtitle1" style={{ marginTop: '1rem' }}>
Response Body:
</Typography>
<SyntaxHighlighter
language="json"
style={githubGist}
wrapLines={false}
>
{responseBody}
</SyntaxHighlighter>
</>
)}
</Grid>
</Grid>
<Snackbar
Expand Down Expand Up @@ -664,7 +766,7 @@ const DebugPage: React.FunctionComponent<Props> = ({
<div>
<IconButton
onClick={onCopy}
disabled={debugResponse.length === 0}
disabled={!responseData?.body}
>
<FileCopyIcon />
</IconButton>
Expand All @@ -676,21 +778,85 @@ const DebugPage: React.FunctionComponent<Props> = ({
<div>
<IconButton
onClick={onClear}
disabled={debugResponse.length === 0}
disabled={!responseData?.body}
>
<DeleteSweepIcon />
</IconButton>
</div>
</Tooltip>
</Grid>
<Grid
Comment thread
hyunw9 marked this conversation as resolved.
Outdated
item
xs
style={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
}}
>
{responseData && (
<Typography
variant="body2"
style={{ whiteSpace: 'nowrap' }}
>
<span
style={{
marginLeft: 16,
color: modalStatusColor,
}}
>
<strong>Status</strong>: {responseData.status ?? '–'}
</span>
<span style={{ marginLeft: 16 }}>
<strong>Execution Time</strong>:{' '}
{responseData.executionTime ?? '–'} ms
</span>
<span style={{ marginLeft: 16 }}>
<strong>Response Size</strong>:{' '}
{responseData.size ?? '–'} B
</span>
<span style={{ marginLeft: 16 }}>
<strong>Execution Timestamp</strong> :{' '}
{responseData.timestamp ?? '-'}
</span>
</Typography>
)}
</Grid>
</Grid>
<SyntaxHighlighter
language="json"
style={githubGist}
wrapLines={false}
>
{debugResponse}
</SyntaxHighlighter>
{responseBody && (
<>
{responseHeadersString && (
<>
<Typography
variant="subtitle1"
style={{ marginTop: '1rem' }}
>
Response Headers:
</Typography>
<SyntaxHighlighter
language="text"
style={githubGist}
wrapLines={false}
>
{responseHeadersString}
</SyntaxHighlighter>
</>
)}
<Typography
variant="subtitle1"
style={{ marginTop: '1rem' }}
>
Response Body:
</Typography>
<SyntaxHighlighter
language="json"
style={githubGist}
wrapLines={false}
>
{responseBody}
</SyntaxHighlighter>
</>
)}
</Grid>
</Grid>
<Snackbar
Expand Down
Loading