Skip to content

Commit

Permalink
Merge pull request #75 from supabase/feat-add-regional-options
Browse files Browse the repository at this point in the history
Feat add regional options
  • Loading branch information
mansueli authored Jan 31, 2024
2 parents 1470363 + 4a5b2d3 commit 45f40ae
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 2 deletions.
13 changes: 12 additions & 1 deletion src/FunctionsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,30 @@ import {
FunctionsRelayError,
FunctionsResponse,
FunctionInvokeOptions,
FunctionRegion,
} from './types'

export class FunctionsClient {
protected url: string
protected headers: Record<string, string>
protected region: FunctionRegion
protected fetch: Fetch

constructor(
url: string,
{
headers = {},
customFetch,
region = FunctionRegion.Any,
}: {
headers?: Record<string, string>
customFetch?: Fetch
region?: FunctionRegion
} = {}
) {
this.url = url
this.headers = headers
this.region = region
this.fetch = resolveFetch(customFetch)
}

Expand All @@ -47,8 +52,14 @@ export class FunctionsClient {
): Promise<FunctionsResponse<T>> {
try {
const { headers, method, body: functionArgs } = options

let _headers: Record<string, string> = {}
let { region } = options
if (!region) {
region = this.region
}
if (region && region !== 'any') {
_headers['x-region'] = region
}
let body: any
if (
functionArgs &&
Expand Down
22 changes: 22 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ export class FunctionsHttpError extends FunctionsError {
super('Edge Function returned a non-2xx status code', 'FunctionsHttpError', context)
}
}
// Define the enum for the 'region' property
export enum FunctionRegion {
Any = 'any',
ApNortheast1 = 'ap-northeast-1',
ApNortheast2 = 'ap-northeast-2',
ApSouth1 = 'ap-south-1',
ApSoutheast1 = 'ap-southeast-1',
ApSoutheast2 = 'ap-southeast-2',
CaCentral1 = 'ca-central-1',
EuCentral1 = 'eu-central-1',
EuWest1 = 'eu-west-1',
EuWest2 = 'eu-west-2',
EuWest3 = 'eu-west-3',
SaEast1 = 'sa-east-1',
UsEast1 = 'us-east-1',
UsWest1 = 'us-west-1',
UsWest2 = 'us-west-2',
}

export type FunctionInvokeOptions = {
/**
Expand All @@ -50,6 +68,10 @@ export type FunctionInvokeOptions = {
* The HTTP verb of the request
*/
method?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE'
/**
* The Region to invoke the function in.
*/
region?: FunctionRegion;
/**
* The body of the request.
*/
Expand Down
154 changes: 153 additions & 1 deletion test/spec/params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { sign } from 'jsonwebtoken'
import { ContentType } from 'allure-js-commons'

import { FunctionsClient } from '../../src/index'

import { FunctionRegion } from '../../src/types'
import { Relay, runRelay } from '../relay/container'
import { attach, log } from '../utils/jest-custom-reporter'
import { str2ab } from '../utils/binaries'
Expand Down Expand Up @@ -146,6 +146,158 @@ describe('params reached to function', () => {
).toBe(true)
})

test('invoke mirror set valid region on request', async () => {
/**
* @feature headers
*/
log('create FunctionsClient')
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`)

log('invoke mirror')
const customHeader = nanoid()
const validRegion = FunctionRegion.ApNortheast1

const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
headers: {
'custom-header': customHeader,
Authorization: `Bearer ${apiKey}`,
},
region: validRegion,
})

log('assert no error')
const expected = {
url: 'http://localhost:8000/mirror',
method: 'POST',
headers: data?.headers ?? [],
body: '',
}
expect(data).toEqual(expected)
attach(
'check headers from function',
`expected to include: ${['custom-header', customHeader]}\n actual: ${JSON.stringify(
data?.headers
)}`,
ContentType.TEXT
)
console.log(data?.headers)
expect(
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === validRegion)
.length > 0
).toBe(true)
})

test('invoke with region overrides region in the client', async () => {
/**
* @feature headers
*/
log('create FunctionsClient')
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`, {
region: FunctionRegion.ApNortheast1,
})

log('invoke mirror')
const customHeader = nanoid()
const validRegion = FunctionRegion.ApSoutheast1

const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
headers: {
'custom-header': customHeader,
Authorization: `Bearer ${apiKey}`,
},
region: validRegion,
})

log('assert no error')
const expected = {
url: 'http://localhost:8000/mirror',
method: 'POST',
headers: data?.headers ?? [],
body: '',
}
expect(data).toEqual(expected)
attach(
'check headers from function',
`expected to include: ${['custom-header', customHeader]}\n actual: ${JSON.stringify(
data?.headers
)}`,
ContentType.TEXT
)
console.log(data?.headers)
expect(
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === validRegion)
.length > 0
).toBe(true)
})

test('starts client with default region, invoke reverts to any (no x-region header)', async () => {
/**
* @feature headers
*/
log('create FunctionsClient')
const validRegion = FunctionRegion.ApSoutheast1
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`, {
region: validRegion,
})

log('invoke mirror')
const customHeader = nanoid()

const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
headers: {
'custom-header': customHeader,
Authorization: `Bearer ${apiKey}`,
},
region: FunctionRegion.Any
})

log('assert no error')
const expected = {
url: 'http://localhost:8000/mirror',
method: 'POST',
headers: data?.headers ?? [],
body: '',
}
expect(data).toEqual(expected)
attach(
'check headers from function',
`expected to include: ${['custom-header', customHeader]}\n actual: ${JSON.stringify(
data?.headers
)}`,
ContentType.TEXT
)
console.log(data?.headers)
expect(
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === validRegion)
.length == 0
).toBe(true)
})

test('invoke region set only on the constructor', async () => {
/**
* @feature headers
*/
log('create FunctionsClient')
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`,{region: FunctionRegion.ApNortheast1})

log('invoke mirror')
const customHeader = nanoid()


const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
headers: {
'custom-header': customHeader,
Authorization: `Bearer ${apiKey}`
},
})

log('assert no error')
expect(
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === FunctionRegion.ApNortheast1)
.length > 0
).toBe(true)
})

test('invoke mirror with body formData', async () => {
/**
* @feature body
Expand Down

0 comments on commit 45f40ae

Please sign in to comment.