Skip to content

Comment Annotations Guide

NpgsqlRest uses PostgreSQL's built-in COMMENT system to configure API endpoints declaratively. This guide explains how comment annotations work and how to use them effectively.

How Annotations Work

Comment annotations are special keywords placed in PostgreSQL comments that control how endpoints are generated and configured. The annotation parser reads comments line by line, looking for recognized keywords at the start of each line.

Basic Rules

  1. Annotations must start at the beginning of a line - the keyword must be the first text on the line
  2. Keywords are case-insensitive - HTTP, http, and Http are all valid
  3. Unrecognized text is ignored - you can mix documentation with annotations
  4. Multiple annotations per comment - use separate lines for each annotation

Simple Example

sql
comment on function get_users() is
'Returns all active users from the database.
HTTP GET
authorize';

This comment contains:

  • Documentation text (ignored by parser)
  • HTTP GET annotation - exposes as GET endpoint
  • authorize annotation - requires authentication

The HTTP Annotation

The HTTP annotation is the primary way to expose a function or table as an endpoint. Without it (when using the default CommentsMode: OnlyWithHttpTag), the object won't be exposed.

Syntax Variations

sql
-- Basic: expose with default method and path
comment on function my_func() is 'HTTP';

-- With HTTP method
comment on function my_func() is 'HTTP GET';
comment on function my_func() is 'HTTP POST';

-- With custom path
comment on function my_func() is 'HTTP /custom-path';

-- With method and path
comment on function my_func() is 'HTTP GET /users/list';

Default Behavior

When method is not specified:

  • GET is used for non-volatile functions, or functions with names starting with get_, containing _get_, or ending with _get
  • POST is used otherwise

When path is not specified, it's generated from the function name using the URL prefix and naming conventions from configuration.

Authorization Annotations

Control access to endpoints with authorization annotations.

Require Authentication

sql
-- Require any authenticated user
comment on function protected_func() is
'HTTP
authorize';

-- Require specific roles
comment on function admin_func() is
'HTTP
authorize admin';

-- Multiple roles (user must have at least one)
comment on function staff_func() is
'HTTP
authorize admin manager supervisor';

Allow Anonymous Access

sql
comment on function public_func() is
'HTTP
allow_anonymous';

This overrides the global RequiresAuthorization setting for this specific endpoint.

Response Headers

Set custom response headers by using the Header-Name: value format:

sql
comment on function get_html_page() is
'HTTP GET
Content-Type: text/html
Cache-Control: public, max-age=3600';

comment on function get_data() is
'HTTP GET
X-Custom-Header: custom-value
X-Another-Header: another-value';

Multiple headers with the same name are supported:

sql
comment on function with_cookies() is
'HTTP
Set-Cookie: session=abc123
Set-Cookie: theme=dark';

Request Parameter Configuration

Control how parameters are transmitted to the endpoint.

Query String vs Body

sql
-- Force query string parameters
comment on function search(_query text) is
'HTTP GET
request_param_type query_string';

-- Force JSON body parameters
comment on function create_user(_name text, _email text) is
'HTTP POST
request_param_type body_json';

Caching

Enable response caching for scalar results:

sql
-- Simple caching
comment on function get_settings() is
'HTTP GET
cached';

-- Cache with specific parameters as cache key
comment on function get_user_profile(_user_id int) is
'HTTP GET
cached _user_id';

-- Set cache expiration
comment on function get_config() is
'HTTP GET
cached
cache_expires_in 1h';

Cache expiration uses PostgreSQL interval format: 10s, 5m, 1h, 1d, etc.

Raw Output Mode

Return raw text instead of JSON:

sql
-- Basic raw mode
comment on function export_text() is
'HTTP GET
raw';

-- CSV export with custom formatting
comment on function export_csv() is
'HTTP GET
raw
separator ,
new_line \n
columns';

The columns annotation includes column names as the first row.

Combining Annotations

Annotations can be combined freely. Order doesn't matter:

sql
comment on function get_report(_department text) is
'Generates a department report.
This is a cached endpoint requiring manager access.

HTTP GET /reports/department
authorize manager admin
cached _department
cache_expires_in 30m
Content-Type: application/json
Cache-Control: private, max-age=1800';

Debugging Annotations

To see which annotations are applied when NpgsqlRest starts, set the logging level to Debug:

In appsettings.json:

json
{
  "Log": {
    "MinimalLevels": {
      "NpgsqlRest": "Debug"
    }
  }
}

Via command line:

bash
npgsqlrest --Log:MinimalLevels:NpgsqlRest=Debug

This will log each annotation as it's parsed and applied to endpoints.

Comments Mode

The CommentsMode configuration setting controls how annotations affect endpoint creation:

ModeBehavior
OnlyWithHttpTagOnly create endpoints for objects with HTTP annotation (default)
ParseAllCreate all endpoints, parse annotations to modify them
IgnoreCreate all endpoints, ignore all annotations

Common Patterns

Public Read, Protected Write

sql
comment on function get_products() is
'HTTP GET
allow_anonymous';

comment on function create_product(_name text, _price numeric) is
'HTTP POST
authorize admin';

API Versioning with Custom Paths

sql
comment on function get_users_v1() is 'HTTP GET /v1/users';
comment on function get_users_v2() is 'HTTP GET /v2/users';

Secure Sensitive Operations

sql
comment on function change_password(_old text, _new text) is
'HTTP POST
authorize
sensitive';

The sensitive annotation prevents parameter values from appearing in logs.

Rate Limiting

sql
comment on function expensive_operation() is
'HTTP POST
rate_limiter bucket';

The policy name must match a policy configured in the Rate Limiter configuration.

Next Steps

Released under the MIT License.