Merge branch 'mastodon-response' into 'main'
MastodonClient: return a MastodonResponse object with `.pagination()` convenience method See merge request soapbox-pub/soapbox!3245
This commit is contained in:
commit
a80238275f
|
@ -1,4 +1,5 @@
|
||||||
import { HTTPError } from './HTTPError.ts';
|
import { HTTPError } from './HTTPError.ts';
|
||||||
|
import { MastodonResponse } from './MastodonResponse.ts';
|
||||||
|
|
||||||
interface Opts {
|
interface Opts {
|
||||||
searchParams?: URLSearchParams | Record<string, string | number | boolean>;
|
searchParams?: URLSearchParams | Record<string, string | number | boolean>;
|
||||||
|
@ -19,35 +20,35 @@ export class MastodonClient {
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(path: string, opts: Opts = {}): Promise<Response> {
|
async get(path: string, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
return this.request('GET', path, undefined, opts);
|
return this.request('GET', path, undefined, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
async post(path: string, data?: unknown, opts: Opts = {}): Promise<Response> {
|
async post(path: string, data?: unknown, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
return this.request('POST', path, data, opts);
|
return this.request('POST', path, data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
async put(path: string, data?: unknown, opts: Opts = {}): Promise<Response> {
|
async put(path: string, data?: unknown, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
return this.request('PUT', path, data, opts);
|
return this.request('PUT', path, data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(path: string, opts: Opts = {}): Promise<Response> {
|
async delete(path: string, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
return this.request('DELETE', path, undefined, opts);
|
return this.request('DELETE', path, undefined, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
async patch(path: string, data: unknown, opts: Opts = {}): Promise<Response> {
|
async patch(path: string, data: unknown, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
return this.request('PATCH', path, data, opts);
|
return this.request('PATCH', path, data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
async head(path: string, opts: Opts = {}): Promise<Response> {
|
async head(path: string, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
return this.request('HEAD', path, undefined, opts);
|
return this.request('HEAD', path, undefined, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
async options(path: string, opts: Opts = {}): Promise<Response> {
|
async options(path: string, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
return this.request('OPTIONS', path, undefined, opts);
|
return this.request('OPTIONS', path, undefined, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
async request(method: string, path: string, data: unknown, opts: Opts = {}): Promise<Response> {
|
async request(method: string, path: string, data: unknown, opts: Opts = {}): Promise<MastodonResponse> {
|
||||||
const url = new URL(path, this.baseUrl);
|
const url = new URL(path, this.baseUrl);
|
||||||
|
|
||||||
if (opts.searchParams) {
|
if (opts.searchParams) {
|
||||||
|
@ -89,7 +90,7 @@ export class MastodonClient {
|
||||||
throw new HTTPError(response, request);
|
throw new HTTPError(response, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return new MastodonResponse(response.body, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import LinkHeader from 'http-link-header';
|
||||||
|
|
||||||
|
export class MastodonResponse extends Response {
|
||||||
|
|
||||||
|
/** Parses the `Link` header and returns URLs for the `prev` and `next` pages of this response, if any. */
|
||||||
|
pagination(): { prev?: string; next?: string } {
|
||||||
|
const header = this.headers.get('link');
|
||||||
|
const links = header ? new LinkHeader(header) : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
next: links?.refs.find((link) => link.rel === 'next')?.uri,
|
||||||
|
prev: links?.refs.find((link) => link.rel === 'prev')?.uri,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ import { normalizeChatMessage } from 'soapbox/normalizers/index.ts';
|
||||||
import toast from 'soapbox/toast.tsx';
|
import toast from 'soapbox/toast.tsx';
|
||||||
import { ChatMessage } from 'soapbox/types/entities.ts';
|
import { ChatMessage } from 'soapbox/types/entities.ts';
|
||||||
import { reOrderChatListItems, updateChatMessage } from 'soapbox/utils/chats.ts';
|
import { reOrderChatListItems, updateChatMessage } from 'soapbox/utils/chats.ts';
|
||||||
import { getPagination } from 'soapbox/utils/pagination.ts';
|
|
||||||
import { flattenPages, PaginatedResult, updatePageItem } from 'soapbox/utils/queries.ts';
|
import { flattenPages, PaginatedResult, updatePageItem } from 'soapbox/utils/queries.ts';
|
||||||
|
|
||||||
import { queryClient } from './client.ts';
|
import { queryClient } from './client.ts';
|
||||||
|
@ -91,7 +90,7 @@ const useChatMessages = (chat: IChat) => {
|
||||||
const response = await api.get(uri);
|
const response = await api.get(uri);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
const { next } = getPagination(response);
|
const { next } = response.pagination();
|
||||||
const hasMore = !!next;
|
const hasMore = !!next;
|
||||||
const result = data.map(normalizeChatMessage);
|
const result = data.map(normalizeChatMessage);
|
||||||
|
|
||||||
|
@ -144,7 +143,7 @@ const useChats = (search?: string) => {
|
||||||
});
|
});
|
||||||
const data: IChat[] = await response.json();
|
const data: IChat[] = await response.json();
|
||||||
|
|
||||||
const { next } = getPagination(response);
|
const { next } = response.pagination();
|
||||||
const hasMore = !!next;
|
const hasMore = !!next;
|
||||||
|
|
||||||
setUnreadChatsCount(Number(response.headers.get('x-unread-messages-count')) || sumBy(data, (chat) => chat.unread));
|
setUnreadChatsCount(Number(response.headers.get('x-unread-messages-count')) || sumBy(data, (chat) => chat.unread));
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
import { useApi } from 'soapbox/hooks/useApi.ts';
|
import { useApi } from 'soapbox/hooks/useApi.ts';
|
||||||
import { Account } from 'soapbox/types/entities.ts';
|
import { Account } from 'soapbox/types/entities.ts';
|
||||||
import { getPagination } from 'soapbox/utils/pagination.ts';
|
|
||||||
import { flattenPages, PaginatedResult } from 'soapbox/utils/queries.ts';
|
import { flattenPages, PaginatedResult } from 'soapbox/utils/queries.ts';
|
||||||
|
|
||||||
export default function useAccountSearch(q: string) {
|
export default function useAccountSearch(q: string) {
|
||||||
|
@ -21,7 +20,7 @@ export default function useAccountSearch(q: string) {
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
const { next } = getPagination(response);
|
const { next } = response.pagination();
|
||||||
const hasMore = !!next;
|
const hasMore = !!next;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { fetchRelationships } from 'soapbox/actions/accounts.ts';
|
||||||
import { importFetchedAccounts } from 'soapbox/actions/importer/index.ts';
|
import { importFetchedAccounts } from 'soapbox/actions/importer/index.ts';
|
||||||
import { useApi } from 'soapbox/hooks/useApi.ts';
|
import { useApi } from 'soapbox/hooks/useApi.ts';
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
import { getPagination } from 'soapbox/utils/pagination.ts';
|
|
||||||
|
|
||||||
import { PaginatedResult, removePageItem } from '../utils/queries.ts';
|
import { PaginatedResult, removePageItem } from '../utils/queries.ts';
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ const useSuggestions = () => {
|
||||||
const getV2Suggestions = async (pageParam: PageParam): Promise<PaginatedResult<Result>> => {
|
const getV2Suggestions = async (pageParam: PageParam): Promise<PaginatedResult<Result>> => {
|
||||||
const endpoint = pageParam?.link || '/api/v2/suggestions';
|
const endpoint = pageParam?.link || '/api/v2/suggestions';
|
||||||
const response = await api.get(endpoint);
|
const response = await api.get(endpoint);
|
||||||
const { next } = getPagination(response);
|
const { next } = response.pagination();
|
||||||
const hasMore = !!next;
|
const hasMore = !!next;
|
||||||
|
|
||||||
const data: Suggestion[] = await response.json();
|
const data: Suggestion[] = await response.json();
|
||||||
|
@ -93,7 +92,7 @@ function useOnboardingSuggestions() {
|
||||||
const getV2Suggestions = async (pageParam: any): Promise<{ data: Suggestion[]; link: string | undefined; hasMore: boolean }> => {
|
const getV2Suggestions = async (pageParam: any): Promise<{ data: Suggestion[]; link: string | undefined; hasMore: boolean }> => {
|
||||||
const link = pageParam?.link || '/api/v2/suggestions';
|
const link = pageParam?.link || '/api/v2/suggestions';
|
||||||
const response = await api.get(link);
|
const response = await api.get(link);
|
||||||
const { next } = getPagination(response);
|
const { next } = response.pagination();
|
||||||
const hasMore = !!next;
|
const hasMore = !!next;
|
||||||
|
|
||||||
const data: Suggestion[] = await response.json();
|
const data: Suggestion[] = await response.json();
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import LinkHeader from 'http-link-header';
|
|
||||||
|
|
||||||
interface Pagination {
|
|
||||||
next?: string;
|
|
||||||
prev?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPagination(response: Response): Pagination {
|
|
||||||
const header = response.headers.get('link');
|
|
||||||
const links = header ? new LinkHeader(header) : undefined;
|
|
||||||
|
|
||||||
return {
|
|
||||||
next: links?.refs.find((link) => link.rel === 'next')?.uri,
|
|
||||||
prev: links?.refs.find((link) => link.rel === 'prev')?.uri,
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in New Issue