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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user