Edge Functions

Logging and Using Headers

How to log the headers received and use them.

When debugging Edge Functions, a common mistake is to try to log headers to the developer console via code like this:

index.ts

_12
Deno.serve(async (req) => {
_12
const headers = JSON.stringify(req.headers)
_12
console.log(`Request headers: ${headers}`)
_12
// OR
_12
console.log(`Request headers: ${JSON.stringify(req.headers)}`)
_12
return new Response('ok', {
_12
headers: {
_12
'Content-Type': 'application/json',
_12
},
_12
status: 200,
_12
})
_12
})

Both attempts will give as output the string "{}", even though retrieving the value using request.headers.get("Your-Header-Name") will indeed give you the correct value. This behavior mirrors that of browsers.

The reason behind this behavior is that Headers objects don't store headers in JavaScript properties that can be enumerated. As a result, neither the developer console nor the JSON stringifier can properly interpret the names and values of the headers. Essentially, it's not an empty object, but rather an opaque one.

However, Headers objects are iterable. You can utilize this feature to craft a couple of succinct one-liners for debugging and printing headers.

Convert headers into an object with Object.fromEntries:

You can use Object.fromEntries which is a call to convert the headers into an object:

index.ts

_11
Deno.serve(async (req) => {
_11
let headersObject = Object.fromEntries(req.headers)
_11
let requestHeaders = JSON.stringify(headersObject, null, 2)
_11
console.log(`Request headers: ${requestHeaders}`)
_11
return new Response('ok', {
_11
headers: {
_11
'Content-Type': 'application/json',
_11
},
_11
status: 200,
_11
})
_11
})

This results in something like:

index.ts

_19
Request headers: {
_19
"accept": "*/*",
_19
"accept-encoding": "gzip",
_19
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InN1cGFuYWNobyIsInJvbGUiOiJhbm9uIiwieW91IjoidmVyeSBzbmVha3ksIGh1aD8iLCJpYXQiOjE2NTQ1NDA5MTYsImV4cCI6MTk3MDExNjkxNn0.cwBbk2tq-fUcKF1S0jVKkOAG2FIQSID7Jjvff5Do99Y",
_19
"cdn-loop": "cloudflare; subreqs=1",
_19
"cf-ew-via": "15",
_19
"cf-ray": "8597a2fcc558a5d7-GRU",
_19
"cf-visitor": "{\"scheme\":\"https\"}",
_19
"cf-worker": "supabase.co",
_19
"content-length": "20",
_19
"content-type": "application/x-www-form-urlencoded",
_19
"host": "edge-runtime.supabase.com",
_19
"my-custom-header": "abcd",
_19
"user-agent": "curl/8.4.0",
_19
"x-deno-subhost": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6InN1cGFiYXNlIn0.eyJkZXBsb3ltZW50X2lkIjoic3VwYW5hY2hvX2M1ZGQxMWFiLTFjYmUtNDA3NS1iNDAxLTY3ZTRlZGYxMjVjNV8wMDciLCJycGNfcm9vdCI6Imh0dHBzOi8vc3VwYWJhc2Utb3JpZ2luLmRlbm8uZGV2L3YwLyIsImV4cCI6MTcwODYxMDA4MiwiaWF0IjoxNzA4NjA5MTgyfQ.-fPid2kEeEM42QHxWeMxxv2lJHZRSkPL-EhSH0r_iV4",
_19
"x-forwarded-host": "edge-runtime.supabase.com",
_19
"x-forwarded-port": "443",
_19
"x-forwarded-proto": "https"
_19
}