From a5ab2acca059799919943b1094a45300d70a39fa Mon Sep 17 00:00:00 2001 From: Natty Date: Fri, 3 Nov 2023 21:14:17 +0100 Subject: [PATCH] TS_RS Rust and TypeScript types should now be in parity --- .../frontend/magnetar-common/src/be-api.ts | 64 ++++++++++++------- .../src/types/GetTimelineReq.ts | 2 +- .../magnetar-common/src/types/NoteByIdReq.ts | 2 +- .../src/types/NoteDetailExt.ts | 4 ++ .../magnetar-common/src/types/UserByIdReq.ts | 2 +- .../magnetar-common/src/types/UserSelfReq.ts | 2 +- .../src/types/endpoints/GetNoteById.ts | 11 ++-- .../src/types/endpoints/GetTimeline.ts | 15 ++--- .../src/types/endpoints/GetUserByAcct.ts | 12 ++-- .../src/types/endpoints/GetUserById.ts | 12 ++-- .../src/types/endpoints/GetUserSelf.ts | 12 ++-- magnetar_sdk/macros/src/lib.rs | 13 ++-- magnetar_sdk/src/endpoints/note.rs | 8 +-- magnetar_sdk/src/endpoints/timeline.rs | 9 +-- magnetar_sdk/src/endpoints/user.rs | 36 +++++------ src/api_v1/note.rs | 4 +- 16 files changed, 116 insertions(+), 92 deletions(-) create mode 100644 fe_calckey/frontend/magnetar-common/src/types/NoteDetailExt.ts diff --git a/fe_calckey/frontend/magnetar-common/src/be-api.ts b/fe_calckey/frontend/magnetar-common/src/be-api.ts index 063c0cc..620c062 100644 --- a/fe_calckey/frontend/magnetar-common/src/be-api.ts +++ b/fe_calckey/frontend/magnetar-common/src/be-api.ts @@ -1,12 +1,16 @@ -import {FrontendApiEndpoint, FrontendApiEndpoints} from "./fe-api"; -import {GetNoteById} from "./types/endpoints/GetNoteById"; +import { GetNoteById } from "./types/endpoints/GetNoteById"; type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; -export interface BackendApiEndpoint { +export interface BackendApiEndpoint< + M extends Method, + PP extends string[], + T, + R +> { method: M; endpoint: string; - pathParams: [string], + pathParams: PP; request?: T; response?: R; } @@ -18,21 +22,22 @@ function nestedUrlSearchParams(data: any, topLevel: boolean = true): string { case "boolean": case "number": case "symbol": - if (topLevel) - return encodeURIComponent(data.toString()) + "="; + if (topLevel) return encodeURIComponent(data.toString()) + "="; return data.toString(); case "object": - if (data === null) - return "null"; + if (data === null) return "null"; if (Array.isArray(data)) - return data.map(d => nestedUrlSearchParams(d, true)) + return data + .map((d) => nestedUrlSearchParams(d, true)) .map(encodeURIComponent) .join("&"); - const inner = Object.entries(data) - .map(([k, v]) => [k, nestedUrlSearchParams(v, false)]); + const inner = Object.entries(data).map(([k, v]) => [ + k, + nestedUrlSearchParams(v, false), + ]); return new URLSearchParams(inner).toString(); @@ -45,8 +50,8 @@ type MagApiErrorCode = "Client:GenericApiError" | string; export interface MagApiError { status: number; - code: MagApiErrorCode, - message: string, + code: MagApiErrorCode; + message: string; } export class MagApiClient { @@ -56,11 +61,21 @@ export class MagApiClient { this.baseUrl = baseUrl; } - async call>( - endpoint: T["endpoint"], - method: M, + async call< + T extends BackendApiEndpoint< + T["method"] & Method, + T["pathParams"] & string[], + T["request"], + T["response"] + > + >( + { endpoint, method }: T, data: T["request"], - pathParams: Record, + pathParams: { + [K in keyof T["pathParams"] as T["pathParams"][K] & string]: + | string + | number; + }, token?: string | null | undefined ): Promise { type Response = T["response"]; @@ -70,6 +85,10 @@ export class MagApiClient { ? `Bearer ${authorizationToken}` : undefined; + for (const name in pathParams) { + endpoint = endpoint.replace(`:${name}`, `${pathParams[name]}`); + } + let url = `${this.baseUrl}/${endpoint}`; if (method === "GET") { @@ -84,7 +103,7 @@ export class MagApiClient { body: method !== "GET" ? JSON.stringify(data) : undefined, credentials: "omit", cache: "no-cache", - headers: authorization ? {authorization} : {}, + headers: authorization ? { authorization } : {}, }) .then(async (res) => { const body = res.status === 204 ? null : await res.json(); @@ -98,15 +117,14 @@ export class MagApiClient { } }) .catch((e) => { - throw ({ + throw { status: -1, code: "Client:GenericApiError", - message: e - }) as MagApiError; + message: e, + } as MagApiError; }); } } - const a = new MagApiClient("https://aaa"); -a.call<"GET", GetNoteById>("", "",{}, {}) +const result = await a.call(GetNoteById, { attachments: true }, { id: "aaaa" }); diff --git a/fe_calckey/frontend/magnetar-common/src/types/GetTimelineReq.ts b/fe_calckey/frontend/magnetar-common/src/types/GetTimelineReq.ts index f084102..00b3b07 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/GetTimelineReq.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/GetTimelineReq.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { NoteListFilter } from "./NoteListFilter"; -export interface GetTimelineReq { limit: bigint, filter: NoteListFilter | null, } \ No newline at end of file +export interface GetTimelineReq { limit?: bigint, filter?: NoteListFilter, } \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/NoteByIdReq.ts b/fe_calckey/frontend/magnetar-common/src/types/NoteByIdReq.ts index afa4fa8..89c08ba 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/NoteByIdReq.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/NoteByIdReq.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export interface NoteByIdReq { context: boolean, attachments: boolean, } \ No newline at end of file +export interface NoteByIdReq { context?: boolean, attachments?: boolean, } \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/NoteDetailExt.ts b/fe_calckey/frontend/magnetar-common/src/types/NoteDetailExt.ts new file mode 100644 index 0000000..3482627 --- /dev/null +++ b/fe_calckey/frontend/magnetar-common/src/types/NoteDetailExt.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackNoteMaybeAttachments } from "./packed/PackNoteMaybeAttachments"; + +export interface NoteDetailExt { parent_note: PackNoteMaybeAttachments | null, renoted_note: PackNoteMaybeAttachments | null, } \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/UserByIdReq.ts b/fe_calckey/frontend/magnetar-common/src/types/UserByIdReq.ts index 1da49a6..91ba28b 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/UserByIdReq.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/UserByIdReq.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export interface UserByIdReq { profile: boolean, pins: boolean, detail: boolean, relation: boolean, auth: boolean, } \ No newline at end of file +export interface UserByIdReq { profile?: boolean, pins?: boolean, detail?: boolean, relation?: boolean, auth?: boolean, } \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/UserSelfReq.ts b/fe_calckey/frontend/magnetar-common/src/types/UserSelfReq.ts index b0527fc..20202e8 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/UserSelfReq.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/UserSelfReq.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export interface UserSelfReq { profile: boolean, pins: boolean, detail: boolean, secrets: boolean, } \ No newline at end of file +export interface UserSelfReq { profile?: boolean, pins?: boolean, detail?: boolean, secrets?: boolean, } \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetNoteById.ts b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetNoteById.ts index 6c96a1f..d292e2f 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetNoteById.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetNoteById.ts @@ -2,10 +2,11 @@ import type { NoteByIdReq } from "../NoteByIdReq"; import type { PackNoteMaybeFull } from "../packed/PackNoteMaybeFull"; -interface GetNoteById { +export const GetNoteById = { endpoint: "/notes/:id", - pathParams: ["id"], - method: "GET", - request: NoteByIdReq, - response: PackNoteMaybeFull + pathParams: ["id"] as ["id"], + method: "GET" as "GET" | "POST" | "PUT" | "DELETE" | "PATCH", + request: undefined as unknown as NoteByIdReq, + response: undefined as unknown as PackNoteMaybeFull } + \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetTimeline.ts b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetTimeline.ts index 6ef7183..148c7a3 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetTimeline.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetTimeline.ts @@ -2,11 +2,10 @@ import type { GetTimelineReq } from "../GetTimelineReq"; import type { PackNoteMaybeFull } from "../packed/PackNoteMaybeFull"; -export interface GetTimeline { - endpoint: "/timeline"; - pathParams: []; - method: "GET"; - request: GetTimelineReq; - response: Array; -} - \ No newline at end of file +export const GetTimeline = { + endpoint: "/timeline", + pathParams: [] as [], + method: "GET" as "GET" | "POST" | "PUT" | "DELETE" | "PATCH", + request: undefined as unknown as GetTimelineReq, + response: undefined as unknown as Array, +}; diff --git a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserByAcct.ts b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserByAcct.ts index 5846031..561116a 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserByAcct.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserByAcct.ts @@ -2,11 +2,11 @@ import type { PackUserMaybeAll } from "../packed/PackUserMaybeAll"; import type { UserByIdReq } from "../UserByIdReq"; -export interface GetUserByAcct { - endpoint: "/users/by-acct/:user_id"; - pathParams: ["user_id"]; - method: "GET"; - request: UserByIdReq; - response: PackUserMaybeAll; +export const GetUserByAcct = { + endpoint: "/users/by-acct/:user_id", + pathParams: ["user_id"] as ["user_id"], + method: "GET" as "GET" | "POST" | "PUT" | "DELETE" | "PATCH", + request: undefined as unknown as UserByIdReq, + response: undefined as unknown as PackUserMaybeAll } \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserById.ts b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserById.ts index b951f3f..fd203be 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserById.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserById.ts @@ -2,11 +2,11 @@ import type { PackUserMaybeAll } from "../packed/PackUserMaybeAll"; import type { UserByIdReq } from "../UserByIdReq"; -export interface GetUserById { - endpoint: "/users/:user_id"; - pathParams: ["user_id"]; - method: "GET"; - request: UserByIdReq; - response: PackUserMaybeAll; +export const GetUserById = { + endpoint: "/users/:user_id", + pathParams: ["user_id"] as ["user_id"], + method: "GET" as "GET" | "POST" | "PUT" | "DELETE" | "PATCH", + request: undefined as unknown as UserByIdReq, + response: undefined as unknown as PackUserMaybeAll } \ No newline at end of file diff --git a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserSelf.ts b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserSelf.ts index 2702509..40303ef 100644 --- a/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserSelf.ts +++ b/fe_calckey/frontend/magnetar-common/src/types/endpoints/GetUserSelf.ts @@ -2,11 +2,11 @@ import type { PackUserSelfMaybeAll } from "../packed/PackUserSelfMaybeAll"; import type { UserSelfReq } from "../UserSelfReq"; -export interface GetUserSelf { - endpoint: "/users/@self"; - pathParams: []; - method: "GET"; - request: UserSelfReq; - response: PackUserSelfMaybeAll; +export const GetUserSelf = { + endpoint: "/users/@self", + pathParams: [] as [], + method: "GET" as "GET" | "POST" | "PUT" | "DELETE" | "PATCH", + request: undefined as unknown as UserSelfReq, + response: undefined as unknown as PackUserSelfMaybeAll } \ No newline at end of file diff --git a/magnetar_sdk/macros/src/lib.rs b/magnetar_sdk/macros/src/lib.rs index be482da..a323b44 100644 --- a/magnetar_sdk/macros/src/lib.rs +++ b/magnetar_sdk/macros/src/lib.rs @@ -356,17 +356,18 @@ pub fn derive_endpoint(item: TokenStream) -> TokenStream { fn decl() -> String { format!( - "interface {} {{\n \ - endpoint: \"{}\";\n \ - pathParams: {};\n \ - method: \"{}\";\n \ - request: {};\n \ - response: {};\n\ + "const {} = {{\n \ + endpoint: \"{}\",\n \ + pathParams: {} as {},\n \ + method: \"{}\" as \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\",\n \ + request: undefined as unknown as {},\n \ + response: undefined as unknown as {}\n\ }} ", Self::name(), Self::ENDPOINT, #path_params, + #path_params, Self::METHOD, #call_name_req, #call_name_res diff --git a/magnetar_sdk/src/endpoints/note.rs b/magnetar_sdk/src/endpoints/note.rs index a80671a..fe52f99 100644 --- a/magnetar_sdk/src/endpoints/note.rs +++ b/magnetar_sdk/src/endpoints/note.rs @@ -9,10 +9,10 @@ use ts_rs::TS; #[derive(Serialize, Deserialize, TS)] #[ts(export)] pub struct NoteByIdReq { - #[serde(default)] - pub context: bool, - #[serde(default)] - pub attachments: bool, + #[ts(optional)] + pub context: Option, + #[ts(optional)] + pub attachments: Option, } #[derive(Endpoint)] diff --git a/magnetar_sdk/src/endpoints/timeline.rs b/magnetar_sdk/src/endpoints/timeline.rs index 680097f..d1e7c1e 100644 --- a/magnetar_sdk/src/endpoints/timeline.rs +++ b/magnetar_sdk/src/endpoints/timeline.rs @@ -10,13 +10,14 @@ use ts_rs::TS; #[derive(Serialize, Deserialize, TS)] #[ts(export)] pub struct GetTimelineReq { - #[serde(default = "default_timeline_limit")] - pub limit: U64Range<1, 100>, + #[ts(optional)] + pub limit: Option>, + #[ts(optional)] pub filter: Option, } -fn default_timeline_limit() -> U64Range { - 15.try_into().unwrap() +pub fn default_timeline_limit() -> U64Range { + 30.try_into().unwrap() } #[derive(Endpoint)] diff --git a/magnetar_sdk/src/endpoints/user.rs b/magnetar_sdk/src/endpoints/user.rs index 5c89be0..436715f 100644 --- a/magnetar_sdk/src/endpoints/user.rs +++ b/magnetar_sdk/src/endpoints/user.rs @@ -10,14 +10,14 @@ use crate::types::user::{PackUserMaybeAll, PackUserSelfMaybeAll}; #[derive(Serialize, Deserialize, TS)] #[ts(export)] pub struct UserSelfReq { - #[serde(default)] - pub profile: bool, - #[serde(default)] - pub pins: bool, - #[serde(default)] - pub detail: bool, - #[serde(default)] - pub secrets: bool, + #[ts(optional)] + pub profile: Option, + #[ts(optional)] + pub pins: Option, + #[ts(optional)] + pub detail: Option, + #[ts(optional)] + pub secrets: Option, } #[derive(Endpoint)] @@ -33,16 +33,16 @@ pub struct GetUserSelf; #[derive(Serialize, Deserialize, TS)] #[ts(export)] pub struct UserByIdReq { - #[serde(default)] - pub profile: bool, - #[serde(default)] - pub pins: bool, - #[serde(default)] - pub detail: bool, - #[serde(default)] - pub relation: bool, - #[serde(default)] - pub auth: bool, + #[ts(optional)] + pub profile: Option, + #[ts(optional)] + pub pins: Option, + #[ts(optional)] + pub detail: Option, + #[ts(optional)] + pub relation: Option, + #[ts(optional)] + pub auth: Option, } #[derive(Endpoint)] diff --git a/src/api_v1/note.rs b/src/api_v1/note.rs index d27d453..b2ca4e0 100644 --- a/src/api_v1/note.rs +++ b/src/api_v1/note.rs @@ -22,8 +22,8 @@ pub async fn handle_note( ) -> Result>, ApiError> { let ctx = PackingContext::new(service, self_user.clone()).await?; let note = NoteModel { - attachments, - with_context: context, + attachments: attachments.unwrap_or_default(), + with_context: context.unwrap_or_default(), } .fetch_single(&ctx, self_user.as_deref(), &id) .await?