Skip to content

Commit c67b4a6

Browse files
committed
Fix a regression where JSON responses are not formatted in DocService
Motivation: JSON pretty-printing logic was unintentionally removed while working on line#6191 https://github.com/line/armeria/pull/6191/files#diff-f12e66c572a486106958b3f165d995f093e16ffb76db3028fd836595eace6c67L64-L67 Modifications: - Prettify JSON responses before rendering them on the debug console. - Remove duplicate duration measurement logic. - Slightly adjust the font size and layout spacing in `ResponseStatusBar` for readability. Result: Fix a regression where JSON responses are not formatted in DocService
1 parent b873335 commit c67b4a6

8 files changed

Lines changed: 66 additions & 112 deletions

File tree

docs-client/src/containers/MethodPage/DebugPage.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,33 +147,31 @@ const ResponseStatusBar: React.FC<{
147147
style={{
148148
display: 'flex',
149149
flexWrap: 'wrap',
150-
justifyContent: 'flex-end',
150+
justifyContent: 'flex-start',
151151
alignItems: 'center',
152152
gap: '4px 16px',
153153
overflow: 'hidden',
154154
wordBreak: 'break-word',
155155
}}
156156
>
157157
<Typography
158-
variant="body2"
158+
variant="subtitle2"
159159
style={{
160160
display: 'flex',
161161
flexWrap: 'wrap',
162162
}}
163163
>
164-
<span style={{ marginLeft: 16, color }}>
164+
<span style={{ marginRight: 16, color }}>
165165
<strong>Status</strong>: {responseMetaData.status ?? '–'}
166166
</span>
167-
<span style={{ marginLeft: 16 }}>
168-
<strong>Execution Time</strong>:{' '}
169-
{responseMetaData.executionTime ?? '–'} ms
167+
<span style={{ marginRight: 16 }}>
168+
<strong>Duration</strong>: {responseMetaData.executionTime ?? '–'} ms
170169
</span>
171-
<span style={{ marginLeft: 16 }}>
172-
<strong>Response Size</strong>: {responseMetaData.size ?? '–'} B
170+
<span style={{ marginRight: 16 }}>
171+
<strong>Size</strong>: {responseMetaData.size ?? '–'} B
173172
</span>
174-
<span style={{ marginLeft: 16 }}>
175-
<strong>Execution Timestamp</strong> :{' '}
176-
{responseMetaData.timestamp ?? '-'}
173+
<span>
174+
<strong>Timestamp</strong> : {responseMetaData.timestamp ?? '-'}
177175
</span>
178176
</Typography>
179177
</Grid>
@@ -688,8 +686,8 @@ const DebugPage: React.FunctionComponent<Props> = ({
688686
{responseHeadersString && (
689687
<>
690688
<Typography
691-
variant="subtitle1"
692-
style={{ marginTop: '1rem' }}
689+
variant="subtitle2"
690+
style={{ marginTop: '1rem', fontWeight: 'bold' }}
693691
>
694692
Response Headers:
695693
</Typography>
@@ -702,7 +700,10 @@ const DebugPage: React.FunctionComponent<Props> = ({
702700
</SyntaxHighlighter>
703701
</>
704702
)}
705-
<Typography variant="subtitle1" style={{ marginTop: '1rem' }}>
703+
<Typography
704+
variant="subtitle2"
705+
style={{ marginTop: '1rem', fontWeight: 'bold' }}
706+
>
706707
Response Body:
707708
</Typography>
708709
<SyntaxHighlighter

docs-client/src/lib/json-util.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,3 @@ export function isValidJsonMimeType(applicationType: string | null) {
134134
}
135135
return applicationType.indexOf('json') >= 0;
136136
}
137-
138-
export function extractHeaderLines(headers: Headers): string[] {
139-
const headerLines: string[] = [];
140-
headers.forEach((value, name) => {
141-
headerLines.push(`${name}: ${value}`);
142-
});
143-
return headerLines;
144-
}

docs-client/src/lib/transports/annotated-http.ts

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,8 @@
1515
*/
1616
import { Endpoint, Method } from '../specification';
1717

18-
import Transport from './transport';
19-
import {
20-
extractHeaderLines,
21-
isValidJsonMimeType,
22-
validateJsonObject,
23-
} from '../json-util';
24-
import { ResponseData } from '../types';
18+
import { Transport } from './transport';
19+
import { isValidJsonMimeType, validateJsonObject } from '../json-util';
2520

2621
export const ANNOTATED_HTTP_MIME_TYPE = 'application/json; charset=utf-8';
2722

@@ -88,13 +83,12 @@ export default class AnnotatedHttpTransport extends Transport {
8883

8984
protected async doSend(
9085
method: Method,
91-
headers: { [name: string]: string },
86+
headers: { [p: string]: string },
9287
pathPrefix: string,
9388
bodyJson?: string,
9489
endpointPath?: string,
9590
queries?: string,
96-
): Promise<ResponseData> {
97-
const start = performance.now();
91+
): Promise<Response> {
9892
const endpoint = this.getDebugMimeTypeEndpoint(method);
9993

10094
const hdrs = new Headers();
@@ -122,23 +116,10 @@ export default class AnnotatedHttpTransport extends Transport {
122116
}
123117
newPath = pathPrefix + newPath;
124118

125-
const response = await fetch(encodeURI(newPath), {
119+
return fetch(encodeURI(newPath), {
126120
headers: hdrs,
127121
method: method.httpMethod,
128122
body: bodyJson,
129123
});
130-
131-
const responseHeaders = extractHeaderLines(response.headers);
132-
const responseText = await response.text();
133-
const duration = Math.round(performance.now() - start);
134-
const timestamp = new Date().toLocaleString();
135-
return {
136-
body: responseText,
137-
headers: responseHeaders,
138-
status: response.status,
139-
executionTime: duration,
140-
size: responseText.length,
141-
timestamp,
142-
};
143124
}
144125
}

docs-client/src/lib/transports/grahpql-http.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414
* under the License.
1515
*/
1616

17-
import Transport from './transport';
17+
import { Transport } from './transport';
1818
import { Method } from '../specification';
19-
import { extractHeaderLines, validateJsonObject } from '../json-util';
20-
import { ResponseData } from '../types';
19+
import { validateJsonObject } from '../json-util';
2120

2221
export const GRAPHQL_HTTP_MIME_TYPE = 'application/graphql+json';
2322

@@ -32,13 +31,12 @@ export default class GraphqlHttpTransport extends Transport {
3231

3332
protected async doSend(
3433
method: Method,
35-
headers: { [name: string]: string },
34+
headers: { [p: string]: string },
3635
pathPrefix: string,
3736
bodyJson?: string,
3837
endpointPath?: string,
3938
queries?: string,
40-
): Promise<ResponseData> {
41-
const start = performance.now();
39+
): Promise<Response> {
4240
const endpoint = this.getDebugMimeTypeEndpoint(method);
4341

4442
const hdrs = new Headers();
@@ -61,23 +59,10 @@ export default class GraphqlHttpTransport extends Transport {
6159
}
6260
newPath = pathPrefix + newPath;
6361

64-
const response = await fetch(encodeURI(newPath), {
62+
return fetch(encodeURI(newPath), {
6563
headers: hdrs,
6664
method: method.httpMethod,
6765
body: bodyJson,
6866
});
69-
70-
const responseHeaders = extractHeaderLines(response.headers);
71-
const responseText = await response.text();
72-
const duration = Math.round(performance.now() - start);
73-
const timestamp = new Date().toLocaleString();
74-
return {
75-
body: responseText,
76-
headers: responseHeaders,
77-
status: response.status,
78-
executionTime: duration,
79-
size: responseText.length,
80-
timestamp,
81-
};
8267
}
8368
}

docs-client/src/lib/transports/grpc-unframed.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515
*/
1616
import { Method } from '../specification';
1717

18-
import Transport from './transport';
19-
import { extractHeaderLines, validateJsonObject } from '../json-util';
20-
import { ResponseData } from '../types';
18+
import { Transport } from './transport';
19+
import { validateJsonObject } from '../json-util';
2120

2221
export const GRPC_UNFRAMED_MIME_TYPE =
2322
'application/json; charset=utf-8; protocol=gRPC';
@@ -37,11 +36,10 @@ export default class GrpcUnframedTransport extends Transport {
3736
pathPrefix: string,
3837
bodyJson?: string,
3938
endpointPath?: string,
40-
): Promise<ResponseData> {
39+
): Promise<Response> {
4140
if (!bodyJson) {
4241
throw new Error('A gRPC request must have body.');
4342
}
44-
const start = performance.now();
4543
const endpoint = this.getDebugMimeTypeEndpoint(method, endpointPath);
4644

4745
const hdrs = new Headers();
@@ -58,23 +56,10 @@ export default class GrpcUnframedTransport extends Transport {
5856
}
5957

6058
const newPath = pathPrefix + (endpointPath ?? endpoint.pathMapping);
61-
const response = await fetch(newPath, {
59+
return fetch(newPath, {
6260
headers: hdrs,
6361
method: 'POST',
6462
body: bodyJson,
6563
});
66-
67-
const responseHeaders = extractHeaderLines(response.headers);
68-
const responseText = await response.text();
69-
const duration = Math.round(performance.now() - start);
70-
const timestamp = new Date().toLocaleString();
71-
return {
72-
body: responseText,
73-
headers: responseHeaders,
74-
status: response.status,
75-
executionTime: duration,
76-
size: responseText.length,
77-
timestamp,
78-
};
7964
}
8065
}

docs-client/src/lib/transports/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { Method } from '../specification';
1919
import AnnotatedHttpTransport from './annotated-http';
2020
import GrpcUnframedTransport from './grpc-unframed';
2121
import ThriftTransport from './thrift';
22-
import Transport from './transport';
22+
import { Transport } from './transport';
2323
import GraphqlHttpTransport from './grahpql-http';
2424

2525
const grpcUnframedTransport = new GrpcUnframedTransport();

docs-client/src/lib/transports/thrift.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616

1717
import { Endpoint, Method } from '../specification';
1818

19-
import Transport from './transport';
20-
import { extractHeaderLines, validateJsonObject } from '../json-util';
21-
import { ResponseData } from '../types';
19+
import { Transport } from './transport';
20+
import { validateJsonObject } from '../json-util';
2221

2322
export const TTEXT_MIME_TYPE = 'application/x-thrift; protocol=TTEXT';
2423

@@ -48,11 +47,10 @@ export default class ThriftTransport extends Transport {
4847
pathPrefix: string,
4948
bodyJson?: string,
5049
endpointPath?: string,
51-
): Promise<ResponseData> {
50+
): Promise<Response> {
5251
if (!bodyJson) {
5352
throw new Error('A Thrift request must have body.');
5453
}
55-
const start = performance.now();
5654
const endpoint = this.getDebugMimeTypeEndpoint(method, endpointPath);
5755

5856
const thriftMethod = ThriftTransport.thriftMethod(endpoint, method);
@@ -68,23 +66,10 @@ export default class ThriftTransport extends Transport {
6866

6967
const newPath = pathPrefix + (endpointPath ?? endpoint.pathMapping);
7068

71-
const response = await fetch(newPath, {
69+
return fetch(newPath, {
7270
headers: hdrs,
7371
method: 'POST',
7472
body: `{"method": "${thriftMethod}", "type": "CALL", "args": ${bodyJson}}`,
7573
});
76-
77-
const responseHeaders = extractHeaderLines(response.headers);
78-
const responseText = await response.text();
79-
const duration = Math.round(performance.now() - start);
80-
const timestamp = new Date().toLocaleString();
81-
return {
82-
body: responseText,
83-
headers: responseHeaders,
84-
status: response.status,
85-
executionTime: duration,
86-
size: responseText.length,
87-
timestamp,
88-
};
8974
}
9075
}

docs-client/src/lib/transports/transport.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,25 @@
1313
* License for the specific language governing permissions and limitations
1414
* under the License.
1515
*/
16+
import JSONbig from 'json-bigint';
17+
import { jsonPrettify } from '../json-util';
1618
import { docServiceDebug, providers } from '../header-provider';
1719
import { Endpoint, Method } from '../specification';
1820
import { ResponseData } from '../types';
1921

20-
export default abstract class Transport {
22+
export abstract class Transport {
2123
public abstract supportsMimeType(mimeType: string): boolean;
2224

2325
public abstract getDebugMimeType(): string;
2426

27+
private toHeaderLines(headers: Headers): string[] {
28+
const headerLines: string[] = [];
29+
headers.forEach((value, name) => {
30+
headerLines.push(`${name}: ${value}`);
31+
});
32+
return headerLines;
33+
}
34+
2535
public async send(
2636
method: Method,
2737
headers: { [name: string]: string },
@@ -59,13 +69,28 @@ export default abstract class Transport {
5969
endpointPath,
6070
queries,
6171
);
62-
const responseHeaders = httpResponse.headers;
63-
const responseText = httpResponse.body;
72+
73+
const responseHeaders = this.toHeaderLines(httpResponse.headers);
74+
const responseText = await httpResponse.text();
75+
const applicationType = httpResponse.headers.get('content-type') || '';
76+
let responseBody: string = responseText;
77+
if (applicationType.indexOf('json') >= 0) {
78+
try {
79+
const json = JSONbig.parse(responseText);
80+
const prettified = jsonPrettify(JSONbig.stringify(json));
81+
if (prettified.length > 0) {
82+
responseBody = prettified;
83+
}
84+
} catch (ignored) {
85+
/* empty */
86+
}
87+
}
6488
const duration = Math.round(performance.now() - start);
6589
const timestamp = new Date().toLocaleString();
90+
6691
if (responseText.length > 0) {
6792
return {
68-
body: responseText,
93+
body: responseBody,
6994
headers: responseHeaders,
7095
status: httpResponse.status,
7196
executionTime: duration,
@@ -78,7 +103,7 @@ export default abstract class Transport {
78103
headers: responseHeaders,
79104
status: httpResponse.status,
80105
executionTime: duration,
81-
size: responseText.length,
106+
size: 0,
82107
timestamp,
83108
};
84109
}
@@ -159,10 +184,10 @@ export default abstract class Transport {
159184

160185
protected abstract doSend(
161186
method: Method,
162-
headers: { [name: string]: string },
187+
headers: { [p: string]: string },
163188
pathPrefix: string,
164189
bodyJson?: string,
165190
endpointPath?: string,
166191
queries?: string,
167-
): Promise<ResponseData>;
192+
): Promise<Response>;
168193
}

0 commit comments

Comments
 (0)