rs-mock-server 0.6.13

A simple, file-based mock API server that maps your directory structure to HTTP and GraphQL routes. Ideal for local development and testing.
<!-- docs/11-graphql.md -->

# GraphQL Routes

This document describes how rs-mock-server handles GraphQL queries and mutations.

## Overview

When a `graphql` folder is detected in the mocks directory, the server:

-   Registers a `POST /graphql` endpoint to execute GraphQL operations.
-   Registers a `GET /graphiql` endpoint to serve the GraphiQL IDE.
-   Loads any files in a nested `/collections` subfolder into Fosk collections for query execution.

Static overrides (JSON or JGD files) take precedence over dynamic execution. If a query or mutation is named, the server will first check for a matching `<operationName>.json` or `<operationName>.jgd` file and return its content directly (for JGD files, it generates dynamic mock data based on the definition).

## GraphiQL Introspection

The GraphiQL IDE is fed by a dynamic schema constructed from the currently loaded collections. This means:

-   All collections under `mocks/graphql/collections` (and any other routes that populate the Fosk database) appear in the GraphiQL sidebar with the inferred fields and relations.
-   Relations inferred by rs-mock-server (for example `orders``order_items``products`) are surfaced as nested object lists, so you can explore available joins directly in the documentation panel.
-   CRUD mutations (`create<Collection>`, `update<Collection>`, `delete<Collection>`) are auto-generated per collection, and GraphiQL lists the expected arguments and return types for each of them.

Open `http://localhost:<port>/graphiql` and use the Docs panel to confirm which collections, relations, and mutations are currently available.

## Folder Layout

```
mocks/
├── graphql/
│   ├── collections/       # JSON or JGD files loaded as collections
│   │   └── users.json     # creates `users` collection
│   ├── getUsers.jgd       # GET /graphql?query=getUsers (static override)
│   └── ...
└── ...
```

## Static Overrides

If your GraphQL request includes an operation name:

```graphql
query showAllOrdersForProduct($product_id: Int) {
    showAllOrdersForProduct(product_id: 35) {
        id
        orderDate
        status
    }
}
```

The handler will look for:

-   `mocks/graphql/showAllOrdersForProduct.json`
-   `mocks/graphql/showAllOrdersForProduct.jgd`

If found:

-   For `.json`, it reads and returns the file as JSON.
-   For `.jgd`, it runs `generate_jgd_from_file` and returns the generated data.

Usage:

```bash
curl -X POST /graphql \
    -H 'Content-Type: application/json' \
    -d '{"query":"query { showAllOrdersForProduct(product_id:35){id}}","operationName":"showAllOrdersForProduct"}'
```

## Dynamic Execution

If no static file matches, the server parses the GraphQL AST and executes against the in-memory Fosk DB:

1. **Validate** referenced collections exist.
2. **Execute** queries by mapping root fields to collections:
    - No arguments → retrieve all records in the collection.
    - Single `id` argument → retrieve the record with that `id`.
    - Other arguments → treat them as filter conditions.
3. **Resolve** any nested relationships based on inferred foreign keys:
    - A foreign key is inferred when one collection’s primary field (e.g. `id` or `_id`) matches another collection’s field named `<collection>_id`.
    - This inference also applies across collections defined by REST routes or authentication handlers, so you can nest queries over any loaded collection (e.g., `users`, `sessions`).
4. **Filter** each JSON object to only include requested fields.

### Example Query

```graphql
query {
    orders(id: 5, status: "Shipped") {
        id
        orderDate
        status
        order_items {
            id
            quantity
            products {
                _id
                name
            }
        }
    }
}
```

Executes SQL:

```sql
SELECT * FROM orders WHERE id = 5 AND status = 'Shipped';
```

Then loads and nests `order_items` and `products`, returning only selected fields.

## Mutations

Root mutation fields map to CRUD operations on collections:

-   `create<CollectionName>` → create a new record in the collection.
-   `update<CollectionName>` → update the specified record.
-   `delete<CollectionName>` → remove the specified record.

Arguments are parsed from the AST and converted to JSON values.

### Create Example

```graphql
mutation {
    createUsers(firstName: "John", lastName: "Doe") {
        id
        firstName
        lastName
    }
}
```

A new user record is created with an auto-generated `id`, and the response includes only the requested fields.

### Update Example

```graphql
mutation {
    updateUsers(id: "1", email: "john.doe@example.com") {
        id
        email
    }
}
```

The existing user with `id = "1"` is updated, and the response includes only the requested fields.

### Delete Example

```graphql
mutation {
    deleteUsers(id: "2") {
        id
    }
}
```

A user with `id = "2"` is removed from the collection, and the response returns the fields specified in the request.

## Loading Collections

Files under `mocks/graphql/collections` are read at startup and loaded into Fosk:

```bash
mocks/graphql/collections/
├── users.json       # static array
└── products.jgd     # dynamic generator
```

Use standard JSON arrays or JGD definitions. See:

-   [02-rest-apis]02-rest-apis.md for JSON
-   [06-jgd-files]06-jgd-files.md for JGD