1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Simplify and improve pagination

This commit is contained in:
xmflsct
2023-01-07 18:01:08 +01:00
parent 44f8900902
commit 7db8b26dd9
12 changed files with 92 additions and 112 deletions

View File

@ -1,5 +1,5 @@
import axios from 'axios'
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete'
@ -49,29 +49,7 @@ const apiGeneral = async <T = unknown>({
? (body as (FormData & { _parts: [][] }) | undefined)?._parts?.length
: Object.keys(body).length) && { data: body })
})
.then(response => {
let links: {
prev?: { id: string; isOffset: boolean }
next?: { id: string; isOffset: boolean }
} = {}
if (response.headers?.link) {
const linksParsed = response.headers.link.matchAll(
new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
)
for (const link of linksParsed) {
switch (link[3]) {
case 'prev':
links.prev = { id: link[2], isOffset: link[1].includes('offset') }
break
case 'next':
links.next = { id: link[2], isOffset: link[1].includes('offset') }
break
}
}
}
return Promise.resolve({ body: response.data, links })
})
.then(response => ({ body: response.data, links: parseHeaderLinks(response.headers.link) }))
.catch(handleError())
}

View File

@ -2,6 +2,7 @@ import * as Sentry from '@sentry/react-native'
import chalk from 'chalk'
import Constants from 'expo-constants'
import { Platform } from 'react-native'
import parse from 'url-parse'
const userAgent = {
'User-Agent': `tooot/${Constants.expoConfig?.version} ${Platform.OS}/${Platform.Version}`
@ -64,10 +65,42 @@ const handleError =
}
}
export const parseHeaderLinks = (headerLink?: string): PagedResponse['links'] => {
if (!headerLink) return undefined
const links: PagedResponse['links'] = {}
const linkParsed = [...headerLink.matchAll(/<(\S+?)>; *rel="(next|prev)"/gi)]
for (const link of linkParsed) {
const queries = parse(link[1], true).query
const isOffset = !!queries.offset?.length
switch (link[2]) {
case 'prev':
const prevId = isOffset ? queries.offset : queries.min_id
if (prevId) links.prev = isOffset ? { offset: prevId } : { min_id: prevId }
break
case 'next':
const nextId = isOffset ? queries.offset : queries.max_id
if (nextId) links.next = isOffset ? { offset: nextId } : { max_id: nextId }
break
}
}
if (links.prev || links.next) {
return links
} else {
return undefined
}
}
type LinkFormat = { id: string; isOffset: boolean }
export type PagedResponse<T = unknown> = {
body: T
links?: { prev?: LinkFormat; next?: LinkFormat }
links?: {
prev?: { min_id: string } | { offset: string }
next?: { max_id: string } | { offset: string }
}
}
export { ctx, handleError, userAgent }

View File

@ -1,6 +1,6 @@
import { getAccountDetails } from '@utils/storage/actions'
import axios, { AxiosRequestConfig } from 'axios'
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
@ -57,29 +57,7 @@ const apiInstance = async <T = unknown>({
...((body as (FormData & { _parts: [][] }) | undefined)?._parts.length && { data: body }),
...extras
})
.then(response => {
let links: {
prev?: { id: string; isOffset: boolean }
next?: { id: string; isOffset: boolean }
} = {}
if (response.headers?.link) {
const linksParsed = response.headers.link.matchAll(
new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
)
for (const link of linksParsed) {
switch (link[3]) {
case 'prev':
links.prev = { id: link[2], isOffset: link[1].includes('offset') }
break
case 'next':
links.next = { id: link[2], isOffset: link[1].includes('offset') }
break
}
}
}
return Promise.resolve({ body: response.data, links })
})
.then(response => ({ body: response.data, links: parseHeaderLinks(response.headers.link) }))
.catch(handleError())
}