Skip to content

Commit

Permalink
Add docs generator and improve http-routes.md generation (bluesky-soc…
Browse files Browse the repository at this point in the history
  • Loading branch information
pfrazee authored Sep 13, 2022
1 parent d2969b4 commit 0681c95
Show file tree
Hide file tree
Showing 31 changed files with 2,895 additions and 190 deletions.
10 changes: 10 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"private": true,
"scripts": {
"build": "node scripts/gen.js"
},
"dependencies": {
"widdershins": "^4.0.1",
"yaml": "^2.1.1"
}
}
37 changes: 37 additions & 0 deletions docs/scripts/gen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const widdershins = require('widdershins')
const yaml = require('yaml')
const fs = require('fs')
const path = require('path')

async function httpRoutes() {
console.log('Converting http-routes.yml to .md')
const yamlStr = fs.readFileSync(
path.join(__dirname, '..', 'specs', 'http-routes.yml'),
'utf8',
)
const md = await widdershins.convert(yaml.parse(yamlStr), {
search: false,
language_tabs: [],
sample: false,
user_templates: path.join(__dirname, 'http-routes-templates'),
})
fs.writeFileSync(
path.join(__dirname, '..', 'specs', 'http-routes.md'),
stripFrontMatter(md),
)
}
httpRoutes()
// widdershins --search false --language_tabs false -o docs/specs/http-routes.md --raw docs/specs/http-routes.yml

function stripFrontMatter(md) {
const lines = md.split('\n')
let numDashLines = 0
let i = 0
while (numDashLines < 2) {
if (lines[i].trim() === '---') {
numDashLines++
}
i++
}
return lines.slice(i).join('\n')
}
64 changes: 64 additions & 0 deletions docs/scripts/http-routes-templates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
## Swagger / OpenAPI 2 and OpenAPI 3 template parameters

Note that properties of OpenAPI objects will be in OpenAPI 3.0 form, as
Swagger / OpenAPI 2.0 definitions are converted automatically.

### Code templates

* `method` - the HTTP method of the operation (in lower-case)
* `methodUpper` - the HTTP method of the operation (in upper-case)
* `url` - the full URL of the operation (including protocol and host)
* `consumes[]` - an array of MIME-types the operation consumes
* `produces[]` - an array of MIME-types the operation produces
* `operation` - the current operation object
* `operationId` - the current operation id
* `opName` - the operationId if set, otherwise the method + path
* `tags[]` - the full list of tags applying to the operation
* `security` - the security definitions applying to the operation
* `resource` - the current tag/path object
* `parameters[]` - an array of parameters for the operation (see below)
* `queryString` - an example queryString, urlEncoded
* `requiredQueryString` - an example queryString for `required:true` parameters
* `queryParameters[]` - a subset of `parameters` that are `in:query`
* `requiredParameters[]` - a subset of `queryParameters` that are `required:true`
* `headerParameters[]` - a subset of `parameters` that are `in:header`
* `allHeaders[]` - a concatenation of `headerParameters` and pseudo-parameters `Accept` and `Content-Type`, and optionally `Authorization` (the latter has an `isAuth` boolean property set true so it can be omitted in templates if desired

### Parameter template

* `parameters[]` - an array of [parameters](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject), including the following pseudo-properties
* `shortDesc` - a truncated version of the parameter description
* `safeType` - a computed version of the parameter type, including Body and schema names
* `originalType` - the original type of the parameter
* `exampleValues` - an object containing examples for use in code-templates
* `json` - example values in JSON compatible syntax
* `object` - example values in raw object form (unquoted strings etc)
* `depth` - a zero-based indicator of the depth of expanded request body parameters
* `enums[]` - an array of (parameter)name/value pairs

### Responses template

* `responses[]` - an array of [responses](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject), including `status` and `meaning` properties

### Authentication template

* `authenticationStr` - a simple string of methods (and scopes where appropriate)
* `securityDefinitions[]` - an array of applicable [securityDefinitions](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securityRequirementObject)

### Schema Property template

* `schemaProperties[]` - an array of
* `name`
* `type`
* `required`
* `description`
* `enums[]` - an array of (schema property)name/value pairs

### Common to all templates

* `openapi` - the top-level OpenAPI / Swagger document
* `header` - the front-matter of the Slate/Shins markdown document
* `host` - the (computed) host of the API
* `protocol` - the default/first protocol of the API
* `baseUrl` - the (computed) baseUrl of the API (including protocol and host)
* `widdershins` - the contents of widdershins `package.json`
5 changes: 5 additions & 0 deletions docs/scripts/http-routes-templates/authentication.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
{{= data.utils.getAuthenticationStr(data) }}
</aside>

3 changes: 3 additions & 0 deletions docs/scripts/http-routes-templates/authentication_none.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<aside class="success">
This operation does not require authentication
</aside>
38 changes: 38 additions & 0 deletions docs/scripts/http-routes-templates/callbacks.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{? typeof data.operation.callbacks === 'object'}}

### Callbacks

{{ data.operationStack.push(data.operation); }}

{{ for (var c of Object.keys(data.operation.callbacks)) { }}

#### {{=c}}

{{ var callback = data.operation.callbacks && data.operation.callbacks[c]; }}

{{ for (var e in callback) { }}
{{ if (!e.startsWith('x-widdershins-')) { }}

**{{=e}}**

{{ var exp = callback[e]; }}

{{ for (var m in exp) { }}

{{ data.operation = exp[m]; }}
{{ data.method.operation = data.operation; }}

{{= data.templates.operation(data) }}

{{ } /* of methods */ }}

{{ } /* of expressions */ }}

{{ } /* of if */ }}

{{ } /* of callbacks */ }}

{{ data.operation = data.operationStack.pop(); }}
{{ data.method.operation = data.operation; }}

{{?}}
133 changes: 133 additions & 0 deletions docs/scripts/http-routes-templates/code_csharp.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

/// <<summary>>
/// Example of Http Client
/// <</summary>>
public class HttpExample
{
private HttpClient Client { get; set; }

/// <<summary>>
/// Setup http client
/// <</summary>>
public HttpExample()
{
Client = new HttpClient();
}
{{? data.methodUpper == "GET"}}
/// Make a dummy request
public async Task MakeGetRequest()
{
string url = "{{=data.url}}";
var result = await GetAsync(url);
}

/// Performs a GET Request
public async Task GetAsync(string url)
{
//Start the request
HttpResponseMessage response = await Client.GetAsync(url);

//Validate result
response.EnsureSuccessStatusCode();

}{{? }}
{{? data.methodUpper == "POST"}}
/// Make a dummy request
public async Task MakePostRequest()
{
string url = "{{=data.url}}";
{{? data.bodyParameter.refName !== undefined }}
string json = @"{{=data.bodyParameter.exampleValues.json.replace(new RegExp('"', "g"), '""')}}";
{{=data.bodyParameter.refName}} content = JsonConvert.DeserializeObject(json);
await PostAsync(content, url);
{{? }}
{{? data.bodyParameter.refName === undefined }}
await PostAsync(null, url);
{{? }}
}
/// Performs a POST Request
public async Task PostAsync({{=data.bodyParameter.refName}} content, string url)
{
//Serialize Object
StringContent jsonContent = SerializeObject(content);
//Execute POST request
HttpResponseMessage response = await Client.PostAsync(url, jsonContent);
}{{? }}
{{? data.methodUpper == "PUT"}}
/// Make a dummy request
public async Task MakePutRequest()
{
int id = 1;
string url = "{{=data.url}}";
{{? data.bodyParameter.refName !== undefined }}
string json = @"{{=data.bodyParameter.exampleValues.json.replace(new RegExp('"', "g"), '""')}}";
{{=data.bodyParameter.refName}} content = JsonConvert.DeserializeObject(json);
var result = await PutAsync(id, content, url);
{{? }}
{{? data.bodyParameter.refName === undefined }}
var result = await PutAsync(id, null, url);
{{? }}
}

/// Performs a PUT Request
public async Task PutAsync(int id, {{=data.bodyParameter.refName}} content, string url)
{
//Serialize Object
StringContent jsonContent = SerializeObject(content);

//Execute PUT request
HttpResponseMessage response = await Client.PutAsync(url + $"/{id}", jsonContent);

//Return response
return await DeserializeObject(response);
}{{? }}
{{? data.methodUpper == "DELETE"}}
/// Make a dummy request
public async Task MakeDeleteRequest()
{
int id = 1;
string url = "{{=data.url}}";

await DeleteAsync(id, url);
}

/// Performs a DELETE Request
public async Task DeleteAsync(int id, string url)
{
//Execute DELETE request
HttpResponseMessage response = await Client.DeleteAsync(url + $"/{id}");

//Return response
await DeserializeObject(response);
}{{? }}
{{? data.methodUpper == "POST" || data.methodUpper == "PUT"}}
/// Serialize an object to Json
private StringContent SerializeObject({{=data.bodyParameter.refName}} content)
{
//Serialize Object
string jsonObject = JsonConvert.SerializeObject(content);

//Create Json UTF8 String Content
return new StringContent(jsonObject, Encoding.UTF8, "application/json");
}
{{? }}
/// Deserialize object from request response
private async Task DeserializeObject(HttpResponseMessage response)
{
//Read body
string responseBody = await response.Content.ReadAsStringAsync();

//Deserialize Body to object
var result = JsonConvert.DeserializeObject(responseBody);
}
}
23 changes: 23 additions & 0 deletions docs/scripts/http-routes-templates/code_go.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"bytes"
"net/http"
)

func main() {

{{?data.allHeaders.length}}
headers := map[string][]string{
{{~data.allHeaders :p:index}}"{{=p.name}}": []string{"{{=p.exampleValues.object}}"},{{?index < data.allHeaders.length-1}}
{{?}}{{~}}
}{{?}}

data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("{{=data.methodUpper}}", "{{=data.url}}", data)
req.Header = headers

client := &http.Client{}
resp, err := client.Do(req)
// ...
}
7 changes: 7 additions & 0 deletions docs/scripts/http-routes-templates/code_http.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{=data.methodUpper}} {{=data.url}}{{=data.requiredQueryString}} HTTP/1.1
{{? data.host}}Host: {{=data.host}}{{?}}
{{?data.consumes.length}}Content-Type: {{=data.consumes[0]}}
{{?}}{{?data.produces.length}}Accept: {{=data.produces[0]}}{{?}}
{{?data.headerParameters.length}}{{~ data.headerParameters :p:index}}{{=p.name}}: {{=p.exampleValues.object}}
{{~}}
{{?}}
13 changes: 13 additions & 0 deletions docs/scripts/http-routes-templates/code_java.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
URL obj = new URL("{{=data.url}}{{=data.requiredQueryString}}");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("{{=data.methodUpper}}");
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
16 changes: 16 additions & 0 deletions docs/scripts/http-routes-templates/code_javascript.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{{?data.bodyParameter.present}}const inputBody = '{{=data.bodyParameter.exampleValues.json}}';{{?}}
{{?data.allHeaders.length}}const headers = {
{{~data.allHeaders :p:index}} '{{=p.name}}':{{=p.exampleValues.json}}{{?index < data.allHeaders.length-1}},{{?}}
{{~}}};
{{?}}
fetch('{{=data.url}}{{=data.requiredQueryString}}',
{
method: '{{=data.methodUpper}}'{{?data.bodyParameter.present || data.allHeaders.length}},{{?}}
{{?data.bodyParameter.present}} body: inputBody{{?}}{{? data.bodyParameter.present && data.allHeaders.length}},{{?}}
{{?data.allHeaders.length}} headers: headers{{?}}
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
14 changes: 14 additions & 0 deletions docs/scripts/http-routes-templates/code_jquery.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{?data.allHeaders.length}}var headers = {
{{~data.allHeaders :p:index}} '{{=p.name}}':{{=p.exampleValues.json}}{{?index < data.allHeaders.length-1}},{{?}}
{{~}}
};
{{?}}
$.ajax({
url: '{{=data.url}}',
method: '{{=data.method.verb}}',
{{?data.requiredQueryString}} data: '{{=data.requiredQueryString}}',{{?}}
{{?data.allHeaders.length}} headers: headers,{{?}}
success: function(data) {
console.log(JSON.stringify(data));
}
})
17 changes: 17 additions & 0 deletions docs/scripts/http-routes-templates/code_nodejs.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const fetch = require('node-fetch');
{{?data.bodyParameter.present}}const inputBody = {{=data.bodyParameter.exampleValues.json}};{{?}}
{{?data.allHeaders.length}}const headers = {
{{~data.allHeaders :p:index}} '{{=p.name}}':{{=p.exampleValues.json}}{{?index < data.allHeaders.length-1}},{{?}}
{{~}}};
{{?}}
fetch('{{=data.url}}{{=data.requiredQueryString}}',
{
method: '{{=data.methodUpper}}'{{?data.bodyParameter.present || data.allHeaders.length}},{{?}}
{{?data.bodyParameter.present}} body: JSON.stringify(inputBody){{?}}{{? data.bodyParameter.present && data.allHeaders.length}},{{?}}
{{?data.allHeaders.length}} headers: headers{{?}}
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
Loading

0 comments on commit 0681c95

Please sign in to comment.