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:
1Deno.serve(async (req) => {2 const { method, url } = req3 const { pathname } = new URL(url)45 // Route based on method and path6 if (method === 'GET' && pathname === '/users') {7 return getAllUsers()8 } else if (method === 'POST' && pathname === '/users') {9 return createUser(req)10 }1112 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.
HTML content is not supported. GET requests that return text/html will be rewritten to text/plain. Edge Functions are designed for APIs and data processing, not serving web pages. Use Supabase for your backend API and your favorite frontend framework for HTML.
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_environment3// This enables autocomplete, go to definition, etc.45import { createClient, SupabaseClient } from 'npm:supabase-js@2'67const corsHeaders = {8 'Access-Control-Allow-Origin': '*',9 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey',10 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE',11}1213interface Task {14 name: string15 status: number16}1718async function getTask(supabaseClient: SupabaseClient, id: string) {19 const { data: task, error } = await supabaseClient.from('tasks').select('*').eq('id', id)20 if (error) throw error2122 return new Response(JSON.stringify({ task }), {23 headers: { ...corsHeaders, 'Content-Type': 'application/json' },24 status: 200,25 })26}2728async function getAllTasks(supabaseClient: SupabaseClient) {29 const { data: tasks, error } = await supabaseClient.from('tasks').select('*')30 if (error) throw error3132 return new Response(JSON.stringify({ tasks }), {33 headers: { ...corsHeaders, 'Content-Type': 'application/json' },34 status: 200,35 })36}3738async function deleteTask(supabaseClient: SupabaseClient, id: string) {39 const { error } = await supabaseClient.from('tasks').delete().eq('id', id)40 if (error) throw error4142 return new Response(JSON.stringify({}), {43 headers: { ...corsHeaders, 'Content-Type': 'application/json' },44 status: 200,45 })46}4748async function updateTask(supabaseClient: SupabaseClient, id: string, task: Task) {49 const { error } = await supabaseClient.from('tasks').update(task).eq('id', id)50 if (error) throw error5152 return new Response(JSON.stringify({ task }), {53 headers: { ...corsHeaders, 'Content-Type': 'application/json' },54 status: 200,55 })56}5758async function createTask(supabaseClient: SupabaseClient, task: Task) {59 const { error } = await supabaseClient.from('tasks').insert(task)60 if (error) throw error6162 return new Response(JSON.stringify({ task }), {63 headers: { ...corsHeaders, 'Content-Type': 'application/json' },64 status: 200,65 })66}6768Deno.serve(async (req) => {69 const { url, method } = req7071 // This is needed if you're planning to invoke your function from a browser.72 if (method === 'OPTIONS') {73 return new Response('ok', { headers: corsHeaders })74 }7576 try {77 // Create a Supabase client with the Auth context of the logged in user.78 const supabaseClient = createClient(79 // Supabase API URL - env var exported by default.80 Deno.env.get('SUPABASE_URL') ?? '',81 // Supabase API ANON KEY - env var exported by default.82 Deno.env.get('SUPABASE_ANON_KEY') ?? '',83 // Create client with Auth context of the user that called the function.84 // This way your row-level-security (RLS) policies are applied.85 {86 global: {87 headers: { Authorization: req.headers.get('Authorization')! },88 },89 }90 )9192 // For more details on URLPattern, check https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API93 const taskPattern = new URLPattern({ pathname: '/restful-tasks/:id' })94 const matchingPath = taskPattern.exec(url)95 const id = matchingPath ? matchingPath.pathname.groups.id : null9697 let task = null98 if (method === 'POST' || method === 'PUT') {99 const body = await req.json()100 task = body.task101 }102103 // call relevant method based on method and id104 switch (true) {105 case id && method === 'GET':106 return getTask(supabaseClient, id as string)107 case id && method === 'PUT':108 return updateTask(supabaseClient, id as string, task)109 case id && method === 'DELETE':110 return deleteTask(supabaseClient, id as string)111 case method === 'POST':112 return createTask(supabaseClient, task)113 case method === 'GET':114 return getAllTasks(supabaseClient)115 default:116 return getAllTasks(supabaseClient)117 }118 } catch (error) {119 console.error(error)120121 return new Response(JSON.stringify({ error: error.message }), {122 headers: { ...corsHeaders, 'Content-Type': 'application/json' },123 status: 400,124 })125 }126})