clan-api: wrap all api responses with error/success envelop type
All checks were successful
buildbot/nix-build .#checks.x86_64-linux.clan-dep-bash Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-e2fsprogs Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-fakeroot Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-age Build done.
buildbot/nix-build .#checks.x86_64-linux.check-for-breakpoints Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-ts-api Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli-docs Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.x86_64-linux.borgbackup Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-docs Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-iso-installer Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.renderClanOptions Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-mypy" Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-rsync Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sops Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-openssh Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-docs Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-vm-manager-no-breakpoints Build done.
buildbot/nix-build .#checks.x86_64-linux.treefmt Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-vm-manager-pytest Build done.
buildbot/nix-build .#checks.x86_64-linux.package-deploy-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-vm-manager Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-with-core Build done.
buildbot/nix-build .#checks.x86_64-linux.package-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.package-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-vm-manager Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-without-core Build done.
buildbot/nix-build .#checks.x86_64-linux.test-backups Build done.
buildbot/nix-build .#checks.x86_64-linux.flash Build done.
buildbot/nix-build .#checks.x86_64-linux.test-installation Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sshpass Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-qemu" Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-tor Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-zbar Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-git Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-nix Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-default Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-example-valid Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.container Build done.
buildbot/nix-build .#checks.x86_64-linux.deltachat Build done.
buildbot/nix-build .#checks.x86_64-linux.matrix-synapse Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.package-default Build done.
buildbot/nix-build .#checks.x86_64-linux.package-editor Build done.
buildbot/nix-build .#checks.x86_64-linux.module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-install-test-ubuntu-22-04 Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-apk Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-archlinux Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-deb Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-rpm Build done.
buildbot/nix-build .#checks.x86_64-linux.package-impure-checks Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-nix-unit-tests Build done.
buildbot/nix-build .#checks.x86_64-linux.package-function-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-merge-after-ci Build done.
buildbot/nix-build .#checks.x86_64-linux.package-pending-reviews Build done.
buildbot/nix-build .#checks.x86_64-linux.package-tea-create-pr Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotier-members Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotierone Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-moonlight-sunshine-accept Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.secrets Build done.
buildbot/nix-build .#checks.x86_64-linux.package-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.wayland-proxy-virtwl Build done.
buildbot/nix-build .#checks.x86_64-linux.zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.syncthing Build done.
buildbot/nix-eval Build done.
checks / checks-impure (pull_request) Successful in 2m27s

This commit is contained in:
Johannes Kirschbauer 2024-06-05 09:46:48 +02:00
parent db88e63148
commit 6576290160
Signed by: hsjobeki
SSH Key Fingerprint: SHA256:vX3utDqig7Ph5L0JPv87ZTPb/w7cMzREKVZzzLFg9qU
4 changed files with 72 additions and 15 deletions

View File

@ -1,10 +1,12 @@
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Generic, Literal, TypeVar from functools import wraps
from typing import Annotated, Any, Generic, Literal, TypeVar, get_type_hints
from clan_cli.errors import ClanError
T = TypeVar("T") T = TypeVar("T")
ResponseDataType = TypeVar("ResponseDataType") ResponseDataType = TypeVar("ResponseDataType")
@ -16,22 +18,55 @@ class ApiError:
@dataclass @dataclass
class ApiResponse(Generic[ResponseDataType]): class SuccessDataClass(Generic[ResponseDataType]):
status: Literal["success", "error"] status: Annotated[Literal["success"], "The status of the response."]
errors: list[ApiError] | None data: ResponseDataType
data: ResponseDataType | None
@dataclass
class ErrorDataClass:
status: Literal["error"]
errors: list[ApiError]
ApiResponse = SuccessDataClass[ResponseDataType] | ErrorDataClass
class _MethodRegistry: class _MethodRegistry:
def __init__(self) -> None: def __init__(self) -> None:
self._orig: dict[str, Callable[[Any], Any]] = {}
self._registry: dict[str, Callable[[Any], Any]] = {} self._registry: dict[str, Callable[[Any], Any]] = {}
def register(self, fn: Callable[..., T]) -> Callable[..., T]: def register(self, fn: Callable[..., T]) -> Callable[..., T]:
self._registry[fn.__name__] = fn self._orig[fn.__name__] = fn
@wraps(fn)
def wrapper(*args: Any, **kwargs: Any) -> ApiResponse[T]:
try:
data: T = fn(*args, **kwargs)
return SuccessDataClass(status="success", data=data)
except ClanError as e:
return ErrorDataClass(
status="error",
errors=[
ApiError(
message=e.msg,
description=e.description,
location=[fn.__name__, e.location],
)
],
)
# @wraps preserves all metadata of fn
# we need to update the annotation, because our wrapper changes the return type
# This overrides the new return type annotation with the generic typeVar filled in
orig_return_type = get_type_hints(fn).get("return")
wrapper.__annotations__["return"] = ApiResponse[orig_return_type] # type: ignore
self._registry[fn.__name__] = wrapper
return fn return fn
def to_json_schema(self) -> dict[str, Any]: def to_json_schema(self) -> dict[str, Any]:
# Import only when needed
from typing import get_type_hints from typing import get_type_hints
from clan_cli.api.util import type_to_dict from clan_cli.api.util import type_to_dict

View File

@ -8,9 +8,8 @@ import {
import { OperationResponse, pyApi } from "./message"; import { OperationResponse, pyApi } from "./message";
export const makeCountContext = () => { export const makeCountContext = () => {
const [machines, setMachines] = createSignal< const [machines, setMachines] =
OperationResponse<"list_machines"> createSignal<OperationResponse<"list_machines">>();
>([]);
const [loading, setLoading] = createSignal(false); const [loading, setLoading] = createSignal(false);
pyApi.list_machines.receive((machines) => { pyApi.list_machines.receive((machines) => {
@ -41,7 +40,7 @@ export const CountContext = createContext<CountContextType>([
loading: () => false, loading: () => false,
// eslint-disable-next-line // eslint-disable-next-line
machines: () => ([]), machines: () => undefined,
}, },
{ {
// eslint-disable-next-line // eslint-disable-next-line

View File

@ -72,6 +72,12 @@ const deserialize =
// Create the API object // Create the API object
const pyApi: PyApi = {} as PyApi; const pyApi: PyApi = {} as PyApi;
pyApi.create_clan.receive((r) => {
if (r.status === "success") {
r.status;
}
});
operationNames.forEach((opName) => { operationNames.forEach((opName) => {
const name = opName as OperationNames; const name = opName as OperationNames;
// @ts-expect-error - TODO: Fix this. Typescript is not recognizing the receive function correctly // @ts-expect-error - TODO: Fix this. Typescript is not recognizing the receive function correctly

View File

@ -1,13 +1,30 @@
import { For, Match, Switch, createEffect, type Component } from "solid-js"; import {
For,
Match,
Switch,
createEffect,
createSignal,
type Component,
} from "solid-js";
import { useCountContext } from "../../Config"; import { useCountContext } from "../../Config";
import { route } from "@/src/App"; import { route } from "@/src/App";
export const MachineListView: Component = () => { export const MachineListView: Component = () => {
const [{ machines, loading }, { getMachines }] = useCountContext(); const [{ machines, loading }, { getMachines }] = useCountContext();
const [data, setData] = createSignal<string[]>([]);
createEffect(() => { createEffect(() => {
if (route() === "machines") getMachines(); if (route() === "machines") getMachines();
}); });
createEffect(() => {
const response = machines();
if (response?.status === "success") {
console.log(response.data);
setData(response.data);
}
});
return ( return (
<div class="max-w-screen-lg"> <div class="max-w-screen-lg">
<div class="tooltip" data-tip="Refresh "> <div class="tooltip" data-tip="Refresh ">
@ -32,12 +49,12 @@ export const MachineListView: Component = () => {
</div> </div>
</div> </div>
</Match> </Match>
<Match when={!loading() && machines().length === 0}> <Match when={!loading() && data().length === 0}>
No machines found No machines found
</Match> </Match>
<Match when={!loading()}> <Match when={!loading()}>
<ul> <ul>
<For each={machines()}> <For each={data()}>
{(entry) => ( {(entry) => (
<li> <li>
<div class="card card-side m-2 bg-base-100 shadow-lg"> <div class="card card-side m-2 bg-base-100 shadow-lg">