---
title: Get a PostgreSQL connection string
summary: Return a ready-to-use PostgreSQL connection string, with host injected client-side.
status: draft
owner: Framework.NCore maintainers
last_reviewed: 2026-10-02
library: SAIF.NetCore.DBConnectionClient
reference_type: package
operation_id: OP-DBC-04
trigger: Caller invokes GetPostgreSqlServerConnection
---

# Get a PostgreSQL connection string

This operation returns a fully formatted PostgreSQL connection string. Unlike SQL Server and Oracle, the PostgreSQL host is not managed by the DBConnectionAPI: the API returns a template with a `{SERVER}` placeholder, and this operation substitutes the caller-supplied server after retrieval.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-DBC-04 |
| **Trigger** | Caller invokes `GetPostgreSqlServerConnection(server, instance, userName)` |
| **Inputs** | `server` (host), `instance`, `userName` |
| **Outputs** | Full PostgreSQL connection string with the host substituted |
| **Primary components** | `ConnectionClient.GetPostgreSqlServerConnection` |
| **Entry point** | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs` |

## Steps

1. Build the cache key `POSTGRES_{instance}_{userName}` — note that `server` is **not** part of the key ([BR-DBC-04](../business-rules.md#br-dbc-04-cache-keys-are-engine-prefixed), [BR-DBC-05](../business-rules.md#br-dbc-05-postgresql-host-is-managed-client-side)).
2. Build the URL path `/{PostgreSqlEndpoint}/{instance}/{userName}` — `server` is not sent to the API ([BR-DBC-05](../business-rules.md#br-dbc-05-postgresql-host-is-managed-client-side)).
3. Acquire the instance-wide connection-string lock and check the cache for this key. On a cache hit, release the lock and skip to step 5 with the cached template.
4. On a cache miss (still under the lock): validate the backoff configuration, then call `HttpClient.GetAsync(urlPath)` in a loop of up to `MaxRetrieveAttempts` (4, by default). A successful non-empty response is decoded, cached (as the un-substituted template — `server` is not part of the cached value), and used below. HTTP 401/403/404 fail fast with no retry ([BR-DBC-09](../business-rules.md#br-dbc-09-401%2F403%2F404-are-permanent-failures)). A 503 or network-level error is transient and retries with fixed backoff (2s, 3s, 5s) until attempts are exhausted ([BR-DBC-10](../business-rules.md#br-dbc-10-503-or-network-level-failure-is-transient)). Any other non-success or an empty body fails immediately ([BR-DBC-11](../business-rules.md#br-dbc-11-other-failures-and-empty-bodies-fail-immediately)). A failed attempt is never cached; the lock is released once the outcome (value or exception) is determined.
   - > **Origin**: Steps 3.1–3.5 of [Cached lookup](cached-lookup.md), which embed the retry and classification logic from [Retrieve with retry](retrieve-with-retry.md), are executed on behalf of this operation.
5. Replace the literal `{SERVER}` placeholder in the template with the caller-supplied `server` ([BR-DBC-05](../business-rules.md#br-dbc-05-postgresql-host-is-managed-client-side)).
   - Because the cache holds the un-substituted template, different hosts sharing the same instance and user reuse a single fetch.

## Process flow

```mermaid
flowchart TD
	Start([GetPostgreSqlServerConnection called]) --> Key["Build key POSTGRES_instance_userName, no server"]
	Key --> Path[Build URL path /PostgreSqlEndpoint/instance/userName]
	Path --> Lock["Acquire lock, check cache"]
	Lock --> Hit{Cache hit?}
	Hit -->|Yes| Substitute
	Hit -->|No| Get["GetAsync, up to 4 attempts"]
	Get --> Outcome{Outcome}
	Outcome -->|Success| Substitute["Replace literal SERVER placeholder with caller server"]
	Outcome -->|"401/403/404"| FailFast(["Throw DBClientException, no retry"])
	Outcome -->|"503/network error"| Retry["Backoff 2s/3s/5s, retry or throw"]
	Outcome -->|Other failure| ImmediateFail(["Throw DBClientException"])
	Substitute --> Return([Return connection string])
```

## Failure and edge-case behavior
- If the returned template has no `{SERVER}` placeholder, `String.Replace` leaves the string unchanged; this library does not validate the host or the final connection-string structure, so a template that already embeds a literal host would still be returned as-is, while one that genuinely omits the host would return a connection string missing it*.
- Any exception from the underlying cached lookup propagates to the caller unchanged.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs`
