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

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