Skip to content

Commit

Permalink
Fix: malformed json error (#3107)
Browse files Browse the repository at this point in the history
* create json validator function

* make message more readable

* show response alongside warning
  • Loading branch information
thewahome authored Apr 30, 2024
1 parent a84d7a4 commit 38c3849
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 40 deletions.
10 changes: 9 additions & 1 deletion src/app/services/actions/query-action-creator-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ export async function generateResponseDownloadUrl(
}
}

async function tryParseJson(textValue: string) {
try {
return JSON.parse(textValue);
} catch (error) {
return textValue;
}
}

export function parseResponse(
response: any,
respHeaders: any = {}
Expand All @@ -233,7 +241,7 @@ export function parseResponse(
const contentType = getContentType(response.headers);
switch (contentType) {
case ContentType.Json:
return response.json();
return response.text().then(tryParseJson);
case ContentType.XML:
case ContentType.HTML:
case ContentType.TextCsv:
Expand Down
4 changes: 2 additions & 2 deletions src/app/services/actions/query-action-creators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ export function runQuery(query: IQuery) {
};

if (error instanceof ClientError) {
status.status = 0;
status.statusText = `${error.name}: ${error.message}`;
status.status = error.message;
status.statusText = error.name;
}

if (queryResultsInCorsError(query.sampleUrl)) {
Expand Down
15 changes: 8 additions & 7 deletions src/app/views/query-response/response/Response.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@

import { useDispatch } from 'react-redux';

import { AppDispatch, useAppSelector } from '../../../../store';
import { useAppSelector } from '../../../../store';
import { getContentType } from '../../../services/actions/query-action-creator-util';
import { convertVhToPx, getResponseEditorHeight,
getResponseHeight } from '../../common/dimensions/dimensions-adjustment';
import {
convertVhToPx, getResponseEditorHeight,
getResponseHeight
} from '../../common/dimensions/dimensions-adjustment';
import ResponseDisplay from './ResponseDisplay';
import { ResponseMessages } from './ResponseMessages';

const Response = () => {
const { dimensions: { response }, graphResponse, responseAreaExpanded, sampleQuery, authToken, graphExplorerMode } =
const { dimensions: { response }, graphResponse, responseAreaExpanded} =
useAppSelector((state) => state);
const { body, headers } = graphResponse;
const dispatch: AppDispatch = useDispatch();

const defaultHeight = convertVhToPx(getResponseHeight(response.height, responseAreaExpanded), 220);
const monacoHeight = getResponseEditorHeight(150);

const contentDownloadUrl = body?.contentDownloadUrl;
const throwsCorsError = body?.throwsCorsError;
const contentType = getContentType(headers);

return (
<div style={{ display: 'block' }}>
{ResponseMessages(graphResponse, sampleQuery, authToken, graphExplorerMode, dispatch)}
<ResponseMessages />
{!contentDownloadUrl && !throwsCorsError && headers &&
<ResponseDisplay
contentType={contentType}
Expand Down
78 changes: 48 additions & 30 deletions src/app/views/query-response/response/ResponseMessages.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Link, MessageBar, MessageBarType } from '@fluentui/react';
import { useState } from 'react';
import { IAuthenticateResult } from '../../../../types/authentication';
import { Mode } from '../../../../types/enums';
import { IGraphResponse } from '../../../../types/query-response';
import { useDispatch } from 'react-redux';

import { AppDispatch, useAppSelector } from '../../../../store';
import { Mode } from '../../../../types/enums';
import { IQuery } from '../../../../types/query-runner';
import { getContentType } from '../../../services/actions/query-action-creator-util';
import { runQuery } from '../../../services/actions/query-action-creators';
import { setSampleQuery } from '../../../services/actions/query-input-action-creators';
import { MOZILLA_CORS_DOCUMENTATION_LINK } from '../../../services/graph-constants';
Expand All @@ -15,31 +16,32 @@ interface ODataLink {
name: string;
}

export function ResponseMessages(
graphResponse: IGraphResponse,
sampleQuery: IQuery,
authToken: IAuthenticateResult,
graphExplorerMode: Mode,
dispatch: Function) {

function getOdataLinkFromResponseBody(responseBody: any): ODataLink | null {
const odataLinks = ['nextLink', 'deltaLink'];
let data = null;
if (responseBody) {
odataLinks.forEach(link => {
if (responseBody[`@odata.${link}`]) {
data = {
link: responseBody[`@odata.${link}`],
name: link
};
}
});
}
return data;
function getOdataLinkFromResponseBody(responseBody: any): ODataLink | null {
const odataLinks = ['nextLink', 'deltaLink'];
let data = null;
if (responseBody) {
odataLinks.forEach(link => {
if (responseBody[`@odata.${link}`]) {
data = {
link: responseBody[`@odata.${link}`],
name: link
};
}
});
}
return data;
}

export const ResponseMessages = () => {
const dispatch: AppDispatch = useDispatch();
const messageBars = [];

const { graphResponse: { body, headers }, sampleQuery, authToken, graphExplorerMode
} = useAppSelector((state) => state);
const [displayMessage, setDisplayMessage] = useState(true);

const tokenPresent = !!authToken.token;
const { body } = graphResponse;
const contentType = getContentType(headers);
const odataLink = getOdataLinkFromResponseBody(body);

const setQuery = () => {
Expand All @@ -51,7 +53,7 @@ export function ResponseMessages(

// Display link to step to next result
if (odataLink) {
return (
messageBars.push(
<MessageBar messageBarType={MessageBarType.info}>
{translateMessage('This response contains an @odata property.')}: @odata.{odataLink.name}
<Link onClick={() => setQuery()} underline>
Expand All @@ -63,7 +65,7 @@ export function ResponseMessages(

// Display link to download file response
if (body?.contentDownloadUrl) {
return (
messageBars.push(
<div>
<MessageBar messageBarType={MessageBarType.warning}>
{translateMessage('This response contains unviewable content')}
Expand All @@ -77,7 +79,7 @@ export function ResponseMessages(

// Show CORS compliance message
if (body?.throwsCorsError) {
return (
messageBars.push(
<div>
<MessageBar messageBarType={MessageBarType.warning}>
{translateMessage('Response content not available due to CORS policy')}
Expand All @@ -90,7 +92,7 @@ export function ResponseMessages(
}

if (body && !tokenPresent && displayMessage && graphExplorerMode === Mode.Complete) {
return (
messageBars.push(
<div>
<MessageBar
messageBarType={MessageBarType.warning}
Expand All @@ -104,4 +106,20 @@ export function ResponseMessages(
</div>
);
}
}

if (contentType === 'application/json' && typeof body === 'string') {
messageBars.push(
<div>
<MessageBar
messageBarType={MessageBarType.info}
onDismiss={() => setDisplayMessage(false)}
dismissButtonAriaLabel={translateMessage('Close')}
>
{translateMessage('Malformed JSON body')}
</MessageBar>
</div>
);
}

return messageBars;
}

0 comments on commit 38c3849

Please sign in to comment.