Feat/api reference curl examples (#720)

* curl reference initial

* add tooltips to curl command

* refactor copy component

* move copy to copy component

* formatting

* always include required fields

* add example values

* format svg

* fix property extraction

* explainer comment
This commit is contained in:
Philip Korsholm
2021-11-19 10:18:16 +01:00
committed by GitHub
parent 2d9879ea09
commit f162b4a2a1
11 changed files with 369 additions and 78 deletions

View File

@@ -10,18 +10,19 @@ import ResponsiveContainer from "./responsive-container"
import { formatMethodParams } from "../../utils/format-parameters"
import useInView from "../../hooks/use-in-view"
import NavigationContext from "../../context/navigation-context"
import { formatRoute } from "../../utils/format-route"
const Method = ({ data, section, pathname }) => {
const Method = ({ data, section, pathname, api }) => {
const { parameters, requestBody, description, method, summary } = data
const jsonResponse = data.responses[0].content?.[0].json
const { updateHash, updateMetadata } = useContext(NavigationContext)
const methodRef = useRef(null)
const [containerRef, isInView] = useInView({
root: null,
rootMargin: "0px 0px -80% 0px",
threshold: 0,
})
const formattedParameters = formatMethodParams({ parameters, requestBody })
useEffect(() => {
if (isInView) {
@@ -42,6 +43,129 @@ const Method = ({ data, section, pathname }) => {
}
}
const getExampleValues = (type, defaultExample) => {
switch (type) {
case "integer":
return 1000
case "boolean":
return false
case "object":
return {}
default:
return defaultExample
}
}
// extract required properties or a non-required property from a json object
// based on the extraction method "getPropertyFromObject"
const getPropertiesFromObject = (
requiredProperties,
properties,
obj,
res,
getPropertyFromObject
) => {
for (const element of requiredProperties) {
try {
res[element.property] = getPropertyFromObject(obj, element.property)
} catch (err) {}
}
// if (Object.keys(res) === requiredProperties.map((p) => p.property)) {
// return res
// }
for (const element of properties) {
try {
res[element.property] = getPropertyFromObject(obj, element.property)
break
} catch (err) {}
}
return res
}
const getCurlJson = (properties, prefix, bodyParameters) => {
if (!properties[0]) {
return
}
const jsonObject = JSON.parse(jsonResponse)
const pathParts = pathname.split("/")
const requiredProperties = bodyParameters.filter((p) => p.required)
let res = {}
// if the endpoint is for a relation i.e. /orders/:id/shipment drill down into the properties of the json object
if (pathParts.length > 3) {
const propertyIndex = pathParts[2].match(/{[A-Za-z_]+}/) ? 3 : 2
try {
const obj =
jsonObject[pathParts[propertyIndex].replace("-", "_")] ||
jsonObject[Object.keys(jsonObject)[0]][
pathParts[propertyIndex].replace("-", "_")
]
res = getPropertiesFromObject(
requiredProperties,
properties,
obj,
res,
(obj, property) =>
Array.isArray(obj)
? obj.find((o) => o[property])[property]
: obj[property]
)
} catch (err) {}
}
// if nothing was found drilling down look at the top level properties
if (JSON.stringify(res) === "{}") {
res = getPropertiesFromObject(
requiredProperties,
properties,
jsonObject,
res,
(jsonObject, property) =>
jsonObject[property] ||
jsonObject[Object.keys(jsonObject)[0]][property]
)
}
// Last resort, set the first property to an example
if (JSON.stringify(res) === "{}") {
res[properties[0].property] = getExampleValues(properties[0].type, `${prefix}_${properties[0].property}`)
}
// Add values to 'undefined' properties before returning due to JSON.stringify removing 'undefined' but not 'null'
return requiredProperties.reduce((prev, curr) => {
if(prev[curr.property] === undefined){
prev[curr.property] = getExampleValues(curr.type, `${prefix}_${curr.property}`)
}
return prev
}, res)
}
const getCurlCommand = (requestBody) => {
const body = JSON.stringify(
getCurlJson(
requestBody.properties,
`example_${section}`,
formattedParameters.body
)
)
return `curl -X ${data.method.toUpperCase()} https://medusa-url.com/${api}${formatRoute(
pathname
)} \\
--header "Authorization: Bearer <ACCESS TOKEN>" ${
data.method.toUpperCase() === "POST" && requestBody.properties?.length > 0
? `\\
--header "content-type: application/json" \\
--data '${body}'`
: ""
}`
}
return (
<Flex
py={"5vw"}
@@ -89,18 +213,27 @@ const Method = ({ data, section, pathname }) => {
<Markdown>{description}</Markdown>
</Text>
</Description>
<Box mt={4}>
<Parameters
params={formatMethodParams({ parameters, requestBody })}
/>
<Box mt={2}>
<Parameters params={formattedParameters} type={"Parameters"} />
</Box>
</Flex>
<Box className="code">
<JsonContainer
json={jsonResponse}
header={"RESPONSE"}
method={convertToKebabCase(summary)}
/>
<Box>
<JsonContainer
json={getCurlCommand(requestBody)}
header={"cURL Example"}
language={"shell"}
allowCopy={true}
method={convertToKebabCase(summary)}
/>
</Box>
<Box>
<JsonContainer
json={jsonResponse}
header={"RESPONSE"}
method={convertToKebabCase(summary)}
/>
</Box>
</Box>
</ResponsiveContainer>
</Flex>