supabase / pg_graphql

GraphQL support for PostgreSQL
https://supabase.github.io/pg_graphql
Apache License 2.0
2.9k stars 102 forks source link

provide request metadata #400

Open chaoky opened 1 year ago

chaoky commented 1 year ago

Summary

set the "request.headers" setting to the graphql request headers

Rationale

this functionality is already offered by supabase postgrest and it's very useful for i18n

Examples

create function "public"."_body"("public"."notifications")
returns setof "public"."translations" rows 1
language sql as
$$
select * from "public"."translations"
where id = $1.body_id and
language = current_setting('request.headers', true)::json->>'accept-language'
limit 1
$$;

Alternatives

in hasura, the metadata is injected into computed fields as an argument

olirice commented 1 year ago

This should already be the case. Are you seeing something different?

On supabase the /graphql/v1/ endpoint goes through PostgREST RPC so those headers are still available. Thats also how the role management works

chaoky commented 1 year ago

in a fresh supabase local instance

create table "public"."notifications" (
    "id" bigint generated by default as identity not null
);

create function "public"."_test"("public"."notifications")
returns json
language sql as
$$
select current_setting('request.headers', true)::json
$$;

with this query

{
  notificationsCollection {
    edges {
      node {
        test
      }
    }
  }
}

besides Authorization, all of the other headers seem static

{
  "x-forwarded-port": "8000",
  "x-real-ip": "172.21.0.11",
  "host": "supabase_rest_dashboard:3000",
  "x-forwarded-host": "supabase_kong_dashboard",
  "content-type": "application/json",
  "accept": "*/*",
  "sec-fetch-mode": "cors",
  "apikey": "...",
  "accept-language": "*",
  "x-forwarded-prefix": "/graphql/v1",
  "x-forwarded-proto": "http",
  "x-forwarded-path": "/graphql/v1",
  "user-agent": "undici",
  "authorization": "Bearer ...",
  "content-length": "150",
  "accept-encoding": "gzip, deflate",
  "x-forwarded-for": "172.21.0.11",
  "connection": "keep-alive",
  "content-profile": "graphql_public"
}
olirice commented 1 year ago

Reproduced by adding a customer header "Fooooo" via GraphiQL and returning the response

Screenshot 2023-08-01 at 6 09 23 AM

@steve-chavez is there a way to forward custom headers so they're visible in he db or are they stripped for security?

steve-chavez commented 1 year ago

Hm, no header is stripped. All headers (including custom) are passed.

Can you guys try with a plain curl call? Not sure how that UI works for sending headers.

imor commented 1 year ago

I tried with curl with the same result. If PostgREST is not stripping custom headers then it could be some other proxy or gateway along the route.

steve-chavez commented 1 year ago

@imor Hm, how about trying with a header like Prefer: return=representation? This is one that PostgREST needs and should pass unmodified by any proxy.

Also can you share the curl snippet?

steve-chavez commented 1 year ago

besides Authorization, all of the other headers seem static "accept-language": "*",

Also, I do see the accept-language in the request.headers output ^.

imor commented 1 year ago

I sent the request using GraphiQL and then from the browser dev tools copied it as a curl command using the "Copy as cURL" context menu option. Here's the command line (edited to omit jwt):

curl "https://api.supabase.io/platform/projects/wcteuwpjlocwxcjvgtkp/api/graphql" -H "authority: api.supabase.io" -H "accept: application/json, multipart/mixed" -H "accept-language: en-US,en;q=0.8" -H "authorization: Bearer <omitted>" -H "content-type: application/json" -H "origin: https://supabase.com" -H "prefer: return=representation" -H "referer: https://supabase.com/" -H "sec-ch-ua: \"Not/A)Brand\";v=\"99\", \"Brave\";v=\"115\", \"Chromium\";v=\"115\"" -H "sec-ch-ua-mobile: ?0" -H "sec-ch-ua-platform: \"Windows\"" -H "sec-fetch-dest: empty" -H "sec-fetch-mode: cors" -H "sec-fetch-site: cross-site" -H "sec-gpc: 1" -H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36" -H "x-graphql-authorization: Bearer <omitted>" --data-raw "{\"query\":\"{  usersCollection {    edges {      node {        test1      }    }  }}\"}"

And these are the headers I get back (formatted for readability):

{
  "baggage": "sentry-environment=production,sentry-release=d5bbed201eb20cc0a1af86619f58cea24cee017d,sentry-public_key=d5e18af8274946988586aab9276cd108,sentry-trace_id=cf9372e30f4e4002b4eb9d6b8bbb3185,sentry-sample_rate=0.002",
  "cf-ipcountry": "FR",
  "cf-visitor": "{\"scheme\":\"https\"}",
  "x-forwarded-port": "443",
  "x-real-ip": "172.71.134.144",
  "host": "localhost:3000",
  "x-consumer-username": "service_role-key",
  "cf-worker": "supabase.co",
  "x-forwarded-host": "wcteuwpjlocwxcjvgtkp.supabase.co",
  "sentry-trace": "cf9372e30f4e4002b4eb9d6b8bbb3185-b06142310af2d6b7-0",
  "accept": "*/*",
  "cf-ray": "7f0d03d771d3f18c-CDG",
  "x-forwarded-prefix": "/graphql/v1",
  "x-consumer-id": "777f6130-904b-5657-ba5f-1e56d7f28356",
  "x-credential-identifier": "764f2ba4-c7e4-5675-8f8d-83fa1c813e09",
  "x-forwarded-proto": "https",
  "x-forwarded-path": "/graphql/v1",
  "user-agent": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)",
  "authorization": "Bearer <omitted>",
  "content-length": "84",
  "cf-ew-via": "15",
  "accept-encoding": "gzip",
  "x-forwarded-for": "167.88.159.69, 172.71.134.144",
  "connection": "keep-alive",
  "cf-connecting-ip": "167.88.159.69",
  "content-profile": "graphql_public",
  "cdn-loop": "cloudflare; subreqs=1"
}

The prefer: return=representation header is missing.

steve-chavez commented 1 year ago

It's really strange because we have had many discussions around using request.headers for custom logic and it has been working normally. For example, see https://github.com/orgs/supabase/discussions/4419#discussioncomment-4321279

So there must be something up with the graphql endpoint, maybe Kong is stripping the headers.

GaryAustin1 commented 1 year ago

image PostgREST on latest version using Supabase-js passes thru custom headers. See the header custom:"hi there"