Skip to content

Commit

Permalink
API spec
Browse files Browse the repository at this point in the history
  • Loading branch information
kohler committed Sep 27, 2024
1 parent c46f255 commit 893e408
Show file tree
Hide file tree
Showing 10 changed files with 597 additions and 242 deletions.
101 changes: 77 additions & 24 deletions batch/apispec.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ function run() {
if (!is_object($xj)) {
continue;
}
if ($xj->summary === $pj->__path
if (($xj->summary ?? "") === $pj->__path
&& !isset($xj->description)
&& !isset($xj->operationId)) {
unset($xj->summary);
Expand Down Expand Up @@ -377,7 +377,7 @@ private function merge_description($name, $xj) {

/** @param string $name
* @return object */
private function resolve_common_schema($name) {
private function reference_common_schema($name) {
if ($this->schemas === null) {
$compj = $this->j->components = $this->j->components ?? (object) [];
$this->schemas = $compj->schemas = $compj->schemas ?? (object) [];
Expand Down Expand Up @@ -415,7 +415,7 @@ private function resolve_common_schema($name) {
$nj = (object) [
"type" => "list",
"description" => "Diagnostic list",
"items" => $this->resolve_common_schema("message")
"items" => $this->reference_common_schema("message")
];
} else if ($name === "message") {
$nj = (object) [
Expand All @@ -437,7 +437,7 @@ private function resolve_common_schema($name) {
"required" => ["ok"],
"properties" => (object) [
"ok" => (object) ["type" => "boolean"],
"message_list" => $this->resolve_common_schema("message_list")
"message_list" => $this->reference_common_schema("message_list")
]
];
} else if ($name === "error_response") {
Expand All @@ -446,7 +446,7 @@ private function resolve_common_schema($name) {
"required" => ["ok"],
"properties" => (object) [
"ok" => (object) ["type" => "boolean", "description" => "always false"],
"message_list" => $this->resolve_common_schema("message_list"),
"message_list" => $this->reference_common_schema("message_list"),
"status_code" => (object) ["type" => "integer"]
]
];
Expand All @@ -464,7 +464,7 @@ private function resolve_common_schema($name) {

/** @param string $name
* @return object */
private function resolve_common_param($name) {
private function reference_common_param($name) {
if ($this->parameters === null) {
$compj = $this->j->components = $this->j->components ?? (object) [];
$this->parameters = $compj->parameters = $compj->parameters ?? (object) [];
Expand All @@ -476,28 +476,28 @@ private function resolve_common_param($name) {
"name" => "p",
"in" => "path",
"required" => true,
"schema" => $this->resolve_common_schema("pid")
"schema" => $this->reference_common_schema("pid")
];
} else if ($name === "p" || $name === "p.opt") {
$nj = (object) [
"name" => "p",
"in" => "query",
"required" => $name === "p",
"schema" => $this->resolve_common_schema("pid")
"schema" => $this->reference_common_schema("pid")
];
} else if ($name === "r" || $name === "r.opt") {
$nj = (object) [
"name" => "r",
"in" => "query",
"required" => $name === "r",
"schema" => $this->resolve_common_schema("rid")
"schema" => $this->reference_common_schema("rid")
];
} else if ($name === "c" || $name === "c.opt") {
$nj = (object) [
"name" => "c",
"in" => "query",
"required" => $name === "c",
"schema" => $this->resolve_common_schema("cid")
"schema" => $this->reference_common_schema("cid")
];
} else if ($name === "redirect") {
$nj = (object) [
Expand All @@ -518,6 +518,31 @@ private function resolve_common_param($name) {
return (object) ["\$ref" => "#/components/parameters/{$name}"];
}

/** @param object $ref
* @param ?string $component
* @return ?object */
private function resolve_reference($ref, $component = null) {
if (!is_object($ref)
|| !isset($ref->{"\$ref"})
|| !is_string($ref->{"\$ref"})
|| !str_starts_with($ref->{"\$ref"}, "#/")) {
return null;
}
if ($component !== null
&& !str_starts_with($ref->{"\$ref"}, "#/components/{$component}/")) {
return null;
}
$j = $this->j;
foreach (explode("/", substr($ref->{"\$ref"}, 2)) as $pathpart) {
if (!is_object($j)
|| !isset($j->{$pathpart})) {
return null;
}
$j = $j->{$pathpart};
}
return $j;
}

/** @param object $x
* @param array<string,int> $known
* @param object $uf
Expand All @@ -534,15 +559,15 @@ private function expand_request($x, $known, $uf, $path) {
} else {
$pn = $f & self::F_REQUIRED ? "p" : "p.opt";
}
$params["p"] = $this->resolve_common_param($pn);
$params["p"] = $this->reference_common_param($pn);
} else if ($name === "r") {
$pn = $f & self::F_REQUIRED ? "r" : "r.opt";
$params["r"] = $this->resolve_common_param($pn);
$params["r"] = $this->reference_common_param($pn);
} else if ($name === "c") {
$pn = $f & self::F_REQUIRED ? "c" : "c.opt";
$params["c"] = $this->resolve_common_param($pn);
$params["c"] = $this->reference_common_param($pn);
} else if ($name === "redirect" && $f === 0) {
$params["redirect"] = $this->resolve_common_param("redirect");
$params["redirect"] = $this->reference_common_param("redirect");
} else if (($f & (self::F_BODY | self::F_FILE)) === 0) {
$ps = $uf->parameter_info->$name ?? null;
$params[$name] = (object) [
Expand Down Expand Up @@ -675,7 +700,7 @@ private function apply_response($x, $bprop, $breq) {
"description" => "",
"content" => (object) [
"application/json" => (object) [
"schema" => $this->resolve_common_schema("error_response")
"schema" => $this->reference_common_schema("error_response")
]
]
];
Expand All @@ -684,13 +709,12 @@ private function apply_response($x, $bprop, $breq) {
$resp200->description = $resp200->description ?? "";
$respc = $resp200->content = $resp200->content ?? (object) [];
$respj = $respc->{"application/json"} = $respc->{"application/json"} ?? (object) [];
$resps = $respj->{"schema"} = $respj->{"schema"} ?? $this->resolve_common_schema("minimal_response");
$resps = $respj->{"schema"} = $respj->{"schema"} ?? $this->reference_common_schema("minimal_response");

if (($resps->{"\$ref"} ?? null) === "#/components/schemas/minimal_response") {
$respstype = 0;
} else if (is_array($resps->allOf ?? null)
&& count($resps->allOf) === 2
&& ($resps->allof[1]->type ?? null) === "object") {
&& self::allOf_object_position($resps->allOf) >= 0) {
$respstype = 1;
} else {
$respstype = -1;
Expand All @@ -703,20 +727,33 @@ private function apply_response($x, $bprop, $breq) {

if (!$bprop) {
if ($respstype !== 0) {
$respj->{"schema"} = $this->resolve_common_schema("minimal_response");
$respj->{"schema"} = $this->reference_common_schema("minimal_response");
}
return;
}

if ($respstype <= 0) {
$resps = $respj->{"schema"} = (object) [
"allOf" => [
$this->resolve_common_schema("minimal_response"),
$this->reference_common_schema("minimal_response"),
(object) ["type" => "object"]
]
];
}
$respb = $resps->allOf[1];
$respb = $resps->allOf[self::allOf_object_position($resps->allOf)];

// referenced properties
$knownparam = $knownreq = [];
foreach ($resps->allOf as $respx) {
if (($j = $this->resolve_reference($respx, "schemas"))
&& is_object($j)
&& ($j->type ?? null) === "object") {
foreach ($j->properties as $k => $v) {
$knownparam[$k] = true;
}
$knownreq = array_merge($knownreq, $j->required ?? []);
}
}

// required properties
if ($this->override_response) {
Expand All @@ -728,7 +765,8 @@ private function apply_response($x, $bprop, $breq) {
} else if ($breq) {
$respb->required = $respb->required ?? [];
foreach ($breq as $p) {
if (!in_array($p, $respb->required)) {
if (!in_array($p, $respb->required)
&& !in_array($p, $knownreq)) {
$respb->required[] = $p;
}
}
Expand All @@ -741,8 +779,10 @@ private function apply_response($x, $bprop, $breq) {
$respprop = $respb->properties = $respb->properties ?? (object) [];
}
foreach ($bprop as $k => $v) {
if (!isset($respprop->{$k})
|| empty((array) $respprop->{$k})) {
if (isset($knownparam[$k])) {
continue;
} else if (!isset($respprop->{$k})
|| empty((array) $respprop->{$k})) {
$respprop->$k = $v;
} else {
if (($v->description ?? "") !== ""
Expand All @@ -753,6 +793,19 @@ private function apply_response($x, $bprop, $breq) {
}
}

static private function allOf_object_position($j) {
$found = -1;
foreach ($j as $i => $jx) {
if (($jx->type ?? null) === "object") {
if ($found >= 0) {
return -1;
}
$found = $i;
}
}
return $found;
}

private function sort() {
$this->tag_order = [];
foreach ($this->j->tags ?? [] as $i => $x) {
Expand Down
10 changes: 10 additions & 0 deletions devel/apidoc/redocly.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
apis:
core@v1:
root: ../../etc/openapi.json
rules:
operation-4xx-response: off
operation-operationId: off
no-empty-servers: off
operation-summary: off
tag-description: off
info-license: off

extends:
- recommended

theme:
openapi:
Expand Down
2 changes: 1 addition & 1 deletion devel/apidoc/subadmin.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# post /assign

> Bulk assignments
> Assignments

# get /{p}/decision
Expand Down
7 changes: 6 additions & 1 deletion devel/apidoc/tags.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
> Retrieve submission tags

# post /tags
# post /{p}/tags

> Change submission tags

# post /assigntags

> Change several tags

# get /alltags

> Retrieve all visible tags
Expand Down
12 changes: 9 additions & 3 deletions etc/apifunctions.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
"function": "Assign_API::assign",
"parameters": "?p =assignments"
},
{
"name": "assigntags", "post": true,
"function": "Tags_API::assigntags",
"parameters": "=tagassignment ?=search",
"response": "p ?ids ?groups ?hotlist ?search_params"
},
{
"name": "claimreview", "post": true, "paper": true, "redirect": true,
"function": "RequestReview_API::claimreview",
Expand Down Expand Up @@ -273,10 +279,10 @@
"response": "pid tags tags_edit_text tags_view_html tag_decoration_html color_classes ?tags_conflicted ?color_classes_conflicted"
},
{
"name": "tags", "post": true,
"name": "tags", "post": true, "paper": true,
"function": "Tags_API::run",
"parameters": "?p ?=tags ?=addtags ?=deltags ?=tagassignment ?=search",
"response": "?pid ?tags ?tags_edit_text ?tags_view_html ?tag_decoration_html ?color_classes ?tags_conflicted ?color_classes_conflicted ?p ?ids ?groups ?hotlist ?search_params"
"parameters": "?=tags ?=addtags ?=deltags ?=search",
"response": "pid ?tags ?tags_edit_text ?tags_view_html ?tag_decoration_html ?color_classes ?tags_conflicted ?color_classes_conflicted ?ids ?groups ?hotlist ?search_params"
},
{
"name": "settingdescriptions", "get": true,
Expand Down
Loading

0 comments on commit 893e408

Please sign in to comment.