Last active
March 24, 2025 06:27
-
-
Save ilfey/686f7dc44bc2f7b1578452c488d11931 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {Contract, createMutation} from "@farfetched/core"; | |
| import {createRequestInstance, Payload} from "./createRequestInstance.ts"; | |
| import {API_URL} from "./config.ts"; | |
| import {sleep} from "./sleep.ts"; | |
| const MOCK_ENABLED = false; | |
| interface MutationParameters< | |
| Params, | |
| Response, | |
| > { | |
| request: Payload<Params> | |
| response: { | |
| contract: Contract<any, Response> | |
| mockedData?: Response, | |
| } | |
| } | |
| export const createApiMutation = < | |
| Params, | |
| Response, | |
| >({ | |
| request, | |
| response, | |
| }: MutationParameters< | |
| Params, | |
| Response | |
| >) => { | |
| const fx = createRequestInstance<Params, Response>({ | |
| baseUrl: API_URL, | |
| payload: request, | |
| }) | |
| const mutation = createMutation({ | |
| effect: fx, | |
| contract: response.contract, | |
| }) | |
| mutation.finished.failure.watch(({error}) => { | |
| console.error(error); | |
| if (error?.errorType === 'NETWORK') { | |
| console.log("@NETWORK") | |
| // TODO: error | |
| } | |
| if (error?.errorType === 'HTTP' && error.status !== 401) { | |
| console.log("@HTTP !== 401") | |
| // TODO: error | |
| } | |
| }); | |
| if (response.mockedData && MOCK_ENABLED) { | |
| mutation.__.executeFx.use(async (params: Params) => { | |
| const config = typeof request === "function" ? request(params) : request; | |
| console.log(`Request ${config.url} mocked`); | |
| await sleep(500); | |
| return response.mockedData; | |
| }); | |
| } | |
| return mutation | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {Contract, createQuery, DynamicallySourcedField,} from "@farfetched/core"; | |
| import {createRequestInstance, Payload} from "./createRequestInstance.ts"; | |
| import {API_URL} from "./config.ts"; | |
| import {sleep} from "./sleep.ts"; | |
| const MOCK_ENABLED = false; | |
| interface QueryParameters< | |
| Params, | |
| Response, | |
| MappedData, | |
| InitialData, | |
| > { | |
| request: Payload<Params> | |
| response: { | |
| contract: Contract<any, Response> | |
| mapData?: DynamicallySourcedField<{ | |
| result: Response; | |
| params: Params; | |
| }, MappedData | InitialData, void> | |
| mockedData?: Response, | |
| } | |
| initialData?: InitialData | null; | |
| } | |
| export const createApiQuery = < | |
| Params, | |
| Response, | |
| MappedData, | |
| InitialData, | |
| >({ | |
| request, | |
| response, | |
| initialData = null, | |
| }: QueryParameters< | |
| Params, | |
| Response, | |
| MappedData, | |
| InitialData | |
| >) => { | |
| const fx = createRequestInstance<Params, Response>({ | |
| baseUrl: API_URL, | |
| payload: request, | |
| }) | |
| const query = createQuery({ | |
| effect: fx, | |
| contract: response.contract, | |
| mapData: response.mapData!, | |
| initialData: initialData, | |
| }) | |
| query.finished.failure.watch(({error}) => { | |
| console.error(error); | |
| if (error?.errorType === 'NETWORK') { | |
| console.log("@NETWORK") | |
| // TODO: error | |
| } | |
| if (error?.errorType === 'HTTP' && error.status !== 401) { | |
| console.log("@HTTP !== 401") | |
| // TODO: error | |
| } | |
| if (error?.errorType === 'INVALID_DATA') { | |
| console.log("@INVALID_DATA") | |
| // TODO: error | |
| } | |
| }); | |
| if (response.mockedData && MOCK_ENABLED) { | |
| query.__.executeFx.use(async (params: Params) => { | |
| const config = typeof request === "function" ? request(params) : request; | |
| console.log(`Request ${config.url} mocked`); | |
| await sleep(500); | |
| return response.mockedData; | |
| }); | |
| } | |
| return query | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {attach, createEffect} from "effector"; | |
| import {$token} from "../api/authorization.ts"; | |
| import {HttpError, NetworkError} from "@farfetched/core" | |
| import {requestFx} from "./request-fx.ts"; | |
| const getTokenFx = attach({ | |
| source: $token, | |
| effect: async (token) => token, | |
| }) | |
| export const createRequestInstance = <P = RequestInit, R = void>({ | |
| baseUrl, | |
| payload, | |
| }: Omit<CreateRequestInstanceParams<P>, "url">) => | |
| createEffect<P, R, HttpError | NetworkError>(async (params) => { | |
| const {url, query, headers, ...fetchOptions} = getConfig(payload, params) | |
| const fullUrl = new URL(url, baseUrl) | |
| if (query) { | |
| fullUrl.search = new URLSearchParams( | |
| Object.entries(query) | |
| .map(kv => [kv[0], kv[1].toString()]) as unknown as string[][], | |
| ).toString() | |
| } | |
| const newHeaders = new Headers(headers); | |
| newHeaders.set("Authorization", "Bearer " + await getTokenFx()); | |
| const request = new Request(fullUrl, { | |
| ...fetchOptions, | |
| headers: newHeaders, | |
| }) | |
| const response = await requestFx(request) | |
| return await response.json() as R | |
| }) | |
| const getConfig = <P>(payload: Payload<P>, params: P): CreateRequestParams => | |
| typeof payload === "function" ? payload(params) : payload | |
| type CreateRequestParams = RequestInit & { | |
| /** The presence of baseUrl is mandatory, otherwise the requests will not work.*/ | |
| baseUrl?: string; | |
| headers?: Record<string, string>; | |
| url: `/${string}`; | |
| query?: Record<string, any>; | |
| }; | |
| export type Payload<P> = CreateRequestParams | ((params: P) => CreateRequestParams); | |
| type CreateRequestInstanceParams<P> = CreateRequestParams & { | |
| payload: Payload<P>; | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {createApiQuery} from "shared/lib/createApiQuery.ts"; | |
| import {createListContract} from "shared/api/types.ts"; | |
| import {AnimeListItemContract} from "../model/AnimeItemDto.ts"; | |
| interface Params { | |
| limit: number, | |
| page: number | |
| } | |
| export const createGetAnimeListQuery = () => | |
| createApiQuery({ | |
| request: (params: Params) => ({ | |
| url: "/api/v1/animes", | |
| method: "GET", | |
| query: params, | |
| }), | |
| response: { | |
| contract: createListContract(AnimeListItemContract), | |
| mapData: ({result}) => result.data | |
| } | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {createEffect} from "effector/compat"; | |
| import {fetchFx, httpError, HttpError, networkError, NetworkError} from "@farfetched/core"; | |
| export const requestFx = createEffect< | |
| Request, | |
| Response, | |
| NetworkError | HttpError | |
| >(async (request) => { | |
| const response = await fetchFx(request) | |
| .catch((cause) => { | |
| throw networkError({ | |
| reason: cause?.message ?? null, | |
| cause, | |
| }); | |
| }); | |
| if (!response.ok) { | |
| const resp = await response.text().catch(() => null) | |
| throw httpError({ | |
| status: response.status, | |
| statusText: response.statusText, | |
| response: resp ?? null, | |
| }); | |
| } | |
| return response; | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment