diff --git a/.changeset/many-tomatoes-bathe.md b/.changeset/many-tomatoes-bathe.md new file mode 100644 index 0000000000..38260be329 --- /dev/null +++ b/.changeset/many-tomatoes-bathe.md @@ -0,0 +1,7 @@ +--- +'@commercetools-docs/gatsby-theme-api-docs': patch +'@commercetools-website/api-docs-smoke-test': patch +'@commercetools-api-specs/test': patch +--- + +Add support for primitive and generic JSON types in API request and response diff --git a/api-specs/test/api.raml b/api-specs/test/api.raml index a540dcd3c2..4510938412 100644 --- a/api-specs/test/api.raml +++ b/api-specs/test/api.raml @@ -475,6 +475,21 @@ uses: type: object example: !include examples/action-success.json + /json-serializable-primitive-type: + put: + description: Use the PUT method to write data to a backend system. Any JSON serializable payload is accepted. The following request example adds a product to a cart. For the response, we recommend to use standard HTTP codes and `application/json` encoded content. The response will be structured [as defined by the `body` property of the action](/). The following response example contains the updated cart information, which includes the added product. + body: + application/json: + type: object + example: !include examples/json-serializable-primitive-object.json + responses: + 200: + description: We recommend to use standard HTTP response codes and `application/json` encoded content. The response will look like the response you have declared in your action. As an example we will fetch the cart. + body: + application/json: + type: any + example: !include examples/json-serializable-primitive-raw.json + # /resourceWithHeaders: # description: Tests use of specific headers. diff --git a/api-specs/test/examples/json-serializable-primitive-object.json b/api-specs/test/examples/json-serializable-primitive-object.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/api-specs/test/examples/json-serializable-primitive-object.json @@ -0,0 +1 @@ +{} diff --git a/api-specs/test/examples/json-serializable-primitive-raw.json b/api-specs/test/examples/json-serializable-primitive-raw.json new file mode 100644 index 0000000000..d3e505fbc8 --- /dev/null +++ b/api-specs/test/examples/json-serializable-primitive-raw.json @@ -0,0 +1 @@ +"raw string" diff --git a/packages/gatsby-theme-api-docs/src/components/resource/method/request-representation.js b/packages/gatsby-theme-api-docs/src/components/resource/method/request-representation.js index d5e3525e25..4e160e02d3 100644 --- a/packages/gatsby-theme-api-docs/src/components/resource/method/request-representation.js +++ b/packages/gatsby-theme-api-docs/src/components/resource/method/request-representation.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import styled from '@emotion/styled'; import SpacingsStack from '@commercetools-uikit/spacings-stack'; import SpacingsInline from '@commercetools-uikit/spacings-inline'; -import { designSystem } from '@commercetools-docs/ui-kit'; +import { designSystem, Markdown } from '@commercetools-docs/ui-kit'; import { useTypeLocations, locationForType, @@ -12,6 +12,7 @@ import renderTypeAsLink from '../../../utils/render-type-as-link'; import ApiTypeByKey from '../../type/type-by-api-key'; import Title from './title'; import ContentType from './highlights'; +import { getDescriptionIfPrimitiveType } from '../../type/type'; const RequestRepresentation = (props) => { const typeLocations = useTypeLocations(); @@ -21,6 +22,19 @@ const RequestRepresentation = (props) => { typeLocations ); + let primitiveJSONType; + + if ( + !requestRepresentationLocation && + props.contentType && + props.contentType.includes('application/json') + ) { + primitiveJSONType = getDescriptionIfPrimitiveType( + 'application/json', + props.apiType + ); + } + const ContentTypeRow = styled.div` display: flex; align-items: center; @@ -46,9 +60,13 @@ const RequestRepresentation = (props) => { })} The file to upload - ) : requestRepresentationLocation ? ( + ) : requestRepresentationLocation || primitiveJSONType ? ( - {renderTypeAsLink(props.apiKey, props.apiType, typeLocations)} + {primitiveJSONType ? ( + {primitiveJSONType} + ) : ( + renderTypeAsLink(props.apiKey, props.apiType, typeLocations) + )} as {props.contentType} @@ -56,6 +74,7 @@ const RequestRepresentation = (props) => { {props.contentType} { apiKey, response.body.applicationjson.type, typeLocations, - response.description + response.description, + contentType )} {contentType.length > 0 && ( <> diff --git a/packages/gatsby-theme-api-docs/src/components/type/type.js b/packages/gatsby-theme-api-docs/src/components/type/type.js index 5aebdcb8d1..c73e98db54 100644 --- a/packages/gatsby-theme-api-docs/src/components/type/type.js +++ b/packages/gatsby-theme-api-docs/src/components/type/type.js @@ -12,13 +12,44 @@ import Enum from './enum'; import Properties from './properties/properties'; import Examples from './examples'; +const contentTypeToPrimitiveMap = { + 'application/json': { + number: 'Any JSON "number"', + any: 'Any valid JSON', + object: 'Any JSON "object"', + boolean: 'Any JSON "boolean"', + string: 'Any JSON "string"', + array: 'Any JSON "array"', + }, +}; + +export const getDescriptionIfPrimitiveType = (contentType, type) => + contentTypeToPrimitiveMap[contentType] && + contentTypeToPrimitiveMap[contentType][type]; + const ApiType = (props) => { - const matchedApiType = props.apiTypes.find((apiType) => { + console.log(props); + let matchedApiType = props.apiTypes.find((apiType) => { return ( apiType.apiKey === props.apiKey && apiType.displayName === props.type ); }); + if (!matchedApiType) { + if (props.contentType && props.contentType.includes('application/json')) { + const primitiveTypeDescription = getDescriptionIfPrimitiveType( + 'application/json', + props.type + ); + if (primitiveTypeDescription) { + matchedApiType = { + displayName: props.type, + description: primitiveTypeDescription, + }; + } + } + } + if (!matchedApiType) { return reportError( `Type with name '${props.type}' not found in '${props.apiKey}' API` @@ -92,6 +123,7 @@ ApiType.propTypes = { ]), doNotRenderExamples: PropTypes.bool, hideInheritedProperties: PropTypes.bool, + contentType: PropTypes.arrayOf(PropTypes.string), }; export default ApiType; 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 59ffbe7e97..bee3c7f86d 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,20 +1,36 @@ import React from 'react'; import { Link } from '@commercetools-docs/gatsby-theme-docs'; -import { markdownFragmentToReact } from '@commercetools-docs/ui-kit'; +import { markdownFragmentToReact, 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) { +function renderTypeAsLink( + apiKey, + type, + typeLocations, + description, + contentType +) { const typeLocation = locationForType(apiKey, type, typeLocations); - const originalTypeLocation = typeLocation ? typeLocation.url : ''; + const originalTypeLocation = typeLocation ? typeLocation.url : undefined; - return originalTypeLocation ? ( - {type} - ) : description ? ( - markdownFragmentToReact(description) - ) : ( - type - ); -} + let primitiveJsonType; + if ( + !originalTypeLocation && + Array.isArray(contentType) && + contentType.includes('application/json') + ) { + primitiveJsonType = getDescriptionIfPrimitiveType('application/json', type); + } + if (originalTypeLocation) { + return {type}; + } else if (primitiveJsonType) { + return {primitiveJsonType}; + } else if (description) { + return markdownFragmentToReact(description); + } + return type; +} export default renderTypeAsLink; diff --git a/websites/api-docs-smoke-test/src/content/endpoints/endpoints-for-resource.mdx b/websites/api-docs-smoke-test/src/content/endpoints/endpoints-for-resource.mdx index d00473a307..76a3052782 100644 --- a/websites/api-docs-smoke-test/src/content/endpoints/endpoints-for-resource.mdx +++ b/websites/api-docs-smoke-test/src/content/endpoints/endpoints-for-resource.mdx @@ -28,3 +28,7 @@ import { ApiEndpointsForResource } from "/shortcodes" # /{projectKey}/resource/namespace-action-with-example + +# /{projectKey}/resource/json-serializable-primitive-type + +