From f9185c6a3c927d4c1edbeb0a5cc865adc19a48dc Mon Sep 17 00:00:00 2001
From: Timon Rey Turak <31767369+timonrey@users.noreply.github.com>
Date: Wed, 16 Aug 2023 17:27:42 +0200
Subject: [PATCH] Display content types for responses correctly (#1790)
* fix: display content types for responses correctly
* feat: enable other content types for responses
* chore: fix graphql query
* chore: show no content type if description is defined
* chore: add testcase for a different content type for responses
* chore: add changeset
* chore: fix indentation
* refactor: add safety checks
* chore: show content type only if description is not displayed
* refactor: rename prop
---
.changeset/witty-glasses-share.md | 6 +++
api-specs/test/api.raml | 17 ++++++--
.../src/components/resource/method/method.js | 33 +++++++++++----
.../method/request-response-examples.js | 21 ++++------
.../components/resource/method/responses.js | 33 ++++++++++-----
.../src/hooks/use-api-resources.js | 40 +++++++++++++++----
.../src/utils/render-type-as-link.js | 12 +-----
.../src/utils/resource/process-methods.mjs | 12 ++++--
8 files changed, 116 insertions(+), 58 deletions(-)
create mode 100644 .changeset/witty-glasses-share.md
diff --git a/.changeset/witty-glasses-share.md b/.changeset/witty-glasses-share.md
new file mode 100644
index 0000000000..5e85da67f0
--- /dev/null
+++ b/.changeset/witty-glasses-share.md
@@ -0,0 +1,6 @@
+---
+'@commercetools-docs/gatsby-transformer-raml': minor
+'@commercetools-docs/gatsby-theme-api-docs': minor
+---
+
+Display the response content type correctly. It also enables support for other content types that are already supported in request bodies.
diff --git a/api-specs/test/api.raml b/api-specs/test/api.raml
index 4510938412..4748300e2e 100644
--- a/api-specs/test/api.raml
+++ b/api-specs/test/api.raml
@@ -284,10 +284,11 @@ uses:
203:
description: ArrayTestType using 2 different custom example files
body:
- type: arrays.ArrayTestType
- examples:
- custom1: !include examples/array-test-type-custom-1.json
- custom2: !include examples/array-test-type-custom-2.json
+ application/x-www-form-urlencoded:
+ type: arrays.ArrayTestType
+ examples:
+ custom1: !include examples/array-test-type-custom-1.json
+ custom2: !include examples/array-test-type-custom-2.json
/description-with-urn-links:
post:
@@ -338,6 +339,14 @@ uses:
body:
application/x-www-form-urlencoded:
type: scalars.StringTestType
+ responses:
+ 200:
+ body:
+ application/json:
+ type: scalars.StringTestType
+ 201:
+ body:
+ type: date-test-type.DateTestType
/searchApiPattern:
get:
diff --git a/packages/gatsby-theme-api-docs/src/components/resource/method/method.js b/packages/gatsby-theme-api-docs/src/components/resource/method/method.js
index 138c9e96af..a1b32957f6 100644
--- a/packages/gatsby-theme-api-docs/src/components/resource/method/method.js
+++ b/packages/gatsby-theme-api-docs/src/components/resource/method/method.js
@@ -33,7 +33,7 @@ const Container = styled.div`
const TitleWithAnchor = Markdown.withCopyToClipboard(Title);
-function convertContentType(type) {
+export function convertContentType(type) {
switch (type) {
case 'applicationjson':
return 'application/json';
@@ -67,7 +67,9 @@ const Method = ({
allUriParameters = allUriParameters.concat(method.uriParameters);
}
- const contentType = [];
+ const requestContentType = [];
+ const responseContentType = [];
+
if (method.body) {
const findOutContentTypes = Object.keys(method.body).reduce(
(list, value) => {
@@ -76,13 +78,29 @@ const Method = ({
[]
);
findOutContentTypes.forEach((type) => {
- contentType.push(convertContentType(type));
+ requestContentType.push(convertContentType(type));
+ });
+ }
+
+ if (method.responses) {
+ const findOutContentTypes = [];
+ method.responses.forEach((response) => {
+ response.body &&
+ Object.keys(response.body).forEach((key) => {
+ if (convertContentType(key) !== '' && response.body[key]) {
+ findOutContentTypes.push(key);
+ }
+ });
+ });
+
+ findOutContentTypes.forEach((type) => {
+ responseContentType.push(type);
});
}
const isStructuredDataType =
- contentType.includes('application/json') ||
- contentType.includes('application/x-www-form-urlencoded');
+ requestContentType.includes('application/json') ||
+ requestContentType.includes('application/x-www-form-urlencoded');
const methodColor = computeMethodColor(methodType.toLowerCase());
@@ -144,7 +162,7 @@ const Method = ({
method.body.applicationxwwwformurlencoded?.type
}
isStructuredDataType={isStructuredDataType}
- contentType={contentType}
+ contentType={requestContentType}
/>
)}
@@ -152,7 +170,7 @@ const Method = ({
)}
@@ -161,6 +179,7 @@ const Method = ({
apiKey={apiKey}
requestCodeExamples={method.codeExamples}
responses={method.responses}
+ contentType={responseContentType}
/>
)}
diff --git a/packages/gatsby-theme-api-docs/src/components/resource/method/request-response-examples.js b/packages/gatsby-theme-api-docs/src/components/resource/method/request-response-examples.js
index 07c00102b7..15093b4063 100644
--- a/packages/gatsby-theme-api-docs/src/components/resource/method/request-response-examples.js
+++ b/packages/gatsby-theme-api-docs/src/components/resource/method/request-response-examples.js
@@ -9,9 +9,8 @@ const RequestResponseExamples = (props) => {
const apiTypes = useApiTypes();
const responsesCodeExamples = [];
if (props.responses) {
- props.responses.forEach((response) => {
- const typeDisplayName =
- response.body && response.body.applicationjson.type;
+ props.responses.forEach((response, index) => {
+ const typeDisplayName = response?.body?.[props.contentType[index]]?.type;
const { code } = response;
if (typeDisplayName) {
const apiType = apiTypes.find((type) => {
@@ -20,7 +19,8 @@ const RequestResponseExamples = (props) => {
);
});
- const examplesNode = response.body?.applicationjson?.examples;
+ const examplesNode =
+ response.body?.[props.contentType[index]]?.examples;
if (examplesNode && Array.isArray(examplesNode)) {
examplesNode.forEach((example) => {
@@ -33,7 +33,7 @@ const RequestResponseExamples = (props) => {
value: example.value,
});
});
- } else if (apiType.examples && apiType.examples.length > 0) {
+ } else if (apiType?.examples?.length > 0) {
responsesCodeExamples.push({
code,
typeDisplayName,
@@ -84,17 +84,10 @@ RequestResponseExamples.propTypes = {
responses: PropTypes.arrayOf(
PropTypes.shape({
code: PropTypes.number.isRequired,
- body: PropTypes.oneOfType([
- PropTypes.node,
- PropTypes.shape({
- applicationjson: PropTypes.shape({
- builtinType: PropTypes.string.isRequired,
- type: PropTypes.string.isRequired,
- }),
- }),
- ]),
+ body: PropTypes.object,
}).isRequired
),
+ contentType: PropTypes.array.isRequired,
};
export default RequestResponseExamples;
diff --git a/packages/gatsby-theme-api-docs/src/components/resource/method/responses.js b/packages/gatsby-theme-api-docs/src/components/resource/method/responses.js
index df2f580646..e2c1a0bd72 100644
--- a/packages/gatsby-theme-api-docs/src/components/resource/method/responses.js
+++ b/packages/gatsby-theme-api-docs/src/components/resource/method/responses.js
@@ -12,6 +12,7 @@ import SpacingsInline from '@commercetools-uikit/spacings-inline';
import { tokens, dimensions, typography } from '../../../design-system';
import { useTypeLocations } from '../../../hooks/use-type-locations';
import renderTypeAsLink from '../../../utils/render-type-as-link';
+import { convertContentType } from './method';
import Title from './title';
const ResponseCode = styled.span`
@@ -35,7 +36,21 @@ const Responses = ({ apiKey, responses, contentType }) => {
Response:
- {responses.map((response) => {
+ {responses.map((response, index) => {
+ const convertedContentType = convertContentType(contentType[index]);
+ const responseDetails =
+ response.body &&
+ renderTypeAsLink(
+ apiKey,
+ response.body[contentType[index]].type,
+ typeLocations,
+ convertedContentType
+ );
+ // If renderTypeAsLink returns the type again and a description is defined, we display the description.
+ // In this case, the content type should not be displayed at the moment.
+ const showDescription =
+ responseDetails === response.body?.[contentType[index]].type &&
+ response.description;
return (
{
{response.code}
- {response.body ? (
+ {responseDetails ? (
- {renderTypeAsLink(
- apiKey,
- response.body.applicationjson.type,
- typeLocations,
- response.description,
- contentType
- )}
- {contentType.length > 0 && (
+ {showDescription
+ ? markdownFragmentToReact(response.description)
+ : responseDetails}
+ {contentType.length > 0 && !showDescription && (
<>
as
- {contentType}
+ {convertedContentType}
>
)}
diff --git a/packages/gatsby-theme-api-docs/src/hooks/use-api-resources.js b/packages/gatsby-theme-api-docs/src/hooks/use-api-resources.js
index 24156b4ec7..a09bb24bac 100644
--- a/packages/gatsby-theme-api-docs/src/hooks/use-api-resources.js
+++ b/packages/gatsby-theme-api-docs/src/hooks/use-api-resources.js
@@ -29,14 +29,7 @@ export const useApiResources = () => {
code
description
body {
- applicationjson {
- type
- builtinType
- examples {
- name
- value
- }
- }
+ ...methodBodiesForResponses
}
}
codeExamples {
@@ -45,6 +38,37 @@ export const useApiResources = () => {
}
}
+ fragment methodBodiesForResponses on RamlResourceMethodBody {
+ applicationjson {
+ type
+ builtinType
+ examples {
+ name
+ value
+ }
+ }
+ applicationxwwwformurlencoded {
+ type
+ builtinType
+ examples {
+ name
+ value
+ }
+ }
+ imagejpeg {
+ type
+ builtinType
+ }
+ imagepng {
+ type
+ builtinType
+ }
+ imagegif {
+ type
+ builtinType
+ }
+ }
+
fragment methodBodies on RamlResourceMethodBody {
applicationjson {
type
diff --git a/packages/gatsby-theme-api-docs/src/utils/render-type-as-link.js b/packages/gatsby-theme-api-docs/src/utils/render-type-as-link.js
index bee3c7f86d..a87f644ac5 100644
--- a/packages/gatsby-theme-api-docs/src/utils/render-type-as-link.js
+++ b/packages/gatsby-theme-api-docs/src/utils/render-type-as-link.js
@@ -1,16 +1,10 @@
import React from 'react';
import { Link } from '@commercetools-docs/gatsby-theme-docs';
-import { markdownFragmentToReact, Markdown } from '@commercetools-docs/ui-kit';
+import { Markdown } from '@commercetools-docs/ui-kit';
import { locationForType } from '../hooks/use-type-locations';
import { getDescriptionIfPrimitiveType } from '../components/type/type';
-function renderTypeAsLink(
- apiKey,
- type,
- typeLocations,
- description,
- contentType
-) {
+function renderTypeAsLink(apiKey, type, typeLocations, contentType) {
const typeLocation = locationForType(apiKey, type, typeLocations);
const originalTypeLocation = typeLocation ? typeLocation.url : undefined;
@@ -28,8 +22,6 @@ function renderTypeAsLink(
return {type};
} else if (primitiveJsonType) {
return {primitiveJsonType};
- } else if (description) {
- return markdownFragmentToReact(description);
}
return type;
}
diff --git a/packages/gatsby-transformer-raml/src/utils/resource/process-methods.mjs b/packages/gatsby-transformer-raml/src/utils/resource/process-methods.mjs
index 84c45f59f4..08afd79859 100644
--- a/packages/gatsby-transformer-raml/src/utils/resource/process-methods.mjs
+++ b/packages/gatsby-transformer-raml/src/utils/resource/process-methods.mjs
@@ -37,10 +37,14 @@ function processMethods({
);
if (returnedMethods[method].responses) {
returnedMethods[method].responses.forEach((response) => {
- if (response?.body?.applicationjson.examples) {
- response.body.applicationjson.examples = examplesToArray(
- response.body.applicationjson.examples
- );
+ if (response?.body) {
+ Object.keys(response.body).forEach((key) => {
+ if (response.body[key].examples) {
+ response.body[key].examples = examplesToArray(
+ response.body[key].examples
+ );
+ }
+ });
}
});
}