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:
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.
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.
// 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 { withSupabase } from 'npm:@supabase/server@^1'import type { SupabaseClient } from 'npm:@supabase/supabase-js@^2'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 Response.json({ task })}async function getAllTasks(supabaseClient: SupabaseClient) { const { data: tasks, error } = await supabaseClient.from('tasks').select('*') if (error) throw error return Response.json({ tasks })}async function deleteTask(supabaseClient: SupabaseClient, id: string) { const { error } = await supabaseClient.from('tasks').delete().eq('id', id) if (error) throw error return Response.json({})}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 Response.json({ task })}async function createTask(supabaseClient: SupabaseClient, task: Task) { const { error } = await supabaseClient.from('tasks').insert(task) if (error) throw error return Response.json({ task })}export default { fetch: withSupabase({ auth: 'user' }, async (req, ctx) => { const { url, method } = req try { // ctx.supabase is scoped to the calling user, so your row-level-security // (RLS) policies are applied. const supabaseClient = ctx.supabase // 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 Response.json({ error: error.message }, { status: 400 }) } }),}