Skip to content

Commit fecfaa0

Browse files
authored
Merge pull request #149 from shotstack/derk/reference-code-samples
[4/4] docs: generate API reference samples that run, in current idioms
2 parents 0919de8 + 0e55c94 commit fecfaa0

13 files changed

Lines changed: 429 additions & 34 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,39 @@ jobs:
5353
pnpm build
5454
diff -r "$RUNNER_TEMP/schemas-before-docs" dist
5555
56+
# Every code sample is run, so CI needs each sample language's runtime.
57+
- uses: actions/setup-python@v5
58+
with:
59+
python-version: '3.12'
60+
61+
- uses: shivammathur/setup-php@v2
62+
with:
63+
php-version: '8.3'
64+
tools: composer
65+
66+
- uses: ruby/setup-ruby@v1
67+
with:
68+
ruby-version: '3.3'
69+
70+
- uses: actions/setup-java@v4
71+
with:
72+
distribution: temurin
73+
java-version: '17'
74+
75+
- uses: actions/setup-go@v5
76+
with:
77+
go-version: '1.22'
78+
cache: false
79+
80+
- name: Install sample libraries
81+
run: |
82+
pip install requests
83+
mkdir -p "$RUNNER_TEMP/php"
84+
composer require guzzlehttp/guzzle:^7 --working-dir "$RUNNER_TEMP/php" --no-interaction
85+
5686
- name: Check reference code samples
87+
env:
88+
CODE_SAMPLES_PHP_DIR: ${{ runner.temp }}/php
5789
run: node tests/reference-code-samples.cjs
5890

5991
- name: Dry run release

‎build-docs.sh‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,19 @@ node scripts/promote-request-examples.cjs "$OAS3_JSON" "$SAMPLES_JSON"
2525
# Convert OpenAPI to doc to Shins Markdown
2626
./node_modules/.bin/widdershins \
2727
--theme vs2015 \
28+
--user_templates templates/code-samples \
2829
--language_tabs shell:Curl http:HTTP javascript--nodejs:NodeJS php:PHP ruby:Ruby python:Python java:Java go:Go \
2930
--summary "$SAMPLES_JSON" \
3031
--outfile "$DOCS_DIR/index.html.md"
3132
rm -f "$SAMPLES_JSON"
3233

3334
cp "$DOCS_DIR/index.html.md" .shins/source/index.html.md
3435

35-
# Replace Serve, Ingest API URL's as overrides do not work
36-
sed -i -e 's/https:\/\/api.shotstack.io\/edit\/{version}\/assets/https:\/\/api.shotstack.io\/serve\/{version}\/assets/g' .shins/source/index.html.md
37-
sed -i -e 's/https:\/\/api.shotstack.io\/edit\/{version}\/sources/https:\/\/api.shotstack.io\/ingest\/{version}\/sources/g' .shins/source/index.html.md
36+
# Replace Serve, Ingest API URL's as overrides do not work. Matching the path, not the full URL, also
37+
# rewrites the HTTP samples' request lines.
38+
sed -i -e 's/\/edit\/{version}\/assets/\/serve\/{version}\/assets/g' .shins/source/index.html.md
39+
sed -i -e 's/\/edit\/{version}\/sources/\/ingest\/{version}\/sources/g' .shins/source/index.html.md
40+
sed -i -e 's/\/edit\/{version}\/upload/\/ingest\/{version}\/upload/g' .shins/source/index.html.md
3841

3942
# Build the Shins docs HTML
4043
cd .shins

‎templates/code-samples/code_go.dot‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{{#def.sample}}package main
2+
3+
import (
4+
"fmt"
5+
{{? sample.returnsJson }} "io"
6+
{{?}} "net/http"
7+
"os"
8+
{{? sample.hasBody }} "strings"
9+
{{?}})
10+
11+
func main() {
12+
{{? sample.hasBody }} body := strings.NewReader({{= sample.goBody }})
13+
14+
{{?}} req, err := http.NewRequest(http.Method{{= sample.verb }}, "{{= sample.url }}", {{= sample.hasBody ? 'body' : 'nil' }})
15+
if err != nil {
16+
panic(err)
17+
}
18+
{{~ sample.headers('os.Getenv("SHOTSTACK_API_KEY")', JSON.stringify) :h }} req.Header.Set("{{= h.name }}", {{= h.value }})
19+
{{~}}
20+
resp, err := http.DefaultClient.Do(req)
21+
if err != nil {
22+
panic(err)
23+
}
24+
defer resp.Body.Close()
25+
26+
{{? sample.returnsJson }} out, err := io.ReadAll(resp.Body)
27+
if err != nil {
28+
panic(err)
29+
}
30+
fmt.Println(resp.Status, string(out))
31+
{{??}} fmt.Println(resp.Status)
32+
{{?}}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{{#def.sample}}{{= sample.method }} {{= sample.path }} HTTP/1.1
2+
Host: {{= data.host }}{{~ sample.headers('YOUR_API_KEY', sample.raw) :h }}
3+
{{= h.name }}: {{= h.value }}{{~}}{{? sample.hasBody }}
4+
Content-Length: {{= Buffer.byteLength(sample.json) }}
5+
6+
{{= sample.json }}{{?}}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{#def.sample}}import java.net.URI;
2+
import java.net.http.HttpClient;
3+
import java.net.http.HttpRequest;
4+
import java.net.http.HttpResponse;
5+
6+
public class Main {
7+
public static void main(String[] args) throws Exception {
8+
{{? sample.hasBody }} var body = """
9+
{{= sample.javaTextBlock }}
10+
""";
11+
12+
{{?}} var request = HttpRequest.newBuilder(URI.create("{{= sample.url }}"))
13+
{{~ sample.headers('System.getenv("SHOTSTACK_API_KEY")', JSON.stringify) :h }} .header("{{= h.name }}", {{= h.value }})
14+
{{~}} .{{= sample.javaMethod }}
15+
.build();
16+
17+
var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
18+
System.out.println({{= sample.returnsJson ? 'response.body()' : 'response.statusCode()' }});
19+
}
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{{#def.sample}}{{? sample.hasBody }}const body = {{= sample.json }};
2+
3+
{{?}}const response = await fetch("{{= sample.url }}", {
4+
{{? sample.method !== 'GET' }} method: "{{= sample.method }}",
5+
{{?}} headers: {
6+
{{~ sample.headers('process.env.SHOTSTACK_API_KEY', JSON.stringify) :h }} "{{= h.name }}": {{= h.value }},
7+
{{~}} },
8+
{{? sample.hasBody }} body: JSON.stringify(body),
9+
{{?}}});
10+
11+
console.log({{= sample.returnsJson ? 'await response.json()' : 'response.status' }});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{{#def.sample}}<?php
2+
3+
require 'vendor/autoload.php';
4+
5+
use GuzzleHttp\Client;
6+
7+
$client = new Client();
8+
9+
$response = $client->request('{{= sample.method }}', {{= sample.single(sample.url) }}, [
10+
'headers' => [
11+
{{~ sample.headers("getenv('SHOTSTACK_API_KEY')", sample.single, true) :h }} {{= sample.single(h.name) }} => {{= h.value }},
12+
{{~}} ],
13+
{{? sample.hasBody }} 'json' => {{= sample.literal(sample.body, sample.php, ' ') }},
14+
{{?}}]);
15+
16+
echo {{= sample.returnsJson ? '$response->getBody()' : '$response->getStatusCode()' }}, PHP_EOL;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{{#def.sample}}import os
2+
3+
import requests
4+
5+
{{? sample.hasBody }}body = {{= sample.literal(sample.body, sample.python) }}
6+
7+
{{?}}response = requests.{{= data.method.verb }}(
8+
"{{= sample.url }}",
9+
headers={
10+
{{~ sample.headers('os.environ["SHOTSTACK_API_KEY"]', JSON.stringify, true) :h }} "{{= h.name }}": {{= h.value }},
11+
{{~}} },
12+
{{? sample.hasBody }} json=body,
13+
{{?}} timeout=30,
14+
)
15+
response.raise_for_status()
16+
print({{= sample.returnsJson ? 'response.json()' : 'response.status_code' }})
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{{#def.sample}}{{? sample.hasBody }}require 'json'
2+
{{?}}require 'net/http'
3+
4+
uri = URI({{= sample.single(sample.url) }})
5+
{{? sample.hasBody }}body = {{= sample.literal(sample.body, sample.ruby) }}
6+
{{?}}
7+
request = Net::HTTP::{{= sample.verb }}.new(uri, {
8+
{{~ sample.headers("ENV.fetch('SHOTSTACK_API_KEY')", sample.single) :h }} {{= sample.single(h.name) }} => {{= h.value }},
9+
{{~}}})
10+
{{? sample.hasBody }}request.body = body.to_json
11+
{{?}}
12+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
13+
http.request(request)
14+
end
15+
16+
puts {{= sample.returnsJson ? 'response.body' : 'response.code' }}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{{#def.sample}}{{? sample.hasBody }}# Save the body parameter below as {{= sample.bodyFile }}
2+
{{?}}curl {{? sample.method !== 'GET' }}-X {{= sample.method }} {{?}}"{{= sample.url }}"{{~ sample.headers('$SHOTSTACK_API_KEY', sample.raw) :h }} \
3+
-H "{{= h.name }}: {{= h.value }}"{{~}}{{? sample.hasBody }} \
4+
-d @{{= sample.bodyFile }}{{?}}

0 commit comments

Comments
 (0)