Files
supabase/apps/docs/app/api/utils.ts
Charis aba0095bd7 feat(content api): add error endpoint (#35941)
* feat(content api): add error endpoint

Add an endpoint to return the details of a Supabase error, given the
error code and service.

Schema additions:

```graphql
type RootQueryType {
  "...previous root queries"

  """Get the details of an error code returned from a Supabase service"""
  error(code: String!, service: Service!): Error
}

"""An error returned by a Supabase service"""
type Error {
  """
  The unique code identifying the error. The code is stable, and can be used for string matching during error handling.
  """
  code: String!

  """The Supabase service that returns this error."""
  service: Service!

  """The HTTP status code returned with this error."""
  httpStatusCode: Int

  """
  A human-readable message describing the error. The message is not stable, and should not be used for string matching during error handling. Use the code instead.
  """
  message: String
}

enum Service {
  AUTH
  REALTIME
  STORAGE
}
```

* test(content api): add tests for top-level query `error`
2025-05-29 15:39:47 -04:00

85 lines
1.8 KiB
TypeScript

import { type PostgrestError } from '@supabase/supabase-js'
import { type ZodError } from 'zod'
type ObjectOrNever = object | never
export type ApiErrorGeneric = ApiError<ObjectOrNever>
export class ApiError<Details extends ObjectOrNever = never> extends Error {
constructor(
message: string,
public source?: unknown,
public details?: Details
) {
super(message)
}
isPrivate() {
return true
}
isUserError() {
return false
}
statusCode() {
return 500
}
}
export class InvalidRequestError<Details extends ObjectOrNever = never> extends ApiError<Details> {
constructor(message: string, source?: unknown, details?: Details) {
super(`Invalid request: ${message}`, source, details)
}
isPrivate() {
return false
}
isUserError() {
return true
}
statusCode() {
return 400
}
}
export class NoDataError<Details extends ObjectOrNever = never> extends ApiError<Details> {
constructor(message: string, source?: unknown, details?: Details) {
super(`Data not found: ${message}`, source, details)
}
isPrivate() {
return false
}
isUserError() {
return true
}
statusCode() {
return 404
}
}
export function convertUnknownToApiError(error: unknown): ApiError {
return new ApiError('Unknown error', error)
}
export function convertPostgrestToApiError(error: PostgrestError): ApiError {
const message = `${error.code}: ${error.hint}`
return new ApiError(message, error)
}
export function convertZodToInvalidRequestError(
error: ZodError,
prelude?: string
): InvalidRequestError {
const issue = error.issues[0]
const pathStr = issue.path.join('.')
const message = `${prelude ? `${prelude}: ` : ''}${issue.message} at key "${pathStr}"`
return new InvalidRequestError(message, error)
}