Edge Functions

Routing

Handle different request types in a single function to create efficient APIs.


Overview

Edge Functions support GET, POST, PUT, PATCH, DELETE, and OPTIONS. This means you can build complete REST APIs in a single function:

1
Deno.serve(async (req) => {
2
const { method, url } = req
3
const { pathname } = new URL(url)
4
5
// Route based on method and path
6
if (method === 'GET' && pathname === '/users') {
7
return getAllUsers()
8
} else if (method === 'POST' && pathname === '/users') {
9
return createUser(req)
10
}
11
12
return new Response('Not found', { status: 404 })
13
})

Edge Functions allow you to build APIs without needing separate functions for each endpoint. This reduces cold starts and simplifies deployment while keeping your code organized.


Example

Here's a full example of a RESTful API built with Edge Functions.

1
// Follow this setup guide to integrate the Deno language server with your editor:
2
// https://deno.land/manual/getting_started/setup_your_environment
3
// This enables autocomplete, go to definition, etc.
4
5
import { createClient, SupabaseClient } from 'npm:supabase-js@2'
6
// New approach (v2.95.0+)
7
import { corsHeaders } from 'jsr:@supabase/supabase-js@2/cors'
8
// For older versions, use hardcoded headers:
9
// const corsHeaders = {
10
// 'Access-Control-Allow-Origin': '*',
11
// 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
12
// 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE',
13
// }
14
15
interface Task {
16
name: string
17
status: number
18
}
19
20
async function getTask(supabaseClient: SupabaseClient, id: string) {
21
const { data: task, error } = await supabaseClient.from('tasks').select('*').eq('id', id)
22
if (error) throw error
23
24
return new Response(JSON.stringify({ task }), {
25
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
26
status: 200,
27
})
28
}
29
30
async function getAllTasks(supabaseClient: SupabaseClient) {
31
const { data: tasks, error } = await supabaseClient.from('tasks').select('*')
32
if (error) throw error
33
34
return new Response(JSON.stringify({ tasks }), {
35
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
36
status: 200,
37
})
38
}
39
40
async function deleteTask(supabaseClient: SupabaseClient, id: string) {
41
const { error } = await supabaseClient.from('tasks').delete().eq('id', id)
42
if (error) throw error
43
44
return new Response(JSON.stringify({}), {
45
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
46
status: 200,
47
})
48
}
49
50
async function updateTask(supabaseClient: SupabaseClient, id: string, task: Task) {
51
const { error } = await supabaseClient.from('tasks').update(task).eq('id', id)
52
if (error) throw error
53
54
return new Response(JSON.stringify({ task }), {
55
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
56
status: 200,
57
})
58
}
59
60
async function createTask(supabaseClient: SupabaseClient, task: Task) {
61
const { error } = await supabaseClient.from('tasks').insert(task)
62
if (error) throw error
63
64
return new Response(JSON.stringify({ task }), {
65
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
66
status: 200,
67
})
68
}
69
70
Deno.serve(async (req) => {
71
const { url, method } = req
72
73
// This is needed if you're planning to invoke your function from a browser.
74
if (method === 'OPTIONS') {
75
return new Response('ok', { headers: corsHeaders })
76
}
77
78
try {
79
// Create a Supabase client with the Auth context of the logged in user.
80
const supabaseClient = createClient(
81
// Supabase API URL - env var exported by default.
82
Deno.env.get('SUPABASE_URL') ?? '',
83
// Supabase API ANON KEY - env var exported by default.
84
Deno.env.get('SUPABASE_ANON_KEY') ?? '',
85
// Create client with Auth context of the user that called the function.
86
// This way your row-level-security (RLS) policies are applied.
87
{
88
global: {
89
headers: { Authorization: req.headers.get('Authorization')! },
90
},
91
}
92
)
93
94
// For more details on URLPattern, check https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API
95
const taskPattern = new URLPattern({ pathname: '/restful-tasks/:id' })
96
const matchingPath = taskPattern.exec(url)
97
const id = matchingPath ? matchingPath.pathname.groups.id : null
98
99
let task = null
100
if (method === 'POST' || method === 'PUT') {
101
const body = await req.json()
102
task = body.task
103
}
104
105
// call relevant method based on method and id
106
switch (true) {
107
case id && method === 'GET':
108
return getTask(supabaseClient, id as string)
109
case id && method === 'PUT':
110
return updateTask(supabaseClient, id as string, task)
111
case id && method === 'DELETE':
112
return deleteTask(supabaseClient, id as string)
113
case method === 'POST':
114
return createTask(supabaseClient, task)
115
case method === 'GET':
116
return getAllTasks(supabaseClient)
117
default:
118
return getAllTasks(supabaseClient)
119
}
120
} catch (error) {
121
console.error(error)
122
123
return new Response(JSON.stringify({ error: error.message }), {
124
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
125
status: 400,
126
})
127
}
128
})
View source