Add HTTP examples to API blocks (#2759)

This commit is contained in:
Scott Cazan
2025-01-21 15:34:42 +01:00
committed by GitHub
parent e5dc05e994
commit 162b4b78b6
3 changed files with 117 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@gitbook/react-openapi': minor
---
Add in HTTP example code blocks
@@ -0,0 +1,51 @@
import { it, expect } from 'bun:test';
import { parseHostAndPath } from './code-samples';
it('should parse host and path on url strings properly', () => {
const testUrls = [
'//example.com/path',
'//sub.example.com',
'//example:8080/v1/test',
'ftp://domain.com',
'//example.com/com.example',
'https://example.com/path.com/another.com',
'example.com/firstPath/secondPath',
];
expect(testUrls.map(parseHostAndPath)).toEqual([
{
host: 'example.com',
path: '/path',
},
{
host: 'sub.example.com',
path: '/',
},
{
host: 'example:8080',
path: '/v1/test',
},
{
host: 'domain.com',
path: '/',
},
{
host: 'example.com',
path: '/com.example',
},
{
host: 'example.com',
path: '/path.com/another.com',
},
{
host: 'example.com',
path: '/firstPath/secondPath',
},
]);
});
@@ -84,6 +84,46 @@ export const codeSampleGenerators: CodeSampleGenerator[] = [
return code;
},
},
{
id: 'http',
label: 'HTTP',
syntax: 'bash',
generate: ({ method, url, headers = {}, body }: CodeSampleInput) => {
const { host, path } = parseHostAndPath(url);
if (body) {
// if we had a body add a content length header
const bodyContent = body ? JSON.stringify(body) : '';
// handle unicode chars with a text encoder
const encoder = new TextEncoder();
headers = {
...headers,
'Content-Length': encoder.encode(bodyContent).length.toString(),
};
}
if (!headers.hasOwnProperty('Accept')) {
headers.Accept = '*/*';
}
const headerString = headers
? Object.entries(headers)
.map(([key, value]) =>
key.toLowerCase() !== 'host' ? `${key}: ${value}` : ``,
)
.join('\n') + '\n'
: '';
const bodyString = body ? `\n${JSON.stringify(body, null, 2)}` : '';
const httpRequest = `${method.toUpperCase()} ${decodeURI(path)} HTTP/1.1
Host: ${host}
${headerString}${bodyString}`;
return httpRequest;
},
},
];
function indent(code: string, spaces: number) {
@@ -93,3 +133,24 @@ function indent(code: string, spaces: number) {
.map((line) => (line ? indent + line : ''))
.join('\n');
}
export function parseHostAndPath(url: string) {
try {
const urlObj = new URL(url);
const path = urlObj.pathname || '/';
return { host: urlObj.host, path };
} catch (e) {
// If the URL was invalid do our best to parse the URL.
// Check for the protocol part and pull it off to grab the host
const fullUrl = url.match(/\/\//) ? url.split('//')[1] : url;
// separate paths from the first element (host)
const parts = fullUrl.split('/');
// pull off the host (mutates)
const host = parts.shift();
// add a leading slash and join the paths again
const path = '/' + parts.join('/');
return { host, path };
}
}