Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ cd my-app
pgpm init
cd packages/your-module

# 3. Install a package
# 3. Install a package
pgpm install @pgpm/faker

# 4. Deploy everything
Expand Down Expand Up @@ -292,7 +292,7 @@ This architecture eliminates the traditional ORM layer and API boilerplate, lett

### 🚀 GraphQL API & Server

- **[@constructive-io/graphql-server](https://github.com/constructive-io/constructive/tree/main/graphql/server)** - Express-based API server powered by PostGraphile with RLS integration and JWT authentication
- **[@constructive-io/graphql-server](https://github.com/constructive-io/constructive/tree/main/graphql/server)** - Express-based API server powered by PostGraphile with RLS integration, JWT auth, and meta API routing
- **[@constructive-io/graphql-explorer](https://github.com/constructive-io/constructive/tree/main/graphql/explorer)** - GraphiQL interface for exploring your auto-generated GraphQL API
- **[graphile-settings](https://github.com/constructive-io/constructive/tree/main/graphile/graphile-settings)** - Centralized PostGraphile plugin configuration with connection filters, PostGIS, and full-text search

Expand Down
114 changes: 113 additions & 1 deletion graphql/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,118 @@
<img height="20" src="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml/badge.svg" />
</a>
<a href="https://github.com/constructive-io/constructive/blob/main/LICENSE"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
<a href="https://www.npmjs.com/package/@constructive-io/graphql-server"><img height="20" src="https://img.shields.io/github/package-json/v/constructive-io/constructive?filename=packages%2Fserver%2Fpackage.json"/></a>
<a href="https://www.npmjs.com/package/@constructive-io/graphql-server"><img height="20" src="https://img.shields.io/github/package-json/v/constructive-io/constructive?filename=graphql%2Fserver%2Fpackage.json"/></a>
</p>

**Constructive GraphQL Server** is an Express-based server built on PostGraphile. It reads Constructive metadata to select API schemas, applies RLS-aware auth, and exposes a production-ready GraphQL API.

## 🚀 Quick Start

### Use as SDK

Install the package:

```bash
pnpm add @constructive-io/graphql-server @constructive-io/graphql-env
```

Start a server:

```ts
import { getEnvOptions } from '@constructive-io/graphql-env';
import { GraphQLServer } from '@constructive-io/graphql-server';

GraphQLServer(
getEnvOptions({
pg: { database: 'constructive_db' },
server: { host: '0.0.0.0', port: 3000 }
})
);
```

> **Tip:** Set `PGHOST`, `PGPORT`, `PGUSER`, `PGPASSWORD`, `PGDATABASE` to control DB connectivity.
See [Configuration](#configuration) for the full list of supported env vars and defaults.

### Local Development (this repo)

```bash
pnpm install
cd graphql/server
pnpm dev
```

This starts the server with env defaults from `@constructive-io/graphql-env`.
> **Tip:** Set `PGHOST`, `PGPORT`, `PGUSER`, `PGPASSWORD`, `PGDATABASE` to control DB connectivity.
See [Configuration](#configuration) for the full list of supported env vars and defaults.


## What it does

Runs an Express server that wires CORS, uploads, domain parsing, auth, and PostGraphile into a single GraphQL endpoint. It serves `/graphql` and `/graphiql`, injects per-request `pgSettings`, and flushes cached schemas on demand or via database notifications. When meta API is enabled, it resolves API config (schemas, roles, modules) from the meta schema using the request host and enforces `api.isPublic`, with optional header overrides in private mode; when meta API is disabled, it serves the fixed schemas and roles from `api.exposedSchemas`, `api.anonRole`, `api.roleName`, and `api.defaultDatabaseId`.

## Key Features

- Automatic GraphQL API generation from PostgreSQL schemas
- RLS-aware authentication and per-request `pgSettings`
- Meta-schema routing by domain + subdomain
- File uploads via `graphql-upload`
- GraphiQL and health check endpoints
- Schema cache flush via `/flush` or database notifications

## Routes

- `GET /healthz` -> health check
- `GET /graphiql` -> GraphiQL UI
- `GET /graphql` / `POST /graphql` -> GraphQL endpoint
- `POST /graphql` (multipart) -> file uploads
- `POST /flush` -> clears cached Graphile schema for the current API

## Meta API routing

When `API_ENABLE_META=true` (default):

- The server resolves APIs from `meta_public.domains` using the request host.
- Only APIs where `api.is_public` matches `API_IS_PUBLIC` are served.
- In private mode (`API_IS_PUBLIC=false`), you can override with headers:
- `X-Api-Name` + `X-Database-Id`
- `X-Schemata` + `X-Database-Id`
- `X-Meta-Schema` + `X-Database-Id`

When `API_ENABLE_META=false`:

- The server skips meta lookups and serves the fixed schemas in `API_EXPOSED_SCHEMAS`.
- Roles and database IDs come from `API_ANON_ROLE`, `API_ROLE_NAME`, and `API_DEFAULT_DATABASE_ID`.

## Configuration

Configuration is merged from defaults, config files, and env vars via `@constructive-io/graphql-env`. See `graphql/env/README.md` for the full list and examples.

| Env var | Purpose | Default |
| --- | --- | --- |
| `PGHOST` | Postgres host | `localhost` |
| `PGPORT` | Postgres port | `5432` |
| `PGUSER` | Postgres user | `postgres` |
| `PGPASSWORD` | Postgres password | `password` |
| `PGDATABASE` | Postgres database | `postgres` |
| `GRAPHILE_SCHEMA` | Comma-separated schemas to expose | empty |
| `FEATURES_SIMPLE_INFLECTION` | Enable simple inflection | `true` |
| `FEATURES_OPPOSITE_BASE_NAMES` | Enable opposite base names | `true` |
| `FEATURES_POSTGIS` | Enable PostGIS support | `true` |
| `API_ENABLE_META` | Enable meta API routing | `true` |
| `API_IS_PUBLIC` | Serve public APIs only | `true` |
| `API_EXPOSED_SCHEMAS` | Schemas when meta routing is disabled | empty |
| `API_META_SCHEMAS` | Meta schemas to query | `collections_public,meta_public` |
| `API_ANON_ROLE` | Anonymous role name | `administrator` |
| `API_ROLE_NAME` | Authenticated role name | `administrator` |
| `API_DEFAULT_DATABASE_ID` | Default database ID | `hard-coded` |

## Testing

Use `supertest` or your HTTP client of choice against `/graphql`. For RLS-aware tests, provide a `Bearer` token and ensure the API's auth function is available.

## Related Packages

- `@constructive-io/graphql-env` - env parsing + defaults for GraphQL
- `@constructive-io/graphql-types` - shared types and defaults
- `graphile-settings` - PostGraphile configuration
- `graphile-meta-schema` - meta schema support