Verified Commit df0a4a2b authored by Kevin Morris's avatar Kevin Morris
Browse files

feat(rpc): add /rpc/v5/{type} openapi-compatible routes



We will be modeling future RPC implementations on an OpenAPI spec.
While this commit does not completely cohere to OpenAPI in terms
of response data, this is a good start and will allow us to cleanly
document these openapi routes in the current and future.

This commit brings in the new RPC routes:
- GET /rpc/v5/info/{pkgname}
- GET /rpc/v5/info?arg[]=pkg1&arg[]=pkg2
- POST /rpc/v5/info with JSON data `{"arg": ["pkg1", "pkg2"]}`
- GET /rpc/v5/search?arg=keywords&by=valid-by-value
- POST /rpc/v5/search with JSON data `{"by": "valid-by-value", "arg": "keywords"}`

Signed-off-by: Kevin Morris's avatarKevin Morris <kevr@0cost.org>
parent bb6e602e
Pipeline #28795 passed with stages
in 2 minutes and 7 seconds
......@@ -160,3 +160,107 @@ async def rpc_post(
callback: Optional[str] = Form(default=None),
):
return await rpc_request(request, v, type, by, arg, args, callback)
@router.get("/rpc/v{version}/info/{name}")
async def rpc_openapi_info(request: Request, version: int, name: str):
return await rpc_request(
request,
version,
"info",
defaults.RPC_SEARCH_BY,
name,
[],
)
@router.get("/rpc/v{version}/info")
async def rpc_openapi_multiinfo(
request: Request,
version: int,
args: Optional[list[str]] = Query(default=[], alias="arg[]"),
):
arg = args.pop(0) if args else None
return await rpc_request(
request,
version,
"info",
defaults.RPC_SEARCH_BY,
arg,
args,
)
@router.post("/rpc/v{version}/info")
async def rpc_openapi_multiinfo_post(
request: Request,
version: int,
):
data = await request.json()
args = data.get("arg", [])
if not isinstance(args, list):
rpc = RPC(version, "info")
return JSONResponse(
rpc.error("the 'arg' parameter must be of array type"),
status_code=HTTPStatus.BAD_REQUEST,
)
arg = args.pop(0) if args else None
return await rpc_request(
request,
version,
"info",
defaults.RPC_SEARCH_BY,
arg,
args,
)
@router.get("/rpc/v{version}/search")
async def rpc_openapi_search(
request: Request,
version: int,
by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY),
arg: Optional[str] = Query(default=str()),
):
return await rpc_request(
request,
version,
"search",
by,
arg,
[],
)
@router.post("/rpc/v{version}/search")
async def rpc_openapi_search_post(
request: Request,
version: int,
):
data = await request.json()
by = data.get("by", defaults.RPC_SEARCH_BY)
if not isinstance(by, str):
rpc = RPC(version, "search")
return JSONResponse(
rpc.error("the 'by' parameter must be of string type"),
status_code=HTTPStatus.BAD_REQUEST,
)
arg = data.get("arg", str())
if not isinstance(arg, str):
rpc = RPC(version, "search")
return JSONResponse(
rpc.error("the 'arg' parameter must be of string type"),
status_code=HTTPStatus.BAD_REQUEST,
)
return await rpc_request(
request,
version,
"search",
by,
arg,
[],
)
......@@ -933,3 +933,98 @@ def test_rpc_too_many_info_results(client: TestClient, packages: list[Package]):
with client as request:
resp = request.get("/rpc", params=params)
assert resp.json().get("error") == "Too many package results."
def test_rpc_openapi_info(client: TestClient, packages: list[Package]):
pkgname = packages[0].Name
with client as request:
endp = f"/rpc/v5/info/{pkgname}"
resp = request.get(endp)
assert resp.status_code == HTTPStatus.OK
data = resp.json()
assert data.get("resultcount") == 1
def test_rpc_openapi_multiinfo(client: TestClient, packages: list[Package]):
pkgname = packages[0].Name
with client as request:
endp = "/rpc/v5/info"
resp = request.get(endp, params={"arg[]": [pkgname]})
assert resp.status_code == HTTPStatus.OK
data = resp.json()
assert data.get("resultcount") == 1
def test_rpc_openapi_multiinfo_post(client: TestClient, packages: list[Package]):
pkgname = packages[0].Name
with client as request:
endp = "/rpc/v5/info"
resp = request.post(endp, json={"arg": [pkgname]})
assert resp.status_code == HTTPStatus.OK
data = resp.json()
assert data.get("resultcount") == 1
def test_rpc_openapi_multiinfo_post_bad_request(
client: TestClient, packages: list[Package]
):
pkgname = packages[0].Name
with client as request:
endp = "/rpc/v5/info"
resp = request.post(endp, json={"arg": pkgname})
assert resp.status_code == HTTPStatus.BAD_REQUEST
data = resp.json()
expected = "the 'arg' parameter must be of array type"
assert data.get("error") == expected
def test_rpc_openapi_search(client: TestClient, packages: list[Package]):
pkgname = packages[0].Name
with client as request:
endp = "/rpc/v5/search"
resp = request.get(endp, params={"arg": pkgname})
assert resp.status_code == HTTPStatus.OK
data = resp.json()
assert data.get("resultcount") == 1
def test_rpc_openapi_search_post(client: TestClient, packages: list[Package]):
pkgname = packages[0].Name
with client as request:
endp = "/rpc/v5/search"
resp = request.post(endp, json={"arg": pkgname})
assert resp.status_code == HTTPStatus.OK
data = resp.json()
assert data.get("resultcount") == 1
def test_rpc_openapi_search_post_bad_request(client: TestClient):
# Test by parameter
with client as request:
endp = "/rpc/v5/search"
resp = request.post(endp, json={"by": 1})
assert resp.status_code == HTTPStatus.BAD_REQUEST
data = resp.json()
expected = "the 'by' parameter must be of string type"
assert data.get("error") == expected
# Test arg parameter
with client as request:
endp = "/rpc/v5/search"
resp = request.post(endp, json={"arg": ["a", "list"]})
assert resp.status_code == HTTPStatus.BAD_REQUEST
data = resp.json()
expected = "the 'arg' parameter must be of string type"
assert data.get("error") == expected
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment