Skip to content
Written with Claude
IMPORTANT

As you may notice, this page and pretty much the entire website were obviously created with the help of AI. I wonder how you could tell? Was it a big "Written With Claude" badge on every page? I moved it to the top now (with the help of AI of course) to make it even more obvious. There are a few blogposts that were written by me manually, the old-fashioned way, I hope there will be more in the future, and those have a similar "Human Written" badge. This project (not the website), on the other hand, is a very, very different story. It took me more than two years of painstaking and unpaid work in my own free time. A story that, hopefully, I will tell someday. But meanwhile, what would you like me to do? To create a complex documentation website with a bunch of highly technical articles with the help of AI and fake it, to give you an illusion that I also did that manually? Like the half of itnernet is doing at this point? How does that makes any sense? Is that even fair to you? Or maybe to create this website manually, the old-fashioned way, just for you? While working a paid job for a salary, most of you wouldn't even get up in the morning. Would you like me to sing you a song while we're at it? For your personal entertainment? Seriously, get a grip. Do you find this information less valuable because of the way this website was created? I give my best to fix it to keep the information as accurate as possible, and I think it is very accurate at this point. If you find some mistakes, inaccurancies or problems, there is a comment section at the bottom of every page, which I also made with the help of the AI. And I woould very much appreciate if you leave your feedback there. Look, I'm just a guy who likes SQL, that's all. If you don't approve of how this website was constructed and the use of AI tools, I suggest closing this page and never wever coming back. And good riddance. And I would ban your access if I could know how. Thank you for your attention to this matter.

Proxy Options

Reverse proxy configuration for NpgsqlRest endpoints. When an endpoint is marked as a proxy, incoming HTTP requests are forwarded to an upstream service, and the response can either be returned directly to the client (passthrough mode) or processed by the PostgreSQL function (transform mode).

Overview

json
json
{
  "NpgsqlRest": {
    "ProxyOptions": {
      "Enabled": false,
      "Host": null,
      "DefaultTimeout": "00:00:30",
      "ForwardHeaders": true,
      "ExcludeHeaders": ["Host", "Content-Length", "Transfer-Encoding"],
      "ForwardResponseHeaders": true,
      "ExcludeResponseHeaders": ["Transfer-Encoding", "Content-Length"],
      "ResponseStatusCodeParameter": "_proxy_status_code",
      "ResponseBodyParameter": "_proxy_body",
      "ResponseHeadersParameter": "_proxy_headers",
      "ResponseContentTypeParameter": "_proxy_content_type",
      "ResponseSuccessParameter": "_proxy_success",
      "ResponseErrorMessageParameter": "_proxy_error_message",
      "ForwardUploadContent": false
    }
  }
}

Settings Reference

SettingTypeDefaultDescription
EnabledboolfalseEnable proxy functionality for endpoints with proxy annotations.
HoststringnullDefault upstream host URL. Can be overridden per endpoint with annotation.
DefaultTimeoutstring"00:00:30"Default timeout for proxy requests. Format: "HH:MM:SS" or interval format (e.g., "30s").
ForwardHeadersbooltrueForward request headers to upstream service.
ExcludeHeadersarray["Host", "Content-Length", "Transfer-Encoding"]Request headers to exclude from forwarding.
ForwardResponseHeadersbooltrueForward response headers from upstream to client.
ExcludeResponseHeadersarray["Transfer-Encoding", "Content-Length"]Response headers to exclude from forwarding.
ForwardUploadContentboolfalseForward raw multipart/form-data to upstream instead of processing locally.

Response Parameter Names

These settings configure which parameter names receive proxy response data:

SettingTypeDefaultDescription
ResponseStatusCodeParameterstring"_proxy_status_code"Parameter name for HTTP status code from upstream.
ResponseBodyParameterstring"_proxy_body"Parameter name for response body content.
ResponseHeadersParameterstring"_proxy_headers"Parameter name for response headers as JSON.
ResponseContentTypeParameterstring"_proxy_content_type"Parameter name for Content-Type header value.
ResponseSuccessParameterstring"_proxy_success"Parameter name for success indicator (true for 2xx status).
ResponseErrorMessageParameterstring"_proxy_error_message"Parameter name for error message if request failed.

Proxy Modes

Passthrough Mode

When the PostgreSQL function has no proxy response parameters, the upstream response is returned directly to the client without opening a database connection:

sql
sql
create function get_external_data()
returns void
language sql
begin atomic;
select;
end;

comment on function get_external_data() is 'HTTP GET
@proxy https://api.example.com/data';

Transform Mode

When the PostgreSQL function has parameters matching the configured response parameter names, the proxy response is passed to the function for processing:

sql
sql
create function get_and_transform(
    _proxy_status_code int default null,
    _proxy_body text default null,
    _proxy_headers json default null,
    _proxy_content_type text default null,
    _proxy_success boolean default null,
    _proxy_error_message text default null
)
returns json
language plpgsql as $$
begin
    if not _proxy_success then
        return json_build_object('error', _proxy_error_message);
    end if;
    return json_build_object(
        'status', _proxy_status_code,
        'data', _proxy_body::json
    );
end;
$$;

comment on function get_and_transform(int, text, json, text, boolean, text) is 'HTTP GET
@proxy https://api.example.com/data';

Response Parameters

When the PostgreSQL function has parameters matching these names, the proxy response data is passed to the function:

Parameter NameTypeDescription
_proxy_status_codeintHTTP status code from upstream (e.g., 200, 404).
_proxy_bodytextResponse body content.
_proxy_headersjsonResponse headers as JSON object.
_proxy_content_typetextContent-Type header value.
_proxy_successbooleanTrue for 2xx status codes.
_proxy_error_messagetextError message if request failed.

User Claims Forwarding

Query Parameters (user_params)

When user_params is enabled on the endpoint, user claim values are forwarded to the upstream proxy as query string parameters:

sql
sql
create function proxy_with_claims(
    _user_id text default null,        -- Forwarded as ?userId=...
    _user_name text default null,      -- Forwarded as ?userName=...
    _ip_address text default null,     -- Forwarded as ?ipAddress=...
    _user_claims json default null,    -- Forwarded as ?userClaims=...
    _proxy_status_code int default null,
    _proxy_body text default null
)
returns json language plpgsql as $$
begin
    return json_build_object('user', _user_id, 'data', _proxy_body);
end;
$$;

comment on function proxy_with_claims(text, text, text, json, int, text) is 'HTTP GET
@authorize
@user_params
@proxy https://api.example.com/data';

HTTP Headers (user_context)

When user_context is enabled, user context values are forwarded as HTTP headers to the upstream proxy:

sql
sql
create function proxy_with_context(
    _proxy_status_code int default null,
    _proxy_body text default null
)
returns json language plpgsql as $$
begin
    return json_build_object('status', _proxy_status_code);
end;
$$;

comment on function proxy_with_context(int, text) is 'HTTP GET
@authorize
@user_context
@proxy https://api.example.com/data';
-- Headers forwarded: request.user_id, request.user_name, request.user_roles
-- (configurable via ContextKeyClaimsMapping)

Upload Forwarding

For upload endpoints with proxy, configure whether to process uploads locally or forward raw multipart data:

json
json
{
  "NpgsqlRest": {
    "ProxyOptions": {
      "ForwardUploadContent": false
    }
  }
}
ValueDescription
false (default)Uploads are processed locally; proxy receives parsed data.
trueRaw multipart/form-data is streamed directly to upstream (memory-efficient for large files).

Key Features

  • Passthrough mode: No database connection opened when function has no proxy response parameters
  • Transform mode: Process upstream response in PostgreSQL before returning to client
  • User claims forwarding: Authenticated user claims passed as query parameters to upstream
  • User context headers: User context values passed as HTTP headers to upstream
  • Streaming uploads: Memory-efficient streaming for large file uploads when ForwardUploadContent is enabled
  • Timeout handling: Configurable per-request timeout with proper 504 Gateway Timeout responses
  • Header forwarding: Configurable request/response header forwarding with exclusion lists

Complete Example

Production configuration with proxy enabled:

json
json
{
  "NpgsqlRest": {
    "ProxyOptions": {
      "Enabled": true,
      "Host": "https://api.internal.example.com",
      "DefaultTimeout": "00:00:30",
      "ForwardHeaders": true,
      "ExcludeHeaders": ["Host", "Content-Length", "Transfer-Encoding", "Authorization"],
      "ForwardResponseHeaders": true,
      "ExcludeResponseHeaders": ["Transfer-Encoding", "Content-Length"],
      "ForwardUploadContent": false
    }
  }
}

Next Steps

Comments