Start implementing the API documentation and stubs for agent APIs

This commit is contained in:
R Tyler Croy 2023-01-28 15:43:29 -08:00
parent 0e3f874870
commit 5494a54483
No known key found for this signature in database
GPG Key ID: E5C92681BEF6CEA2
21 changed files with 181 additions and 16 deletions

View File

@ -0,0 +1 @@
{"openapi":"3.0.0","info":{"description":"Janky Agent API defintion\n","version":"1.0.0","title":"Janky APIs","contact":{"email":"rtyler+janky@brokenco.de"},"license":{"name":"AGPL v3.0","url":"https://www.gnu.org/licenses/agpl-3.0.en.html"}},"servers":[{"url":"http://localhost:9000/api/v1","description":"Local dev agent (APIv1)"}],"paths":{"/capabilities":{"get":{"summary":"Retrieve a list of capabilities of this agent","description":null,"responses":{"200":{"description":"Getting capabilities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapsResponse"}}}}}}}},"components":{"schemas":{"CapsResponse":{"type":"array","properties":{"caps":{"$ref":"#/components/schemas/Capability"}}},"Capability":{"type":"object","properties":{"name":{"type":"string"},"path":{"type":"string"},"data":{"type":"object"}}}}}}

BIN
apidocs/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

BIN
apidocs/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

60
apidocs/index.html Normal file
View File

@ -0,0 +1,60 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/apidocs/api-description.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>

View File

@ -0,0 +1,72 @@
<!doctype html>
<html lang="en-US">
<title>Swagger UI: OAuth2 Redirect</title>
<body>
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
window.addEventListener('DOMContentLoaded', function () {
run();
});
</script>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
apidocs/swagger-ui.css Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3
apidocs/swagger-ui.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
#!/bin/sh
exec ruby -ryaml -rjson -e 'puts JSON.dump(YAML.load(STDIN.read))' < agent-api-description.yml > apidocs/api-description.json

View File

@ -2,7 +2,6 @@ use dotenv::dotenv;
use log::*;
mod routes {
use tide::{Body, Request};
/**
@ -11,6 +10,18 @@ mod routes {
pub async fn index(_req: Request<()>) -> Result<Body, tide::Error> {
Ok("Hello World from the Janky Agent".into())
}
pub mod api {
use tide::{Body, Request};
pub fn register(app: &mut tide::Server<()>) {
app.at("/api/v1/capabilities").get(get_caps);
}
pub async fn get_caps(_req: Request<()>) -> Result<Body, tide::Error> {
Ok("{}".into())
}
}
}
#[async_std::main]
@ -27,6 +38,7 @@ async fn main() -> Result<(), tide::Error> {
debug!("Configuring routes");
app.at("/").get(routes::index);
routes::api::register(&mut app);
app.listen("0.0.0.0:9000").await?;
Ok(())
}

View File

@ -12,8 +12,7 @@ struct Capability {
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
struct CapsRequest {
}
struct CapsRequest {}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
struct CapsResponse {
@ -37,7 +36,5 @@ struct CommandResponse {
task_url: Url,
}
#[cfg(test)]
mod tests {
}
mod tests {}

View File

@ -58,10 +58,8 @@ impl AppState<'_> {
*/
mod routes {
use crate::AppState;
use tide::{Body, Request};
/**
* GET /
@ -75,12 +73,7 @@ mod routes {
Ok(body)
}
pub mod api {
}
pub mod api {}
}
#[async_std::main]
@ -91,7 +84,8 @@ async fn main() -> Result<(), tide::Error> {
let database_url = std::env::var("DATABASE_URL").unwrap_or(":memory:".to_string());
let pool = SqlitePool::connect(&database_url).await?;
if database_url == ":memory:" {
sqlx::migrate!().run(&pool).await?;
// TODO: Figure out why failing
//sqlx::migrate!().run(&pool).await?;
}
let state = AppState::new(pool);
@ -123,6 +117,7 @@ async fn main() -> Result<(), tide::Error> {
/*
* All builds will have apidocs, since they're handy
*/
app.at("/apidocs").serve_dir("apidocs/")?;
app.at("/static").serve_dir("static/")?;
debug!("Configuring routes");
app.at("/").get(routes::index);