Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: return task either for endpoints rest client methods #1557

Merged
merged 1 commit into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import { fp, pipe } from "@liexp/core/lib/fp/index.js";
import { GetLogger } from "@liexp/core/lib/logger/index.js";
import { useQuery } from "@tanstack/react-query";
import * as R from "fp-ts/lib/Record.js";
import { type TaskEither } from "fp-ts/lib/TaskEither.js";
import {
type InferEndpointParams,
type MinimalEndpoint,
type MinimalEndpointInstance,
} from "ts-endpoint";
import { type serializedType } from "ts-io-error/lib/Codec.js";
import { type EndpointsMapType } from "../../endpoints/Endpoints.js";
import { type APIError } from "../../io/http/Error/APIError.js";
import { throwTE } from "../../utils/task.utils.js";
import {
type EndpointOutput,
type GetFn,
Expand Down Expand Up @@ -53,7 +56,7 @@ export type FetchQuery<FN extends (...args: any[]) => Promise<any>> =
: never;

export const fetchQuery =
<P, Q, R>(q: (p: P, q?: Q) => Promise<R>) =>
<P, Q, R>(q: (p: P, q?: Q) => TaskEither<APIError, R>) =>
async (params: any, query?: any, discrete?: boolean): Promise<R> => {
if (discrete) {
if (
Expand All @@ -64,7 +67,7 @@ export const fetchQuery =
}
}

return q(params, query);
return pipe(q(params, query), throwTE);
};

const toGetResourceQuery = <G>(
Expand All @@ -88,7 +91,7 @@ const toGetResourceQuery = <G>(
Partial<serializedType<InferEndpointParams<G>["query"]>>,
EndpointOutput<G>
> = (params, query) => {
return getFn(params, query);
return pipe(getFn(params, query), throwTE);
};
return {
getKey,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { fp } from "@liexp/core/lib/fp/index.js";
import { useQuery } from "@tanstack/react-query";
import { type TaskEither } from "fp-ts/lib/TaskEither.js";
import { pipe } from "fp-ts/lib/function.js";
import {
type InferEndpointParams,
Expand All @@ -8,6 +9,7 @@ import {
} from "ts-endpoint";
import { type serializedType } from "ts-io-error/lib/Codec.js";
import { type EndpointsMapType } from "../../endpoints/Endpoints.js";
import { type APIError } from "../../io/http/Error/APIError.js";
import {
type EndpointsRESTClient,
type GetFnParams,
Expand All @@ -25,7 +27,7 @@ export interface GetQueryOverride<P, Q = undefined> {

export type CustomQueryOverride<ES extends EndpointsMapType, P, Q, O> = (
q: EndpointsRESTClient<ES>["Endpoints"],
) => (p: P, q: Q) => Promise<O>;
) => (p: P, q: Q) => TaskEither<APIError, O>;

export interface ResourceEndpointsQueriesOverride<
ES extends EndpointsMapType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { fp, pipe } from "@liexp/core/lib/fp/index.js";
import { type MinimalEndpointInstance } from "ts-endpoint";
import { type Endpoints } from "../../endpoints/index.js";
import {
Expand Down Expand Up @@ -38,11 +39,14 @@ const GetPageContentByPath: CustomQueryOverride<
undefined,
GetDataOutputEI<typeof Endpoints.Page.Get>
> = (Q) => (path) => {
return Q.Page.getList({
sort: { field: "createdAt", order: "DESC" },
filter: { path },
pagination: { perPage: 1, page: 1 },
}).then((r) => r.data[0]);
return pipe(
Q.Page.getList({
sort: { field: "createdAt", order: "DESC" },
filter: { path },
pagination: { perPage: 1, page: 1 },
}),
fp.TE.map((r) => r.data[0]),
);
};

const GetByPath: CustomQueryOverride<
Expand All @@ -51,8 +55,9 @@ const GetByPath: CustomQueryOverride<
undefined,
GetDataOutputEI<typeof Endpoints.Story.Get>
> = (Q) => (p) =>
Q.Story.getList({ ...defaultUseQueryListParams, filter: { path: p } }).then(
(r) => r.data[0],
pipe(
Q.Story.getList({ ...defaultUseQueryListParams, filter: { path: p } }),
fp.TE.map((r) => r.data[0]),
);

const PageOverride: ResourceEndpointsQueriesOverride<
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GetLogger } from "@liexp/core/lib/logger/index.js";
import { isAxiosError } from "axios";
import * as A from "fp-ts/lib/Array.js";
import type * as E from "fp-ts/lib/Either.js";
Expand All @@ -21,7 +22,6 @@ import { type ResourceEndpoints } from "../../endpoints/types.js";
import { toAPIError, type APIError } from "../../io/http/Error/APIError.js";
import { type APIRESTClient } from "../../providers/api-rest.provider.js";
import { fromValidationErrors } from "../../providers/http/http.provider.js";
import { throwTE } from "../../utils/task.utils.js";

const toError = (e: unknown): APIError => {
if (isAxiosError(e)) {
Expand Down Expand Up @@ -68,7 +68,7 @@ export type GetEndpointQueryType<G> =

export type EndpointOutput<L> =
InferEndpointParams<L>["output"] extends t.ExactType<infer T>
? t.TypeOf<T>["data"] extends any[]
? t.TypeOf<T>["data"] extends unknown[]
? t.TypeOf<T>
: t.TypeOf<T>["data"]
: never;
Expand All @@ -80,23 +80,23 @@ export type EndpointDataOutput<L> =

export type GetDataOutputEI<L> =
InferEndpointInstanceParams<L>["output"] extends t.ExactType<infer T>
? t.TypeOf<T>["data"] extends any[]
? t.TypeOf<T>["data"] extends unknown[]
? t.TypeOf<T>
: t.TypeOf<T>["data"]
: never;

export type GetFn<G> = (
params: GetFnParams<G>,
query?: Partial<serializedType<InferEndpointParams<G>["query"]>>,
) => Promise<EndpointOutput<G>>;
) => TE.TaskEither<APIError, EndpointOutput<G>>;

export type GetListFnParams<L, O = undefined> = O extends undefined
? Omit<GetListParams, "filter"> & { filter: Partial<GetEndpointQueryType<L>> }
: O;

export type GetListFn<L, O = undefined> = (
params: GetListFnParams<L, O>,
) => Promise<EndpointOutput<L>>;
) => TE.TaskEither<APIError, EndpointOutput<L>>;

export interface Query<G, L, CC> {
get: GetFn<G>;
Expand Down Expand Up @@ -132,7 +132,7 @@ export interface Query<G, L, CC> {
InferEndpointInstanceParams<CC[K]>["body"]
>;
}),
) => Promise<TypeOfEndpointInstance<CC[K]>["Output"]>;
) => TE.TaskEither<APIError, TypeOfEndpointInstance<CC[K]>["Output"]>;
}
: never;
}
Expand Down Expand Up @@ -168,30 +168,34 @@ const restFromResourceEndpoints = <
CC
>,
): Query<G, L, CC> => {
const log = GetLogger("endpoints-rest-client");
return {
get: (params, query) => {
const url = e.Get.getPath(params);
log.debug.log("GET %s: %j", url, params);
const getParams = { ...(params ?? {}), ...(query ?? {}) };
return pipe(
dataProviderRequestLift(
() =>
apiClient.get<
serializedType<InferEndpointParams<G>["output"]> & {
id: string;
}
>(url, { ...(params ?? {}), ...(query ?? {}) }),
>(url, getParams),
e.Get.Output.decode,
),
TE.map((r) => r.data),
throwTE,
);
},
getList: (
params: GetListParams,
): Promise<
): TE.TaskEither<
APIError,
InferEndpointParams<L>["output"] extends t.ExactType<infer T>
? t.TypeOf<T>
: never
> => {
log.debug.log("GET %s: %j", e.List.getPath(), params);
return pipe(
dataProviderRequestLift(
() =>
Expand All @@ -200,16 +204,18 @@ const restFromResourceEndpoints = <
}>(e.List.getPath(), params),
e.List.Output.decode,
),
throwTE,
);
},
Custom: pipe(
e.Custom as any,
e.Custom,
R.map((ee: MinimalEndpointInstance) => {
const fetch = (
params: TypeOfEndpointInstance<typeof ee>["Input"],
): TE.TaskEither<APIError, any> => {
const url = ee.getPath((params as any).Params);

log.debug.log("%s %s: %j", ee.Method, url, params);

return dataProviderRequestLift(
() =>
apiClient.request({
Expand All @@ -230,7 +236,10 @@ const restFromResourceEndpoints = <
return (
params: TypeOfEndpointInstance<typeof ee>["Input"],
q: any,
): Promise<TypeOfEndpointInstance<typeof ee>["Output"]> => {
): TE.TaskEither<
APIError,
TypeOfEndpointInstance<typeof ee>["Output"]
> => {
const p: any = params;
return pipe(
fetch({
Expand All @@ -239,8 +248,8 @@ const restFromResourceEndpoints = <
...(p?.Query ?? {}),
...(q ?? {}),
},
Body: p?.Body,
} as any),
throwTE,
);
};
}),
Expand Down
22 changes: 15 additions & 7 deletions services/web/src/client/state/commands.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { pipe, fp } from "@liexp/core/lib/fp/index.js";
import { type Endpoints } from "@liexp/shared/lib/endpoints";
import { type APIError } from "@liexp/shared/lib/io/http/Error/APIError.js";
import { type http } from "@liexp/shared/lib/io/index.js";
import { type EndpointsRESTClient } from "@liexp/shared/lib/providers/EndpointsRESTClient/EndpointsRESTClient";
import { throwTE } from "@liexp/shared/lib/utils/task.utils.js";
import {
useMutation,
type QueryClient,
type UseMutationResult,
} from "@tanstack/react-query";
import { pipe } from "fp-ts/lib/function.js";

export const createEventFromLink = (
api: EndpointsRESTClient<Endpoints>,
Expand All @@ -21,6 +22,7 @@ export const createEventFromLink = (
url: params.url,
},
}),
throwTE,
),
onSuccess: () => qc.invalidateQueries({ queryKey: ["events"] }),
});
Expand All @@ -38,6 +40,7 @@ export const getEventFromLink = (
_end: null,
},
}),
throwTE,
),
});

Expand All @@ -54,6 +57,7 @@ export const createEventSuggestion = (
api.Endpoints.Event.Custom.CreateSuggestion({
Body: params as any,
}),
throwTE,
),
});

Expand All @@ -62,10 +66,14 @@ export const getURLMetadata = (
): UseMutationResult<any, APIError, { url: string }> =>
useMutation({
mutationFn: (params) =>
api.Endpoints.OpenGraph.Custom.GetMetadata({
Query: {
url: params.url as any,
type: "Link",
},
}).then((r) => r.data),
pipe(
api.Endpoints.OpenGraph.Custom.GetMetadata({
Query: {
url: params.url as any,
type: "Link",
},
}),
fp.TE.map((r) => r.data),
throwTE,
),
});
Loading