Chore/deprecate lib common fetch 03 (#36529)

* Deprecate use of getWithTimeout, refactor BuildingState and RestoringState to use RQ

* Refactor profile-create-mutation to use data/fetchers, and edge-function-status-query to use fetch

* Shift post from lib/common/fetch, refactor bucket-object-download-mutation

* Address feedback

* Minor fix

* Refactor post calls from lib/common/fetch in auth pages to data/fetchers

* Add missing POST users endpoint + small fix when deleting user via context menu

* Remove all use of any imports from lib/common/fetch

* Clean up remaining usage of lib/common/fetch

* Fix fetchHeadWithTimeout

* simplify handleFetchError

* allow handleFetchError to accept unknown

* non-breaking change

* small fixes

* fix query path

---------

Co-authored-by: Alaister Young <a@alaisteryoung.com>
This commit is contained in:
Joshen Lim
2025-07-21 16:59:17 +08:00
committed by GitHub
parent 4bd28eecb8
commit dbb413beeb
29 changed files with 205 additions and 831 deletions

View File

@@ -176,7 +176,7 @@ export const handleError = (
throw new ResponseError(undefined)
}
// [Joshen] The methods below are brought over from lib/common/fetchers because we still need them
// [Joshen] The methods below are brought over from lib/common/fetch because we still need them
// primarily for our own endpoints in the dashboard repo. So consolidating all the fetch methods into here.
async function handleFetchResponse<T>(response: Response): Promise<T | ResponseError> {
@@ -196,6 +196,21 @@ async function handleFetchResponse<T>(response: Response): Promise<T | ResponseE
}
}
async function handleFetchHeadResponse<T>(
response: Response,
headers: string[]
): Promise<T | ResponseError> {
try {
const res = {} as any
headers.forEach((header: string) => {
res[header] = response.headers.get(header)
})
return res
} catch (e) {
return handleError(response) as T | ResponseError
}
}
async function handleFetchError(response: unknown): Promise<ResponseError> {
let resJson: any = {}
@@ -229,6 +244,34 @@ async function handleFetchError(response: unknown): Promise<ResponseError> {
return error
}
/**
* To be used only for dashboard API endpoints. Use `fetch` directly if calling a non dashboard API endpoint
*/
export async function fetchGet<T = any>(
url: string,
options?: { [prop: string]: any }
): Promise<T | ResponseError> {
try {
const { headers: otherHeaders, abortSignal, ...otherOptions } = options ?? {}
const headers = await constructHeaders({
'Content-Type': 'application/json',
...DEFAULT_HEADERS,
...otherHeaders,
})
const response = await fetch(url, {
headers,
method: 'GET',
referrerPolicy: 'no-referrer-when-downgrade',
...otherOptions,
signal: abortSignal,
})
if (!response.ok) return handleFetchError(response)
return handleFetchResponse(response)
} catch (error) {
return handleFetchError(error)
}
}
/**
* To be used only for dashboard API endpoints. Use `fetch` directly if calling a non dashboard API endpoint
*
@@ -247,10 +290,10 @@ export async function fetchPost<T = any>(
...otherHeaders,
})
const response = await fetch(url, {
headers,
method: 'POST',
body: JSON.stringify(data),
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
signal: abortSignal,
})
@@ -260,3 +303,36 @@ export async function fetchPost<T = any>(
return handleFetchError(error)
}
}
/**
* To be used only for dashboard API endpoints. Use `fetch` directly if calling a non dashboard API endpoint
*/
export async function fetchHeadWithTimeout<T = any>(
url: string,
headersToRetrieve: string[],
options?: { [prop: string]: any }
): Promise<T | ResponseError> {
try {
const timeout = options?.timeout ?? 60000
const { headers: otherHeaders, abortSignal, ...otherOptions } = options ?? {}
const headers = await constructHeaders({
'Content-Type': 'application/json',
...DEFAULT_HEADERS,
...otherHeaders,
})
const response = await fetch(url, {
method: 'HEAD',
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
signal: AbortSignal.timeout(timeout),
})
if (!response.ok) return handleFetchError(response)
return handleFetchHeadResponse(response, headersToRetrieve)
} catch (error) {
return handleFetchError(error)
}
}

View File

@@ -1,8 +1,25 @@
import { isResponseOk } from 'lib/common/fetch'
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import { ResponseError, ResponseFailure } from 'types'
import { IS_PLATFORM } from '../constants'
import { apiAuthenticate } from './apiAuthenticate'
export function isResponseOk<T>(response: T | ResponseFailure | undefined): response is T {
if (response === undefined || response === null) {
return false
}
if (response instanceof ResponseError) {
return false
}
if (typeof response === 'object' && 'error' in response && Boolean(response.error)) {
return false
}
return true
}
// Purpose of this apiWrapper is to function like a global catchall for ANY errors
// It's a safety net as the API service should never drop, nor fail

View File

@@ -1,112 +0,0 @@
import { getAccessToken } from 'lib/gotrue'
import { isUndefined } from 'lodash'
import type { SupaResponse } from 'types/base'
/* @deprecated Use handleError from data/fetchers instead */
export function handleError<T>(e: any, requestId: string): SupaResponse<T> {
const message = e?.message ? `An error has occurred: ${e.message}` : 'An error has occurred'
const error = { code: 500, message, requestId }
return { error } as unknown as SupaResponse<T>
}
export async function handleResponse<T>(
response: Response,
requestId: string
): Promise<SupaResponse<T>> {
const contentType = response.headers.get('Content-Type')
if (contentType === 'application/octet-stream') return response as any
try {
const resTxt = await response.text()
try {
// try to parse response text as json
return JSON.parse(resTxt)
} catch (err) {
// return as text plain
return resTxt as any
}
} catch (e) {
return handleError(response, requestId) as SupaResponse<T>
}
}
export async function handleHeadResponse<T>(
response: Response,
requestId: string,
headers: string[]
): Promise<SupaResponse<T>> {
try {
const res = {} as any
headers.forEach((header: string) => {
res[header] = response.headers.get(header)
})
return res
} catch (e) {
return handleError(response, requestId) as SupaResponse<T>
}
}
export async function handleResponseError<T = unknown>(
response: Response,
requestId: string
): Promise<SupaResponse<T>> {
let resJson: { [prop: string]: any }
const resTxt = await response.text()
try {
resJson = JSON.parse(resTxt)
} catch (_) {
resJson = {}
}
if (resJson.error && typeof resJson.error === 'string') {
if (resJson.error_description) {
const error = {
code: response.status,
message: resJson.error,
description: resJson.error_description,
requestId,
}
return { error } as unknown as SupaResponse<T>
} else {
const error = { code: response.status, message: resJson.error, requestId }
return { error } as unknown as SupaResponse<T>
}
} else if (resJson.message) {
const error = { code: response.status, message: resJson.message, requestId }
return { error } as unknown as SupaResponse<T>
} else if (resJson.msg) {
const error = { code: response.status, message: resJson.msg, requestId }
return { error } as unknown as SupaResponse<T>
} else if (resJson.error && resJson.error.message) {
return { error: { code: response.status, ...resJson.error } } as unknown as SupaResponse<T>
} else {
const message = resTxt ?? `An error has occurred: ${response.status}`
const error = { code: response.status, message, requestId }
return { error } as unknown as SupaResponse<T>
}
}
export async function constructHeaders(requestId: string, optionHeaders?: { [prop: string]: any }) {
let headers: { [prop: string]: any } = {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-Request-Id': requestId,
...optionHeaders,
}
const hasAuthHeader = !isUndefined(optionHeaders) && 'Authorization' in optionHeaders
if (!hasAuthHeader) {
const accessToken = await getAccessToken()
if (accessToken) headers.Authorization = `Bearer ${accessToken}`
}
return headers
}
export function isResponseOk<T>(response: SupaResponse<T> | undefined): response is T {
return (
response !== undefined &&
response !== null &&
!(typeof response === 'object' && 'error' in response && Boolean(response.error))
)
}

View File

@@ -1,30 +0,0 @@
import { handleError, handleResponse, handleResponseError, constructHeaders } from './base'
import { uuidv4 } from '../../helpers'
import type { SupaResponse } from 'types/base'
/**
* @deprecated please use del method from data/fetchers instead
*/
export async function delete_<T = any>(
url: string,
data?: { [prop: string]: any },
options?: { [prop: string]: any }
): Promise<SupaResponse<T>> {
const requestId = uuidv4()
try {
const { headers: optionHeaders, ...otherOptions } = options ?? {}
const headers = await constructHeaders(requestId, optionHeaders)
const response = await fetch(url, {
method: 'DELETE',
body: JSON.stringify(data),
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
})
if (!response.ok) return handleResponseError(response, requestId)
return handleResponse(response, requestId)
} catch (error) {
return handleError(error, requestId)
}
}

View File

@@ -1,27 +0,0 @@
import type { SupaResponse } from 'types/base'
import { uuidv4 } from '../../helpers'
import { constructHeaders, handleError, handleResponse, handleResponseError } from './base'
/**
* @deprecated Please use get method from data/fetchers instead, unless making requests to an external URL
*/
export async function get<T = any>(
url: string,
options?: { [prop: string]: any }
): Promise<SupaResponse<T>> {
const requestId = uuidv4()
try {
const { headers: optionHeaders, ...otherOptions } = options ?? {}
const headers = await constructHeaders(requestId, optionHeaders)
const response = await fetch(url, {
method: 'GET',
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
})
if (!response.ok) return handleResponseError(response, requestId)
return handleResponse(response, requestId)
} catch (error) {
return handleError(error, requestId)
}
}

View File

@@ -1,56 +0,0 @@
import { handleError, handleHeadResponse, handleResponseError, constructHeaders } from './base'
import { uuidv4 } from '../../helpers'
import type { SupaResponse } from 'types/base'
/**
* @deprecated please use head method from data/fetchers instead
*/
export async function head<T = any>(
url: string,
headersToRetrieve: string[],
options?: { [prop: string]: any }
): Promise<SupaResponse<T>> {
const requestId = uuidv4()
try {
const { headers: optionHeaders, ...otherOptions } = options ?? {}
const headers = await constructHeaders(requestId, optionHeaders)
const response = await fetch(url, {
method: 'HEAD',
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
})
if (!response.ok) return handleResponseError(response, requestId)
return handleHeadResponse(response, requestId, headersToRetrieve)
} catch (error) {
return handleError(error, requestId)
}
}
export async function headWithTimeout<T = any>(
url: string,
headersToRetrieve: string[],
options?: { [prop: string]: any }
): Promise<SupaResponse<T>> {
const requestId = uuidv4()
try {
const timeout = options?.timeout ?? 60000
const controller = new AbortController()
const id = setTimeout(() => controller.abort(), timeout)
const { headers: optionHeaders, ...otherOptions } = options ?? {}
const headers = await constructHeaders(requestId, optionHeaders)
const response = await fetch(url, {
method: 'HEAD',
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
signal: controller.signal,
})
clearTimeout(id)
if (!response.ok) return handleResponseError(response, requestId)
return handleHeadResponse(response, requestId, headersToRetrieve)
} catch (error) {
return handleError(error, requestId)
}
}

View File

@@ -1,16 +0,0 @@
// Even though this is a barrel file, the exports are all very similar
export {
constructHeaders,
handleError,
handleHeadResponse,
handleResponse,
handleResponseError,
isResponseOk,
} from './base'
export { delete_ } from './delete'
export { get } from './get'
export { head, headWithTimeout } from './head'
export { patch } from './patch'
export { post } from './post'
export { put } from './put'

View File

@@ -1,30 +0,0 @@
import { constructHeaders, handleError, handleResponse, handleResponseError } from './base'
import { uuidv4 } from '../../helpers'
import type { SupaResponse } from 'types/base'
/**
* @deprecated please use patch method from data/fetchers instead
*/
export async function patch<T = any>(
url: string,
data: { [prop: string]: any },
options?: { [prop: string]: any }
): Promise<SupaResponse<T>> {
const requestId = uuidv4()
try {
const { headers: optionHeaders, ...otherOptions } = options ?? {}
const headers = await constructHeaders(requestId, optionHeaders)
const response = await fetch(url, {
method: 'PATCH',
body: JSON.stringify(data),
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
})
if (!response.ok) return handleResponseError(response, requestId)
return handleResponse(response, requestId)
} catch (error) {
return handleError(error, requestId)
}
}

View File

@@ -1,32 +0,0 @@
import { uuidv4 } from 'lib/helpers'
import type { SupaResponse } from 'types/base'
import { constructHeaders, handleError, handleResponse, handleResponseError } from './base'
/**
* @deprecated Please use post method from data/fetchers instead
*
* Exception for bucket-object-download-mutation as openapi-fetch doesn't support octet-stream responses
*/
export async function post<T = any>(
url: string,
data: { [prop: string]: any },
options?: { [prop: string]: any }
): Promise<SupaResponse<T>> {
const requestId = uuidv4()
try {
const { headers: optionHeaders, abortSignal, ...otherOptions } = options ?? {}
const headers = await constructHeaders(requestId, optionHeaders)
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify(data),
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
signal: abortSignal,
})
if (!response.ok) return handleResponseError(response, requestId)
return handleResponse(response, requestId)
} catch (error) {
return handleError(error, requestId)
}
}

View File

@@ -1,31 +0,0 @@
import { constructHeaders, handleError, handleResponse, handleResponseError } from './base'
import { uuidv4 } from '../../helpers'
import type { SupaResponse } from 'types/base'
/**
* @deprecated please use post method from data/fetchers instead
*/
export async function put<T = any>(
url: string,
data: { [prop: string]: any },
options?: { [prop: string]: any }
): Promise<SupaResponse<T>> {
const requestId = uuidv4()
try {
const { headers: optionHeaders, ...otherOptions } = options ?? {}
const headers = await constructHeaders(requestId, optionHeaders)
const response = await fetch(url, {
method: 'PUT',
body: JSON.stringify(data),
credentials: 'include',
referrerPolicy: 'no-referrer-when-downgrade',
headers,
...otherOptions,
})
if (!response.ok) return handleResponseError(response, requestId)
return handleResponse(response, requestId)
} catch (error) {
return handleError(error, requestId)
}
}

View File

@@ -1,7 +1,7 @@
import { fetchHandler } from 'data/fetchers'
import type { Integration } from 'data/integrations/integrations.types'
import { ResponseError, type SupaResponse } from 'types'
import { isResponseOk } from './common/fetch'
import { isResponseOk } from './api/apiWrapper'
async function fetchGitHub<T = any>(url: string, responseJson = true): Promise<SupaResponse<T>> {
const response = await fetchHandler(url)

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import * as fetchModule from 'data/fetchers'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import pingPostgrest from './pingPostgrest'
import * as fetchModule from './common/fetch'
vi.mock('./constants', () => ({ API_URL: 'https://api.example.com' }))
@@ -9,14 +9,14 @@ describe('pingPostgrest', () => {
vi.restoreAllMocks()
})
it('returns true if headWithTimeout returns no error', async () => {
vi.spyOn(fetchModule, 'headWithTimeout').mockResolvedValue({ error: undefined })
it('returns true if fetchHeadWithTimeout returns no error', async () => {
vi.spyOn(fetchModule, 'fetchHeadWithTimeout').mockResolvedValue({ error: undefined })
const result = await pingPostgrest('my-project')
expect(result).toBe(true)
})
it('returns false if headWithTimeout returns an error', async () => {
vi.spyOn(fetchModule, 'headWithTimeout').mockResolvedValue({ error: { message: 'fail' } })
it('returns false if fetchHeadWithTimeout returns an error', async () => {
vi.spyOn(fetchModule, 'fetchHeadWithTimeout').mockResolvedValue({ error: { message: 'fail' } })
const result = await pingPostgrest('my-project')
expect(result).toBe(false)
})
@@ -26,8 +26,10 @@ describe('pingPostgrest', () => {
expect(result).toBe(false)
})
it('passes timeout option to headWithTimeout', async () => {
const spy = vi.spyOn(fetchModule, 'headWithTimeout').mockResolvedValue({ error: undefined })
it('passes timeout option to fetchHeadWithTimeout', async () => {
const spy = vi
.spyOn(fetchModule, 'fetchHeadWithTimeout')
.mockResolvedValue({ error: undefined })
await pingPostgrest('my-project', { timeout: 1234 })
expect(spy).toHaveBeenCalledWith(
'https://api.example.com/projects/my-project/api/rest',

View File

@@ -1,4 +1,4 @@
import { headWithTimeout } from './common/fetch'
import { fetchHeadWithTimeout } from 'data/fetchers'
import { API_URL } from './constants'
const DEFAULT_TIMEOUT_MILLISECONDS = 2000
@@ -33,7 +33,7 @@ export default pingPostgrest
* @return true if there's no error else false
*/
async function pingOpenApi(ref: string, timeout?: number) {
const { error } = await headWithTimeout(`${API_URL}/projects/${ref}/api/rest`, [], {
const { error } = await fetchHeadWithTimeout(`${API_URL}/projects/${ref}/api/rest`, [], {
timeout: timeout ?? DEFAULT_TIMEOUT_MILLISECONDS,
})
return error === undefined

View File

@@ -1,9 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { delete_, get, post } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
import { getPgMetaRedirectUrl } from './tables'
export default (req: NextApiRequest, res: NextApiResponse) =>
@@ -14,10 +13,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
@@ -26,39 +21,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(getPgMetaRedirectUrl(req, 'column-privileges'), {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = req.body
const response = await post(`${PG_META_URL}/column-privileges`, payload, {
headers,
})
const response = await fetchGet(getPgMetaRedirectUrl(req, 'column-privileges'), { headers })
if (response.error) {
console.error('Role POST:', response.error)
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = req.body
const response = await delete_(`${PG_META_URL}/column-privileges`, payload, { headers })
if (response.error) {
console.error('Role DELETE:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}

View File

@@ -1,80 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { constructHeaders, toSnakeCase } from 'lib/api/apiHelpers'
import { PG_META_URL } from 'lib/constants'
import { delete_, get, patch, post } from 'lib/common/fetch'
import { getPgMetaRedirectUrl } from './tables'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'PATCH':
return handlePatch(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET', 'POST', 'PATCH', 'DELETE'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
}
}
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(getPgMetaRedirectUrl(req, 'columns'), {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await post(`${PG_META_URL}/columns`, payload, {
headers,
})
if (response.error) {
console.error('Column POST:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePatch = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await patch(`${PG_META_URL}/columns/${req.query.id}`, payload, {
headers,
})
if (response.error) {
console.error('Column PATCH:', response)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await delete_(`${PG_META_URL}/columns/${req.query.id}`, {}, { headers })
if (response.error) {
console.error('Column DELETE:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}

View File

@@ -1,9 +1,9 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { PG_META_URL } from 'lib/constants'
import { get, post, delete_ } from 'lib/common/fetch'
import { constructHeaders, toSnakeCase } from 'lib/api/apiHelpers'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
@@ -14,10 +14,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
@@ -26,38 +22,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/extensions`, {
headers,
})
if (response.error) {
return res.status(400).json(response.error)
}
return res.status(200).json(response)
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await post(`${PG_META_URL}/extensions`, payload, {
headers,
})
const response = await fetchGet(`${PG_META_URL}/extensions`, { headers })
if (response.error) {
console.error('Extensions POST:', response.error)
return res.status(400).json(response.error)
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await delete_(`${PG_META_URL}/extensions/${req.query.id}`, {}, { headers })
if (response.error) {
console.error('Extensions DELETE:', response.error)
return res.status(400).json(response.error)
}
return res.status(200).json(response)
}

View File

@@ -1,9 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { get } from 'lib/common/fetch'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { PG_META_URL } from 'lib/constants'
import apiWrapper from 'lib/api/apiWrapper'
import { getPgMetaRedirectUrl } from './tables'
export default (req: NextApiRequest, res: NextApiResponse) =>
@@ -14,7 +13,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
if (req.query.id) return handleGetOne(req, res)
return handleGetAll(req, res)
default:
res.setHeader('Allow', ['GET'])
@@ -24,23 +22,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(getPgMetaRedirectUrl(req, 'foreign-tables'), {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
const response = await fetchGet(getPgMetaRedirectUrl(req, 'foreign-tables'), { headers })
return res.status(200).json(response)
}
const handleGetOne = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/foreign-tables/${req.query.id}`, {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}

View File

@@ -1,9 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { get } from 'lib/common/fetch'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { PG_META_URL } from 'lib/constants'
import apiWrapper from 'lib/api/apiWrapper'
import { getPgMetaRedirectUrl } from './tables'
export default (req: NextApiRequest, res: NextApiResponse) =>
@@ -14,7 +13,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
if (req.query.id) return handleGetOne(req, res)
return handleGetAll(req, res)
default:
res.setHeader('Allow', ['GET'])
@@ -24,23 +22,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(getPgMetaRedirectUrl(req, 'materialized-views'), {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
const response = await fetchGet(getPgMetaRedirectUrl(req, 'materialized-views'), { headers })
return res.status(200).json(response)
}
const handleGetOne = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/materialized-views/${req.query.id}`, {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}

View File

@@ -1,8 +1,9 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { get } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
import { NextApiRequest, NextApiResponse } from 'next'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
@@ -14,18 +15,19 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
case 'GET':
return handleGetAll(req, res)
default:
res.setHeader('Allow', ['GET', 'POST', 'PATCH', 'DELETE'])
res.setHeader('Allow', ['GET'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
}
}
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/policies`, {
headers,
})
const response = await fetchGet(`${PG_META_URL}/policies`, { headers })
if (response.error) {
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}

View File

@@ -1,8 +1,9 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { constructHeaders, toSnakeCase } from 'lib/api/apiHelpers'
import { PG_META_URL } from 'lib/constants'
import { delete_, get, patch, post } from 'lib/common/fetch'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
@@ -13,67 +14,20 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'PATCH':
return handlePatch(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET', 'POST', 'PATCH', 'DELETE'])
res.setHeader('Allow', ['GET'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
}
}
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/publications`, {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await post(`${PG_META_URL}/publications`, payload, {
headers,
})
const response = await fetchGet(`${PG_META_URL}/publications`, { headers })
if (response.error) {
console.error('Publication POST:', response.error)
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}
const handlePatch = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await patch(`${PG_META_URL}/publications/${req.query.id}`, payload, {
headers,
})
if (response.error) {
console.error('Publication PATCH:', response)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await delete_(`${PG_META_URL}/publications/${req.query.id}`, {}, { headers })
if (response.error) {
console.error('Publication DELETE:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}

View File

@@ -1,32 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { constructHeaders } from 'lib/api/apiHelpers'
import { PG_META_URL } from 'lib/constants'
import { post } from 'lib/common/fetch'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
switch (method) {
case 'POST':
return handlePost(req, res)
default:
res.setHeader('Allow', ['POST'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
}
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const { query } = req.body
const headers = constructHeaders(req.headers)
const response = await post(`${PG_META_URL}/query/format`, { query }, { headers })
if (response.error) {
return res.status(400).json({ error: response.error })
} else {
return res.status(200).json(response)
}
}

View File

@@ -1,32 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { constructHeaders } from 'lib/api/apiHelpers'
import { PG_META_URL } from 'lib/constants'
import { post } from 'lib/common/fetch'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
switch (method) {
case 'POST':
return handlePost(req, res)
default:
res.setHeader('Allow', ['POST'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
}
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const { query } = req.body
const headers = constructHeaders(req.headers)
const response = await post(`${PG_META_URL}/query/parse`, { query }, { headers })
if (response.error) {
return res.status(400).json({ valid: false, error: response.error })
} else {
return res.status(200).json({ valid: true })
}
}

View File

@@ -1,8 +1,9 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { PG_META_URL } from 'lib/constants'
import apiWrapper from 'lib/api/apiWrapper'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { delete_, get, patch, post } from 'lib/common/fetch'
import apiWrapper from 'lib/api/apiWrapper'
import { PG_META_URL } from 'lib/constants'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
@@ -12,16 +13,9 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
if (req.query.id) return handleGetOne(req, res)
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'PATCH':
return handlePatch(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET', 'POST', 'PATCH', 'DELETE'])
res.setHeader('Allow', ['GET'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
}
}
@@ -53,61 +47,12 @@ export function getPgMetaRedirectUrl(req: NextApiRequest, endpoint: string) {
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await fetchGet(getPgMetaRedirectUrl(req, 'tables'), { headers })
const response = await get(getPgMetaRedirectUrl(req, 'tables'), { headers })
if (response.error) {
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}
const handleGetOne = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/tables/${req.query.id}`, {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = req.body
const response = await post(`${PG_META_URL}/tables`, payload, {
headers,
})
if (response.error) {
console.error('Table POST:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePatch = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = req.body
const response = await patch(`${PG_META_URL}/tables/${req.query.id}`, payload, {
headers,
})
if (response.error) {
console.error('Table PATCH:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await delete_(`${PG_META_URL}/tables/${req.query.id}`, {}, { headers })
if (response.error) {
console.error('Table DELETE:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}

View File

@@ -1,7 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { constructHeaders, toSnakeCase } from 'lib/api/apiHelpers'
import { delete_, get, patch, post } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
export default (req: NextApiRequest, res: NextApiResponse) =>
@@ -13,67 +14,20 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'PATCH':
return handlePatch(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET', 'POST', 'PATCH', 'DELETE'])
res.setHeader('Allow', ['GET'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
}
}
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/triggers`, {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await post(`${PG_META_URL}/triggers`, payload, {
headers,
})
const response = await fetchGet(`${PG_META_URL}/triggers`, { headers })
if (response.error) {
console.error('Trigger POST:', response.error)
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}
const handlePatch = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await patch(`${PG_META_URL}/triggers/${req.query.id}`, payload, {
headers,
})
if (response.error) {
console.error('Trigger PATCH:', response)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await delete_(`${PG_META_URL}/triggers/${req.query.id}`, {}, { headers })
if (response.error) {
console.error('Trigger DELETE:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}

View File

@@ -1,8 +1,9 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { get } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
import { NextApiRequest, NextApiResponse } from 'next'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
@@ -21,11 +22,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await get(`${PG_META_URL}/types`, { headers })
const response = await fetchGet(`${PG_META_URL}/types`, { headers })
if (response.error) {
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}

View File

@@ -1,9 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { get } from 'lib/common/fetch'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { PG_META_URL } from 'lib/constants'
import apiWrapper from 'lib/api/apiWrapper'
import { getPgMetaRedirectUrl } from './tables'
export default (req: NextApiRequest, res: NextApiResponse) =>
@@ -14,7 +13,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
if (req.query.id) return handleGetOne(req, res)
return handleGetAll(req, res)
default:
res.setHeader('Allow', ['GET'])
@@ -24,23 +22,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(getPgMetaRedirectUrl(req, 'views'), {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
}
const response = await fetchGet(getPgMetaRedirectUrl(req, 'views'), { headers })
return res.status(200).json(response)
}
const handleGetOne = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
let response = await get(`${PG_META_URL}/views/${req.query.id}`, {
headers,
})
if (response.error) {
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json(response)
}

View File

@@ -1,9 +1,9 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { paths } from 'api-types'
import { fetchPost } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { post } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
@@ -25,7 +25,11 @@ type ResponseData =
const handleGet = async (req: NextApiRequest, res: NextApiResponse<ResponseData>) => {
const headers = constructHeaders(req.headers)
const response = await post(`${PG_META_URL}/query`, { query: enrichQuery(LINT_SQL) }, { headers })
const response = await fetchPost(
`${PG_META_URL}/query`,
{ query: enrichQuery(LINT_SQL) },
{ headers }
)
if (response.error) {
return res.status(400).json(response.error)
} else {

View File

@@ -1,8 +1,9 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { PG_META_URL } from 'lib/constants'
import apiWrapper from 'lib/api/apiWrapper'
import { fetchGet } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { get } from 'lib/common/fetch'
import apiWrapper from 'lib/api/apiWrapper'
import { PG_META_URL } from 'lib/constants'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
@@ -40,14 +41,15 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await get(
const response = await fetchGet(
`${PG_META_URL}/generators/typescript?included_schema=${includedSchema}&excluded_schemas=${excludedSchema}`,
{ headers }
)
if (response.error) {
return res.status(400).json({ error: response.error })
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
return res.status(200).json({ types: response })
}

View File

@@ -34,12 +34,7 @@ export default defineConfig({
reporters: [['default']],
coverage: {
reporter: ['lcov'],
exclude: [
'**/*.test.ts',
'**/*.test.tsx',
// 👇 Excluded because it will be deprecated.
'lib/common/fetch/**',
],
exclude: ['**/*.test.ts', '**/*.test.tsx'],
include: ['lib/**/*.ts'],
},
},