Add graphql logic to RequestManager
This commit is contained in:
@@ -9,6 +9,18 @@
|
|||||||
import { AxiosInstance, AxiosRequestConfig } from 'axios';
|
import { AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||||
import useSWR, { Middleware, SWRConfiguration, SWRResponse } from 'swr';
|
import useSWR, { Middleware, SWRConfiguration, SWRResponse } from 'swr';
|
||||||
import useSWRInfinite, { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr/infinite';
|
import useSWRInfinite, { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr/infinite';
|
||||||
|
import {
|
||||||
|
FetchResult,
|
||||||
|
MutationHookOptions,
|
||||||
|
MutationOptions,
|
||||||
|
MutationTuple,
|
||||||
|
QueryHookOptions,
|
||||||
|
QueryResult,
|
||||||
|
TypedDocumentNode,
|
||||||
|
useMutation,
|
||||||
|
useQuery,
|
||||||
|
} from '@apollo/client';
|
||||||
|
import { OperationVariables } from '@apollo/client/core';
|
||||||
import {
|
import {
|
||||||
BackupValidationResult,
|
BackupValidationResult,
|
||||||
BatchChaptersChange,
|
BatchChaptersChange,
|
||||||
@@ -31,6 +43,7 @@ import {
|
|||||||
} from '@/typings.ts';
|
} from '@/typings.ts';
|
||||||
import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts';
|
import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts';
|
||||||
import storage from '@/util/localStorage.tsx';
|
import storage from '@/util/localStorage.tsx';
|
||||||
|
import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts';
|
||||||
|
|
||||||
enum SWRHttpMethod {
|
enum SWRHttpMethod {
|
||||||
SWR_GET,
|
SWR_GET,
|
||||||
@@ -39,6 +52,12 @@ enum SWRHttpMethod {
|
|||||||
SWR_POST_INFINITE,
|
SWR_POST_INFINITE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum GQLMethod {
|
||||||
|
USE_QUERY = 'USE_QUERY',
|
||||||
|
USE_MUTATION = 'USE_MUTATION',
|
||||||
|
MUTATION = 'MUTATION',
|
||||||
|
}
|
||||||
|
|
||||||
type HttpMethodType = DefaultHttpMethod | SWRHttpMethod;
|
type HttpMethodType = DefaultHttpMethod | SWRHttpMethod;
|
||||||
const HttpMethod = { ...SWRHttpMethod, ...DefaultHttpMethod };
|
const HttpMethod = { ...SWRHttpMethod, ...DefaultHttpMethod };
|
||||||
|
|
||||||
@@ -64,6 +83,16 @@ export type AbortableSWRInfiniteResponse<Data = any, Error = any> = SWRInfiniteR
|
|||||||
AbortableRequest &
|
AbortableRequest &
|
||||||
SWRInfiniteResponseLoadInfo;
|
SWRInfiniteResponseLoadInfo;
|
||||||
|
|
||||||
|
type AbortableApolloUseQueryResponse<
|
||||||
|
Data = any,
|
||||||
|
Variables extends OperationVariables = OperationVariables,
|
||||||
|
> = QueryResult<Data, Variables> & AbortableRequest;
|
||||||
|
type AbortableApolloUseMutationResponse<Data = any, Variables extends OperationVariables = OperationVariables> = [
|
||||||
|
MutationTuple<Data, Variables>[0],
|
||||||
|
MutationTuple<Data, Variables>[1] & AbortableRequest,
|
||||||
|
];
|
||||||
|
type AbortableApolloMutationResponse<Data = any> = { response: Promise<FetchResult<Data>> } & AbortableRequest;
|
||||||
|
|
||||||
const isLoadingMore = (swrResult: SWRInfiniteResponse): boolean => {
|
const isLoadingMore = (swrResult: SWRInfiniteResponse): boolean => {
|
||||||
const isNextPageMissing = !!swrResult.data && typeof swrResult.data[swrResult.size - 1] === 'undefined';
|
const isNextPageMissing = !!swrResult.data && typeof swrResult.data[swrResult.size - 1] === 'undefined';
|
||||||
const isRequestActive = swrResult.isValidating;
|
const isRequestActive = swrResult.isValidating;
|
||||||
@@ -97,6 +126,8 @@ const disableSwrCache: Middleware = (useSWRNext) => (key, fetcher, config) => {
|
|||||||
export class RequestManager {
|
export class RequestManager {
|
||||||
public static readonly API_VERSION = '/api/v1/';
|
public static readonly API_VERSION = '/api/v1/';
|
||||||
|
|
||||||
|
private readonly graphQLClient = new GraphQLClient();
|
||||||
|
|
||||||
private readonly restClient: RestClient = new RestClient();
|
private readonly restClient: RestClient = new RestClient();
|
||||||
|
|
||||||
public getClient(): IRestClient {
|
public getClient(): IRestClient {
|
||||||
@@ -105,6 +136,7 @@ export class RequestManager {
|
|||||||
|
|
||||||
public updateClient(config: Partial<AxiosInstance['defaults']>): void {
|
public updateClient(config: Partial<AxiosInstance['defaults']>): void {
|
||||||
this.restClient.updateConfig(config);
|
this.restClient.updateConfig(config);
|
||||||
|
this.graphQLClient.updateConfig({ uri: config.baseURL });
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBaseUrl(): string {
|
public getBaseUrl(): string {
|
||||||
@@ -138,6 +170,100 @@ export class RequestManager {
|
|||||||
return `${this.getValidUrlFor(imageUrl, apiVersion)}${useCacheQuery}`;
|
return `${this.getValidUrlFor(imageUrl, apiVersion)}${useCacheQuery}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private doRequestNew<Data, Variables extends OperationVariables = OperationVariables>(
|
||||||
|
method: GQLMethod.USE_QUERY,
|
||||||
|
operation: TypedDocumentNode<Data, Variables>,
|
||||||
|
variables: Variables,
|
||||||
|
options?: Partial<QueryHookOptions<Data, Variables>>,
|
||||||
|
): AbortableApolloUseQueryResponse<Data, Variables>;
|
||||||
|
|
||||||
|
private doRequestNew<Data, Variables extends OperationVariables = OperationVariables>(
|
||||||
|
method: GQLMethod.USE_MUTATION,
|
||||||
|
operation: TypedDocumentNode<Data, Variables>,
|
||||||
|
variables: Variables | undefined,
|
||||||
|
options?: Partial<MutationHookOptions<Data, Variables>>,
|
||||||
|
): AbortableApolloUseMutationResponse<Data, Variables>;
|
||||||
|
|
||||||
|
private doRequestNew<Data, Variables extends OperationVariables = OperationVariables>(
|
||||||
|
method: GQLMethod.MUTATION,
|
||||||
|
operation: TypedDocumentNode<Data, Variables>,
|
||||||
|
variables: Variables,
|
||||||
|
options?: Partial<MutationOptions<Data, Variables>>,
|
||||||
|
): AbortableApolloMutationResponse<Data>;
|
||||||
|
|
||||||
|
private doRequestNew<Data, Variables extends OperationVariables = OperationVariables>(
|
||||||
|
method: GQLMethod,
|
||||||
|
operation: TypedDocumentNode<Data, Variables>,
|
||||||
|
variables: Variables,
|
||||||
|
options?:
|
||||||
|
| QueryHookOptions<Data, Variables>
|
||||||
|
| MutationHookOptions<Data, Variables>
|
||||||
|
| MutationOptions<Data, Variables>,
|
||||||
|
):
|
||||||
|
| AbortableApolloUseQueryResponse<Data, Variables>
|
||||||
|
| AbortableApolloUseMutationResponse<Data, Variables>
|
||||||
|
| AbortableApolloMutationResponse<Data> {
|
||||||
|
const abortController = new AbortController();
|
||||||
|
const abortRequest = (reason?: any): void => {
|
||||||
|
if (!abortController.signal.aborted) {
|
||||||
|
abortController.abort(reason);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (method) {
|
||||||
|
case GQLMethod.USE_QUERY:
|
||||||
|
return {
|
||||||
|
...useQuery<Data, Variables>(operation, {
|
||||||
|
variables,
|
||||||
|
client: this.graphQLClient.client,
|
||||||
|
...options,
|
||||||
|
context: {
|
||||||
|
...options?.context,
|
||||||
|
fetchOptions: {
|
||||||
|
signal: abortController.signal,
|
||||||
|
...options?.context?.fetchOptions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
abortRequest,
|
||||||
|
};
|
||||||
|
case GQLMethod.USE_MUTATION:
|
||||||
|
// eslint-disable-next-line no-case-declarations
|
||||||
|
const mutationResult = useMutation<Data, Variables>(operation, {
|
||||||
|
variables,
|
||||||
|
client: this.graphQLClient.client,
|
||||||
|
...(options as MutationHookOptions<Data, Variables>),
|
||||||
|
context: {
|
||||||
|
...options?.context,
|
||||||
|
fetchOptions: {
|
||||||
|
signal: abortController.signal,
|
||||||
|
...options?.context?.fetchOptions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return [mutationResult[0], { ...mutationResult[1], abortRequest }];
|
||||||
|
case GQLMethod.MUTATION:
|
||||||
|
return {
|
||||||
|
response: this.graphQLClient.client.mutate<Data, Variables>({
|
||||||
|
mutation: operation,
|
||||||
|
variables,
|
||||||
|
...(options as MutationOptions<Data, Variables>),
|
||||||
|
context: {
|
||||||
|
...options?.context,
|
||||||
|
fetchOptions: {
|
||||||
|
signal: abortController.signal,
|
||||||
|
...options?.context?.fetchOptions,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
abortRequest,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error(`unexpected GQLRequest type "${method}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private useSwr<
|
private useSwr<
|
||||||
Data = any,
|
Data = any,
|
||||||
ErrorResponse = any,
|
ErrorResponse = any,
|
||||||
|
|||||||
53
src/lib/requests/client/GraphQLClient.ts
Normal file
53
src/lib/requests/client/GraphQLClient.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ApolloClient, ApolloClientOptions, InMemoryCache, NormalizedCacheObject } from '@apollo/client';
|
||||||
|
import { createUploadLink } from 'apollo-upload-client';
|
||||||
|
import { BaseClient } from '@/lib/requests/client/BaseClient.ts';
|
||||||
|
import { StrictTypedTypePolicies } from '@/lib/graphql/generated/apollo-helpers.ts';
|
||||||
|
|
||||||
|
const typePolicies: StrictTypedTypePolicies = {
|
||||||
|
GlobalMetaType: { keyFields: ['key'] },
|
||||||
|
ExtensionType: { keyFields: ['apkName'] },
|
||||||
|
AboutPayload: { keyFields: [] },
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
|
export class GraphQLClient extends BaseClient<
|
||||||
|
ApolloClient<NormalizedCacheObject>,
|
||||||
|
ApolloClientOptions<NormalizedCacheObject>,
|
||||||
|
null
|
||||||
|
> {
|
||||||
|
readonly fetcher = null;
|
||||||
|
|
||||||
|
public declare client: ApolloClient<NormalizedCacheObject>;
|
||||||
|
|
||||||
|
public override getBaseUrl(): string {
|
||||||
|
return `${super.getBaseUrl()}/api/graphql`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createUploadLink() {
|
||||||
|
return createUploadLink({ uri: () => this.getBaseUrl() });
|
||||||
|
}
|
||||||
|
|
||||||
|
private createLink() {
|
||||||
|
return this.createUploadLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createClient() {
|
||||||
|
this.client = new ApolloClient({
|
||||||
|
cache: new InMemoryCache({
|
||||||
|
typePolicies,
|
||||||
|
}),
|
||||||
|
connectToDevTools: true,
|
||||||
|
link: this.createLink(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override updateConfig() {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user