1
0
mirror of synced 2025-12-23 11:54:18 -05:00
Files
docs/components/lib/get-rest-code-samples.ts
Tim Rogers 037d6328b8 Recommend an Accept header without V3 in it when documenting our REST API operations (#28477)
* Recommend an `Accept` header for REST API requests which doesn't mention V3

In the documentation for every REST API, in the "Headers"
section, we say for the `Accept` header that:

> Setting to `application/vnd.github.v3+json` is recommended.

Putting the V3 bit in doesn't actually do anything - in fact,
a high proportion of API consumers don't do it - and this
recommendation is going to be confusing once we launch our
new API versioning. This recommends that people use
`application/vnd.gitrhub+json` instead.

We could just recommend `application/json` - I'd be in favour
of that! - but I'm trying to make this change as small as
possible.

* Update cURL and GitHub CLI code examples to use an `Accept` header without V3

Co-authored-by: Sarah Edwards <skedwards88@github.com>
2022-06-29 15:50:07 +00:00

151 lines
5.4 KiB
TypeScript

import { parseTemplate } from 'url-template'
import { stringify } from 'javascript-stringify'
import type { CodeSample, Operation } from '../rest/types'
/*
Generates a curl example
For example:
curl \
-X POST \
-H "Accept: application/vnd.github+json" \
https://{hostname}/api/v3/repos/OWNER/REPO/deployments \
-d '{"ref":"topic-branch","payload":"{ \"deploy\": \"migrate\" }","description":"Deploy request from hubot"}'
*/
export function getShellExample(operation: Operation, codeSample: CodeSample) {
// This allows us to display custom media types like application/sarif+json
const defaultAcceptHeader = codeSample?.response?.contentType?.includes('+json')
? codeSample.response.contentType
: 'application/vnd.github+json'
const requestPath = codeSample?.request?.parameters
? parseTemplate(operation.requestPath).expand(codeSample.request.parameters)
: operation.requestPath
let requestBodyParams = ''
if (codeSample?.request?.bodyParameters) {
requestBodyParams = `-d '${JSON.stringify(codeSample.request.bodyParameters)}'`
// If the content type is application/x-www-form-urlencoded the format of
// the shell example is --data-urlencode param1=value1 --data-urlencode param2=value2
// For example, this operation:
// https://docs.github.com/en/enterprise/rest/reference/enterprise-admin#enable-or-disable-maintenance-mode
if (codeSample.request.contentType === 'application/x-www-form-urlencoded') {
requestBodyParams = ''
const paramNames = Object.keys(codeSample.request.bodyParameters)
paramNames.forEach((elem) => {
requestBodyParams = `${requestBodyParams} --data-urlencode ${elem}=${codeSample.request.bodyParameters[elem]}`
})
}
}
const args = [
operation.verb !== 'get' && `-X ${operation.verb.toUpperCase()}`,
`-H "Accept: ${defaultAcceptHeader}" \\ \n -H "Authorization: token <TOKEN>"`,
`${operation.serverUrl}${requestPath}`,
requestBodyParams,
].filter(Boolean)
return `curl \\\n ${args.join(' \\\n ')}`
}
/*
Generates a GitHub CLI example
For example:
gh api \
-X POST \
-H "Accept: application/vnd.github+json" \
/repos/OWNER/REPO/deployments \
-fref,topic-branch=0,payload,{ "deploy": "migrate" }=1,description,Deploy request from hubot=2
*/
export function getGHExample(operation: Operation, codeSample: CodeSample) {
const defaultAcceptHeader = codeSample?.response?.contentType?.includes('+json')
? codeSample.response.contentType
: 'application/vnd.github+json'
const hostname = operation.serverUrl !== 'https://api.github.com' ? '--hostname HOSTNAME' : ''
const requestPath = codeSample?.request?.parameters
? parseTemplate(operation.requestPath).expand(codeSample.request.parameters)
: operation.requestPath
let requestBodyParams = ''
if (codeSample?.request?.bodyParameters) {
const bodyParamValues = Object.values(codeSample.request.bodyParameters)
// GitHub CLI does not support sending Objects and arrays using the -F or
// -f flags. That support may be added in the future. It is possible to
// use gh api --input to take a JSON object from standard input
// constructed by jq and piped to gh api. However, we'll hold off on adding
// that complexity for now.
if (bodyParamValues.some((elem) => typeof elem === 'object')) {
return undefined
}
requestBodyParams = Object.keys(codeSample.request.bodyParameters)
.map((key) => {
if (typeof codeSample.request.bodyParameters[key] === 'string') {
return `-f ${key}='${codeSample.request.bodyParameters[key]}'\n`
} else {
return `-F ${key}=${codeSample.request.bodyParameters[key]}\n`
}
})
.join(' ')
}
const args = [
operation.verb !== 'get' && `--method ${operation.verb.toUpperCase()}`,
`-H "Accept: ${defaultAcceptHeader}"`,
hostname,
requestPath,
requestBodyParams,
].filter(Boolean)
return `# GitHub CLI api\n# https://cli.github.com/manual/gh_api\n\ngh api \\\n ${args.join(
' \\\n '
)}`
}
/*
Generates an octokit.js example
For example:
await octokit.request('POST /repos/{owner}/{repo}/deployments'{
"owner": "OWNER",
"repo": "REPO",
"ref": "topic-branch",
"payload": "{ \"deploy\": \"migrate\" }",
"description": "Deploy request from hubot"
})
*/
export function getJSExample(operation: Operation, codeSample: CodeSample) {
const parameters = codeSample.request
? { ...codeSample.request.parameters, ...codeSample.request.bodyParameters }
: {}
let queryParameters = ''
// Add query parameters to the request path for POST and PUT operations in
// URL template format e.g. 'POST /repos/{owner}/{repo}/releases/{release_id}/assets{?name,label}'
if (operation.verb === 'post' || operation.verb === 'put') {
const queryParms = operation.parameters
.filter((param) => {
return param.in === 'query'
})
.map((param) => {
return param.name
})
if (queryParms.length > 0) {
queryParameters = `{?${queryParms.join(',')}}`
}
}
const comment = `// Octokit.js\n// https://github.com/octokit/core.js#readme\n`
const require = `const octokit = new Octokit(${stringify(
{ auth: 'personal-access-token123' },
null,
2
)})\n\n`
return `${comment}${require}await octokit.request('${operation.verb.toUpperCase()} ${
operation.requestPath
}${queryParameters}', ${stringify(parameters, null, 2)})`
}