mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat: reorg function docs and add videos.
This commit is contained in:
1 parent
d47aa83064
commit
36c366b564
14 files changed
+533
-236
No files matched your search
@@ -421,14 +421,28 @@ export const functions = {
|
||||
label: 'Edge Functions',
|
||||
url: '/guides/functions',
|
||||
items: [
|
||||
{ name: 'Overview', url: '/guides/functions/overview', items: [] },
|
||||
{ name: 'Auth', url: '/guides/functions/auth', items: [] },
|
||||
{ name: 'CORS', url: '/guides/functions/cors', items: [] },
|
||||
{ name: 'CI/CD Workflow', url: '/guides/functions/cicd-workflow', items: [] },
|
||||
{ name: 'Best Practices', url: '/guides/functions/best-practices', items: [] },
|
||||
{ name: 'Quickstart', url: '/guides/functions/quickstart', items: [] },
|
||||
{ name: 'Managing Secrets', url: '/guides/functions/secrets', items: [] },
|
||||
{ name: 'Testing & Debugging', url: '/guides/functions/testing-debugging', items: [] },
|
||||
{ name: 'Tips', url: '/guides/functions/tips', items: [] },
|
||||
{
|
||||
name: 'Examples',
|
||||
url: '/guides/functions/examples',
|
||||
items: [{ name: 'OG Image', url: '/guides/functions/examples/og-image', items: [] }],
|
||||
items: [
|
||||
{
|
||||
name: 'Cloudflare Turnstile',
|
||||
url: '/guides/functions/examples/cloudflare-turnstile',
|
||||
items: [],
|
||||
},
|
||||
{ name: 'GitHub Actions', url: '/guides/functions/examples/github-actions', items: [] },
|
||||
{ name: 'OG Image', url: '/guides/functions/examples/og-image', items: [] },
|
||||
{ name: 'Storage Caching', url: '/guides/functions/examples/storage-caching', items: [] },
|
||||
{ name: 'Stripe Webhooks', url: '/guides/functions/examples/stripe-webhooks', items: [] },
|
||||
{ name: 'Telegram Bot', url: '/guides/functions/examples/telegram-bot', items: [] },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -35,6 +35,15 @@ jobs:
|
||||
- run: supabase functions deploy your-function-name --project-ref $PROJECT_ID
|
||||
```
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/6OMVWiiycLs"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
See the [example on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/.github/workflows/deploy.yaml).
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'functions-cors',
|
||||
title: 'CORS (Cross-Origin Resource Sharing)',
|
||||
description: 'Add CORS headers to invoke functions from the browser.',
|
||||
}
|
||||
|
||||
To invoke the functions from the browser, you need to handle [CORS Preflight](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) requests.
|
||||
|
||||
See the [example on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/browser-with-cors/index.ts).
|
||||
|
||||
### Recommended setup
|
||||
|
||||
We recommend adding a `corst.ts` file within a `_shared` folder which makes it easy to reuse the CORS headers across functions:
|
||||
|
||||
```ts cors.ts
|
||||
export const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
||||
}
|
||||
```
|
||||
|
||||
You can then import and use the CORS headers within your functions:
|
||||
|
||||
```ts index.ts
|
||||
import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
|
||||
import { corsHeaders } from '../_shared/cors.ts'
|
||||
|
||||
console.log(`Function "browser-with-cors" up and running!`)
|
||||
|
||||
serve(async (req) => {
|
||||
// This is needed if you're planning to invoke your function from a browser.
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response('ok', { headers: corsHeaders })
|
||||
}
|
||||
|
||||
try {
|
||||
const { name } = await req.json()
|
||||
const data = {
|
||||
message: `Hello ${name}!`,
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify(data), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 200,
|
||||
})
|
||||
} catch (error) {
|
||||
return new Response(JSON.stringify({ error: error.message }), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 400,
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,96 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'examples-cloudflare-turnstile',
|
||||
title: 'Cloudflare Turnstile',
|
||||
description: 'Protecting Forms with Cloudflare Turnstile.',
|
||||
}
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/OwW0znboh60"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
[Clouflare Turnstile](https://www.cloudflare.com/products/turnstile/) is a friendly, free CAPTCHA replacement, and it works seamlessly with Supabase Edge Functions to protect your forms. [View on GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/cloudflare-turnstile).
|
||||
|
||||
## Setup
|
||||
|
||||
- Follow these steps to set up a new site: https://developers.cloudflare.com/turnstile/get-started/
|
||||
- Add the Cloudflare Turnstile widget to your site: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/
|
||||
|
||||
## Code
|
||||
|
||||
Create a new function in your project:
|
||||
|
||||
```bash
|
||||
supabase functions new cloudflare-turnstile
|
||||
```
|
||||
|
||||
And add the code to the `index.ts` file:
|
||||
|
||||
```ts index.ts
|
||||
import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
|
||||
import { corsHeaders } from '../_shared/cors.ts'
|
||||
|
||||
console.log('Hello from Cloudflare Trunstile!')
|
||||
|
||||
function ips(req: Request) {
|
||||
return req.headers.get('x-forwarded-for')?.split(/\s*,\s*/)
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
// This is needed if you're planning to invoke your function from a browser.
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response('ok', { headers: corsHeaders })
|
||||
}
|
||||
|
||||
const { token } = await req.json()
|
||||
const clientIps = ips(req) || ['']
|
||||
const ip = clientIps[0]
|
||||
|
||||
// Validate the token by calling the
|
||||
// "/siteverify" API endpoint.
|
||||
let formData = new FormData()
|
||||
formData.append('secret', Deno.env.get('CLOUDFLARE_SECRET_KEY') ?? '')
|
||||
formData.append('response', token)
|
||||
formData.append('remoteip', ip)
|
||||
|
||||
const url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'
|
||||
const result = await fetch(url, {
|
||||
body: formData,
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
const outcome = await result.json()
|
||||
console.log(outcome)
|
||||
if (outcome.success) {
|
||||
return new Response('success', { headers: corsHeaders })
|
||||
}
|
||||
return new Response('failure', { headers: corsHeaders })
|
||||
})
|
||||
```
|
||||
|
||||
## Deploy the server-side validation Edge Functions
|
||||
|
||||
- https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
|
||||
|
||||
```bash
|
||||
supabase functions deploy cloudflare-turnstile
|
||||
supabase secrets set CLOUDFLARE_TURNSTILE_SECRET_KEY=your_secret_key
|
||||
```
|
||||
|
||||
## Invoke the function from your site
|
||||
|
||||
```js
|
||||
const { data, error } = await supabase.functions.invoke('cloudflare-turnstile', {
|
||||
body: { token },
|
||||
})
|
||||
```
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,49 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'examples-github-actions',
|
||||
title: 'GitHub Actions',
|
||||
description: 'Deploying Edge Functions with GitHub Actions.',
|
||||
}
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/6OMVWiiycLs"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
Use the Supabase CLI together with GitHub Actions to automatically deploy our Supabase Edge Functions. [View on GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/github-action-deploy).
|
||||
|
||||
```yaml deploy.yaml
|
||||
name: Deploy Function
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
|
||||
PROJECT_ID: zdtdtxajzydjqzuktnqx
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: supabase/setup-cli@v1
|
||||
with:
|
||||
version: 1.0.0
|
||||
|
||||
- run: supabase functions deploy github-action-deploy --project-ref $PROJECT_ID
|
||||
```
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -17,6 +17,10 @@ export const meta = {
|
||||
|
||||
Generate Open Graph images with Deno and Supabase Edge Functions. [View on GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/opengraph).
|
||||
|
||||
## Code
|
||||
|
||||
Create a `handler.tsx` file to construct the OG image in React:
|
||||
|
||||
```tsx handler.tsx
|
||||
import React from 'https://esm.sh/react@18.2.0'
|
||||
import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts'
|
||||
@@ -42,6 +46,8 @@ export default function handler(req: Request) {
|
||||
}
|
||||
```
|
||||
|
||||
Create an `index.ts` file to execute the handler on incoming requests:
|
||||
|
||||
```ts index.ts
|
||||
import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
|
||||
import handler from './handler.tsx'
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'examples-storage-caching',
|
||||
title: 'Caching Images with Supabase Storage CDN',
|
||||
description: 'Integrate Edge Functions with Supabase Storage to cache images on the Edge (CDN).',
|
||||
}
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/wW6L52v9Ldo"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
Integrate Edge Functions with Supabase Storage to cache images on the Edge (CDN). [View on GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/og-image-with-storage-cdn).
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,22 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'examples-stripe-webhooks',
|
||||
title: 'Handling Stripe Webhooks',
|
||||
description: 'Handling signed Stripe Webhooks with Edge Functions.',
|
||||
}
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/6OMVWiiycLs"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
Handling signed Stripe Webhooks with Edge Functions. [View on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/stripe-webhooks/index.ts).
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,22 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'examples-telegram-bot',
|
||||
title: 'Telegram Bot',
|
||||
description: 'Building a Telegram Bot with Edge Functions.',
|
||||
}
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/AWfE3a9J_uo"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
Handle Telegram Bot Webhooks with the [grammY framework](https://grammy.dev/). grammY is an open source Telegram Bot Framework which makes it easy to handle and respond to incoming messages. [View on GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/telegram-bot).
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,84 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'functions-overview',
|
||||
title: 'Edge Functions Overview',
|
||||
description: 'Globally distributed TypeScript Functions.',
|
||||
sidebar_label: 'Overview',
|
||||
}
|
||||
|
||||
Learn how to build an Edge Function locally and deploy it to the Supabase Platform in less than 7 minutes.
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/rzglqRdZUQE"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Follow the steps to prepare your Supabase project on your local machine.
|
||||
|
||||
- Install the Supabase CLI. [Docs](/docs/guides/cli).
|
||||
- Login to the CLI using the command: `supabase login`. [Docs](/docs/reference/cli/usage#supabase-login).
|
||||
- Initialize Supabase inside your project using the command: `supabase init`. [Docs](/docs/guides/cli/local-development#getting-started).
|
||||
- Link to your Remote Project using the command `supabase link --project-ref your-project-ref`. [Docs](/docs/reference/cli/usage#supabase-link).
|
||||
- Optional: Setup your environment: Follow [this setup guide](https://deno.land/manual/getting_started/setup_your_environment) to integrate the Deno language server with your editor.
|
||||
|
||||
## Create a function
|
||||
|
||||
Let's create a new Edge Function called `hello-world` inside your project:
|
||||
|
||||
```bash
|
||||
supabase functions new hello-world
|
||||
```
|
||||
|
||||
This creates a function stub in your `supabase` folder at `./functions/hello-world/index.ts`.
|
||||
|
||||
## Deploy to production
|
||||
|
||||
```bash
|
||||
supabase functions deploy hello-world
|
||||
```
|
||||
|
||||
This command bundles your Edge Function from `./functions/hello-world/index.ts` and deploys it to the Supabase platform.
|
||||
The command outputs a URL to the Supabase Dashboard which you can open to find view more details. Let's open the link to find the execution command.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
By default, Edge Functions require a valid JWT in the authorization header. This header is automatically set when invoking your function via a Supabase client library.
|
||||
|
||||
If you want to use Edge Functions to handle webhooks (e.g. [Stripe payment webhooks](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks) etc.), you need to pass the `--no-verify-jwt` flag when deploying your function.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Execute remote functions
|
||||
|
||||
You can execute Edge Functions using curl. Copy the curl command from the Dashboard. It should look like this:
|
||||
|
||||
```bash
|
||||
curl --request POST 'https://<project_ref>.functions.supabase.co/hello-world' \
|
||||
--header 'Authorization: Bearer ANON_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{ "name":"Functions" }'
|
||||
```
|
||||
|
||||
If you receive an error `Invalid JWT`, find the `ANON_KEY` of your project in the Dashboard under `Settings > API`.
|
||||
|
||||
After invoking your Edge Function you should see the response `{ "message":"Hello Functions!" }`.
|
||||
|
||||
## Limitations
|
||||
|
||||
- Deno Deploy limitations
|
||||
- Deno does not support outgoing connections to ports `25`, `465`, and `587`.
|
||||
- Cannot write to File System
|
||||
- Edge Functions
|
||||
- Local development - only one function at a time
|
||||
- Serving of HTML content is not supported (`GET` requests that return `text/html` will be rewritten to `text/plain`).
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -1,210 +0,0 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'functions-quickstart',
|
||||
title: 'Edge Functions Quickstart',
|
||||
description: 'Globally distributed TypeScript functions.',
|
||||
sidebar_label: 'Quickstart',
|
||||
}
|
||||
|
||||
Learn how to build an Edge Function locally and deploy it to the Supabase Platform in less than 7 minutes.
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/rzglqRdZUQE"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Follow the steps to prepare your Supabase project on your local machine.
|
||||
|
||||
- Install the Supabase CLI. [Docs](/docs/guides/cli).
|
||||
- Login to the CLI using the command: `supabase login`. [Docs](/docs/reference/cli/usage#supabase-login).
|
||||
- Initialize Supabase inside your project using the command: `supabase init`. [Docs](/docs/guides/cli/local-development#getting-started).
|
||||
- Link to your Remote Project using the command `supabase link --project-ref your-project-ref`. [Docs](/docs/reference/cli/usage#supabase-link).
|
||||
- Optional: Setup your environment: Follow [this setup guide](https://deno.land/manual/getting_started/setup_your_environment) to integrate the Deno language server with your editor.
|
||||
|
||||
## Create a function
|
||||
|
||||
Let's create a new Edge Function called `hello-world` inside your project:
|
||||
|
||||
```bash
|
||||
supabase functions new hello-world
|
||||
```
|
||||
|
||||
This creates a function stub in your `supabase` folder at `./functions/hello-world/index.ts`.
|
||||
|
||||
## Deploy to production
|
||||
|
||||
```bash
|
||||
supabase functions deploy hello-world
|
||||
```
|
||||
|
||||
This command bundles your Edge Function from `./functions/hello-world/index.ts` and deploys it to the Supabase platform.
|
||||
The command outputs a URL to the Supabase Dashboard which you can open to find view more details. Let's open the link to find the execution command.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
By default, Edge Functions require a valid JWT in the authorization header. This header is automatically set when invoking your function via a Supabase client library.
|
||||
|
||||
If you want to use Edge Functions to handle webhooks (e.g. [Stripe payment webhooks](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks) etc.), you need to pass the `--no-verify-jwt` flag when deploying your function.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Execute remote functions
|
||||
|
||||
You can execute Edge Functions using curl. Copy the curl command from the Dashboard. It should look like this:
|
||||
|
||||
```bash
|
||||
curl --request POST 'https://<project_ref>.functions.supabase.co/hello-world' \
|
||||
--header 'Authorization: Bearer ANON_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{ "name":"Functions" }'
|
||||
```
|
||||
|
||||
If you receive an error `Invalid JWT`, find the `ANON_KEY` of your project in the Dashboard under `Settings > API`.
|
||||
|
||||
After invoking your Edge Function you should see the response `{ "message":"Hello Functions!" }`.
|
||||
|
||||
## Debug functions
|
||||
|
||||
You can debug your deployed Edge Functions using the "Functions" section of the Dashboard. There are two types debugging tools available:
|
||||
|
||||
- Invocations: shows the Request and Response for each execution.
|
||||
- Logs: shows any platform events, including deployments and errors.
|
||||
|
||||

|
||||
|
||||
## Develop locally
|
||||
|
||||
You can run your Edge Function locally using [`supabase functions serve`](/docs/reference/cli/usage#supabase-functions-serve):
|
||||
|
||||
```bash
|
||||
supabase start # start the supabase stack
|
||||
supabase functions serve hello-world # start the Function watcher
|
||||
```
|
||||
|
||||
The `functions serve` command has hot-reloading capabilities. It will watch for any changes to your files and restart the Deno server.
|
||||
|
||||
### Invoke functions locally
|
||||
|
||||
While serving your local Function, you can execute it using curl:
|
||||
|
||||
```bash
|
||||
curl --request POST 'http://localhost:54321/functions/v1/hello-world' \
|
||||
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{ "name":"Functions" }'
|
||||
```
|
||||
|
||||
You should see the response `{ "message":"Hello Functions!" }`.
|
||||
|
||||
<details>
|
||||
<summary>Implementation details</summary>
|
||||
|
||||
- Edge Functions don't serve HTML content (`GET` requests that return `text/html` are rewritten to `text/plain`).
|
||||
- The `Authorization` header is required. You can use either the `ANON` key, the `SERVICE_ROLE` key, or a logged-in user's JWT.
|
||||
- The Function is proxied through the local API (`http://localhost:54321`)
|
||||
|
||||
</details>
|
||||
<br />
|
||||
|
||||
If you execute Function with a different payload the response will change. <br />
|
||||
Modify the `--data '{"name":"Functions"}'` line to `--data '{"name":"World"}'` and try invoking the command again!
|
||||
|
||||
## Secrets and Environment Variables
|
||||
|
||||
It's common that you will need to use sensitive information or environment-specific variables inside your Edge Functions. You can access these using Deno's built-in handler
|
||||
|
||||
```js
|
||||
Deno.env.get(MY_SECRET_NAME)
|
||||
```
|
||||
|
||||
### Default secrets
|
||||
|
||||
By default, Edge Functions have access to these secrets:
|
||||
|
||||
- `SUPABASE_URL`: The API gateway for your Supabase project.
|
||||
- `SUPABASE_ANON_KEY`: The `anon` key for your Supabase API. This is safe to use in a browser when you have [Row Level Security](/docs/guides/auth/row-level-security) enabled.
|
||||
- `SUPABASE_SERVICE_ROLE_KEY`: The `service_role` key for your Supabase API. This is safe to use in Edge Functions, but it should NEVER be used in a browser. This key will bypass [Row Level Security](/docs/guides/auth/row-level-security).
|
||||
- `SUPABASE_DB_URL`: The URL for your [PostgreSQL database](/docs/guides/database). You can use this to connect directly to your database.
|
||||
|
||||
### Local secrets
|
||||
|
||||
Let's create a local file for storing our secrets, and inside it we can store a secret `MY_NAME`:
|
||||
|
||||
```jsx
|
||||
echo "MY_NAME=Yoda" >> ./supabase/.env.local
|
||||
```
|
||||
|
||||
This creates a new file `./supabase/.env.local` for storing your local development secrets.
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Never check your .env files into Git!
|
||||
|
||||
</Admonition>
|
||||
|
||||
Now let's access this environment variable `MY_NAME` inside our Function. Anywhere in your function, add this line:
|
||||
|
||||
```jsx
|
||||
console.log(Deno.env.get('MY_NAME'))
|
||||
```
|
||||
|
||||
Now we can invoke our function locally, by serving it with our new `.env.local` file:
|
||||
|
||||
```bash
|
||||
supabase functions serve hello-world --env-file ./supabase/.env.local
|
||||
```
|
||||
|
||||
When the function starts you should see the name “Yoda” output to the terminal.
|
||||
|
||||
### Production secrets
|
||||
|
||||
Let's create a `.env` for production. In this case we'll just use the same as our local secrets:
|
||||
|
||||
```bash
|
||||
cp ./supabase/.env.local ./supabase/.env
|
||||
```
|
||||
|
||||
This creates a new file `./supabase/.env` for storing your production secrets.
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Never check your `.env` files into Git!
|
||||
|
||||
</Admonition>
|
||||
|
||||
Let's push all the secrets from the `.env` file to our remote project using [`supabase secrets set`](/docs/reference/cli/usage#supabase-secrets-set):
|
||||
|
||||
```bash
|
||||
supabase secrets set --env-file ./supabase/.env
|
||||
|
||||
# You can also set secrets individually using:
|
||||
supabase secrets set MY_NAME=Chewbacca
|
||||
```
|
||||
|
||||
You don't need to re-deploy after setting your secrets.
|
||||
|
||||
To see all the secrets which you have set remotely, use [`supabase secrets list`](/docs/reference/cli/usage#supabase-secrets-list):
|
||||
|
||||
```bash
|
||||
supabase secrets list
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- Deno Deploy limitations
|
||||
- Deno does not support outgoing connections to ports `25`, `465`, and `587`.
|
||||
- Cannot write to File System
|
||||
- Edge Functions
|
||||
- Local development - only one function at a time
|
||||
- Serving of HTML content is not supported (`GET` requests that return `text/html` will be rewritten to `text/plain`).
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,89 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'functions-secrets',
|
||||
title: 'Secrets and Environment Variables',
|
||||
description: 'Managing secrets and environment variables.',
|
||||
}
|
||||
|
||||
It's common that you will need to use sensitive information or environment-specific variables inside your Edge Functions. You can access these using Deno's built-in handler
|
||||
|
||||
```js
|
||||
Deno.env.get(MY_SECRET_NAME)
|
||||
```
|
||||
|
||||
### Default secrets
|
||||
|
||||
By default, Edge Functions have access to these secrets:
|
||||
|
||||
- `SUPABASE_URL`: The API gateway for your Supabase project.
|
||||
- `SUPABASE_ANON_KEY`: The `anon` key for your Supabase API. This is safe to use in a browser when you have [Row Level Security](/docs/guides/auth/row-level-security) enabled.
|
||||
- `SUPABASE_SERVICE_ROLE_KEY`: The `service_role` key for your Supabase API. This is safe to use in Edge Functions, but it should NEVER be used in a browser. This key will bypass [Row Level Security](/docs/guides/auth/row-level-security).
|
||||
- `SUPABASE_DB_URL`: The URL for your [PostgreSQL database](/docs/guides/database). You can use this to connect directly to your database.
|
||||
|
||||
### Local secrets
|
||||
|
||||
Let's create a local file for storing our secrets, and inside it we can store a secret `MY_NAME`:
|
||||
|
||||
```jsx
|
||||
echo "MY_NAME=Yoda" >> ./supabase/.env.local
|
||||
```
|
||||
|
||||
This creates a new file `./supabase/.env.local` for storing your local development secrets.
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Never check your .env files into Git!
|
||||
|
||||
</Admonition>
|
||||
|
||||
Now let's access this environment variable `MY_NAME` inside our Function. Anywhere in your function, add this line:
|
||||
|
||||
```jsx
|
||||
console.log(Deno.env.get('MY_NAME'))
|
||||
```
|
||||
|
||||
Now we can invoke our function locally, by serving it with our new `.env.local` file:
|
||||
|
||||
```bash
|
||||
supabase functions serve hello-world --env-file ./supabase/.env.local
|
||||
```
|
||||
|
||||
When the function starts you should see the name “Yoda” output to the terminal.
|
||||
|
||||
### Production secrets
|
||||
|
||||
Let's create a `.env` for production. In this case we'll just use the same as our local secrets:
|
||||
|
||||
```bash
|
||||
cp ./supabase/.env.local ./supabase/.env
|
||||
```
|
||||
|
||||
This creates a new file `./supabase/.env` for storing your production secrets.
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Never check your `.env` files into Git!
|
||||
|
||||
</Admonition>
|
||||
|
||||
Let's push all the secrets from the `.env` file to our remote project using [`supabase secrets set`](/docs/reference/cli/usage#supabase-secrets-set):
|
||||
|
||||
```bash
|
||||
supabase secrets set --env-file ./supabase/.env
|
||||
|
||||
# You can also set secrets individually using:
|
||||
supabase secrets set MY_NAME=Chewbacca
|
||||
```
|
||||
|
||||
You don't need to re-deploy after setting your secrets.
|
||||
|
||||
To see all the secrets which you have set remotely, use [`supabase secrets list`](/docs/reference/cli/usage#supabase-secrets-list):
|
||||
|
||||
```bash
|
||||
supabase secrets list
|
||||
```
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,55 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'functions-testing-debugging',
|
||||
title: 'Testing and Debugging Functions',
|
||||
description: 'Test and debug functions locally and in production.',
|
||||
}
|
||||
|
||||
You can debug your deployed Edge Functions using the "Functions" section of the Dashboard. There are two types debugging tools available:
|
||||
|
||||
- Invocations: shows the Request and Response for each execution.
|
||||
- Logs: shows any platform events, including deployments and errors.
|
||||
|
||||

|
||||
|
||||
## Develop locally
|
||||
|
||||
You can run your Edge Function locally using [`supabase functions serve`](/docs/reference/cli/usage#supabase-functions-serve):
|
||||
|
||||
```bash
|
||||
supabase start # start the supabase stack
|
||||
supabase functions serve hello-world # start the Function watcher
|
||||
```
|
||||
|
||||
The `functions serve` command has hot-reloading capabilities. It will watch for any changes to your files and restart the Deno server.
|
||||
|
||||
### Invoke functions locally
|
||||
|
||||
While serving your local Function, you can execute it using curl:
|
||||
|
||||
```bash
|
||||
curl --request POST 'http://localhost:54321/functions/v1/hello-world' \
|
||||
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{ "name":"Functions" }'
|
||||
```
|
||||
|
||||
You should see the response `{ "message":"Hello Functions!" }`.
|
||||
|
||||
<details>
|
||||
<summary>Implementation details</summary>
|
||||
|
||||
- Edge Functions don't serve HTML content (`GET` requests that return `text/html` are rewritten to `text/plain`).
|
||||
- The `Authorization` header is required. You can use either the `ANON` key, the `SERVICE_ROLE` key, or a logged-in user's JWT.
|
||||
- The Function is proxied through the local API (`http://localhost:54321`)
|
||||
|
||||
</details>
|
||||
<br />
|
||||
|
||||
If you execute Function with a different payload the response will change. <br />
|
||||
Modify the `--data '{"name":"Functions"}'` line to `--data '{"name":"World"}'` and try invoking the command again!
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
+3
-23
@@ -1,9 +1,9 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'functions-best-practices',
|
||||
title: 'Edge Functions Best Practices',
|
||||
description: 'Globally distributed TypeScript functions.',
|
||||
id: 'functions-tips',
|
||||
title: 'Edge Functions Tips',
|
||||
description: 'Misc Tips for Supabase Edge Functions.',
|
||||
}
|
||||
|
||||
## Database Functions vs Edge Functions
|
||||
@@ -35,26 +35,6 @@ We recommend developing “fat functions”. This means that you should develop
|
||||
|
||||
We recommend using hyphens to name functions because hyphens are the most URL-friendly of all the naming conventions (snake_case, camelCase, PascalCase).
|
||||
|
||||
## CORS (Cross-Origin Resource Sharing)
|
||||
|
||||
We recommend adding a check to handle [CORS Preflight](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) requests in your edge function to be able to invoke the function from browsers.
|
||||
|
||||
See the [example on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/browser-with-cors/index.ts).
|
||||
|
||||
```ts
|
||||
export const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey',
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response('ok', { headers: corsHeaders })
|
||||
}
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
## Using HTTP Methods
|
||||
|
||||
Edge Functions supports `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`. A function can be designed to perform different actions based on a request's HTTP method. See the [example on building a RESTful service](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/restful-tasks) to learn how to handle different HTTP methods in your function.
|
||||
Reference in new issue
Block a user