> For the complete documentation index, see [llms.txt](https://navixy.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://navixy.com/docs/navixy-graphql-api/graphql-basics/graphql-tips-and-patterns.md).

# GraphQL tips and patterns

Practical GraphQL patterns for cleaner requests: variables, operation names, fragments, aliases, and directives.

This article covers patterns that make your GraphQL code cleaner, more maintainable, and easier to debug. If you're new to GraphQL, start with [GraphQL basics ](/docs/navixy-graphql-api/graphql-basics.md)first.

## Variables

When you're testing queries, it's easy to write values directly into the query string. But real applications need to pass different values each time: a user might click on another device, select a different filter, or navigate to the next page.

Variables solve this by separating what you're asking for (the query) from the specific values (the variables). Think of it like a function: the query is the function definition, and variables are the arguments you pass in.

Here's a query without variables:

```graphql
query GetDevice {
  bdr {
    device(id: "550e8400-e29b-41d4-a716-446655440001") {
      title
    }
  }
}
```

And here's the same query with a variable:

```graphql
query GetDevice($deviceId: ID!) {
  bdr {
    device(id: $deviceId) {
      title
    }
  }
}
```

The variable `$deviceId` is declared in parentheses after the operation name. The `ID!` part specifies the type (must match what the schema expects). Then you use `$deviceId` wherever you need that value in the query.

The actual value is passed separately as JSON:

```json
{
  "deviceId": "550e8400-e29b-41d4-a716-446655440001"
}
```

When you send the request, include both the query and the variables. GraphQL tools and client libraries send both for you, and you provide only the variables object.

### Multiple variables

You can declare as many variables as you need:

```graphql
query ListDevices($statusIds: [ID!]!, $limit: Int = 20) {
  bdr {
    devices(
      filter: { statusIds: $statusIds }
      first: $limit
    ) {
      nodes {
        id
        title
      }
    }
  }
}
```

In this example:

* `$statusIds: [ID!]!` is required (the `!` after the brackets means the list itself cannot be null)
* Each item in the list is a non-null `ID` (the `!` inside the brackets)
* `$limit: Int = 20` is optional with a default value of 20

Variables in JSON:

```json
{
  "statusIds": ["a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"],
  "limit": 50
}
```

## Operation names

You can give your operations custom names to make them easier to identify in logs, debugging tools, and network traces.

The name `GetDevice` appears after the operation type (`query`, `mutation`, or `subscription`). It doesn't affect execution, as the API ignores it, but helps in several ways:

* Debugging: Error messages and server logs reference the operation name
* Tooling: GraphQL clients use names for caching and request deduplication
* Analytics: Track which operations are called most frequently
* Readability: Self-documenting code, especially with multiple operations

Mutations benefit from naming too:

```graphql
mutation UpdateDeviceTitle($id: ID!, $version: Int, $title: String) {
  bdr {
    deviceUpdate(input: { id: $id, version: $version, title: $title }) {
      device { id version title }
    }
  }
}
```

Common naming conventions use PascalCase with a verb prefix: `GetDevice`, `ListDevices`, `UpdateAsset`, `CreateGeoObject`, `DeleteSchedule`.

## Fragments

Fragments let you define reusable sets of fields. They're useful when you need the same fields in multiple queries.

Define a fragment on a specific type:

```graphql
fragment DeviceFields on Device {
  id
  version
  title
  status { code title }
  workspace { id title }
}
```

Use it in queries with the spread operator (`...`):

```graphql
query GetDevice($id: ID!) {
  bdr {
    device(id: $id) {
      ...DeviceFields
      identifiers { type value }
    }
  }
}

query ListDevices {
  bdr {
    devices(first: 10) {
      nodes {
        ...DeviceFields
      }
    }
  }
}
```

Both queries now share the same field selection for core device data.

### Inline fragments for interfaces

When working with interfaces like [Node](/docs/navixy-graphql-api/core-api-reference/common.md#node), use inline fragments to request type-specific fields:

```graphql
query GetNode($id: ID!) {
  node(id: $id) {
    id
    ... on Device {
      title
      status { code }
    }
    ... on Asset {
      title
      type { code title }
    }
    ... on Workspace {
      title
      isActive
    }
  }
}
```

The `node` query returns any entity by ID. The inline fragments (`... on Type`) tell GraphQL what fields to return based on the actual type.

## Aliases

Aliases let you rename fields in the response or fetch the same field multiple times with different arguments.

### Renaming fields

```graphql
query GetTwoDevices {
  bdr {
    truck: device(id: "device-uuid-1") {
      title
    }
    trailer: device(id: "device-uuid-2") {
      title
    }
  }
}
```

Response:

```json
{
  "data": {
    "bdr": {
      "truck": { "title": "Truck 42" },
      "trailer": { "title": "Trailer A7" }
    }
  }
}
```

### Comparing entities

Fetch the same entity at different points or with different parameters:

```graphql
query CompareAssets {
  bdr {
    truck: asset(id: "019d48ea-0752-8000-801f-444556437ab1") {
      title
      type { title }
      customFields { code }
    }
    van: asset(id: "019d48ea-0752-8000-801f-4445564380f2") {
      title
      type { title }
      customFields { code }
    }
  }
}
```

### Batch mutations

Aliases enable batch operations in a single request. In a mutation, you can select only one field inside a single `bdr` block, so alias the `bdr` namespace itself, one block per call:

```graphql
mutation BatchUpdateDevices {
  device1: bdr {
    deviceUpdate(input: {
      id: "uuid-1"
      version: 3
      title: "Truck 42 - Updated"
    }) {
      device { id version title }
    }
  }
  device2: bdr {
    deviceUpdate(input: {
      id: "uuid-2"
      version: 5
      title: "Truck 43 - Updated"
    }) {
      device { id version title }
    }
  }
}
```

Selecting two mutation fields inside one `bdr` block returns a validation error instead. This rule applies to mutations only: a query can select as many fields inside one `bdr` block as it needs, like the examples above.

The aliased blocks execute one after another, in the order they appear, and each mutation runs independently. If one fails, the others can still succeed, so check the `errors` array. See [Partial failure](/docs/navixy-graphql-api/error-handling.md#partial-failure).

There are no dedicated bulk mutations, so aliased blocks are also how you update many entities in one request. For large programmatic batches, send the `version` you last read for each entity. A concurrent change then fails only that block with `CONFLICT`, and you re-read and retry that entity alone. See [Optimistic locking](/docs/navixy-graphql-api/optimistic-locking.md).

## Directives

Directives modify how fields are executed. The API supports the standard GraphQL directives plus one custom directive; see [Directives](/docs/navixy-graphql-api/core-api-reference/directives.md) for the full list. The two you use directly in queries are `@include` and `@skip`, which turn a field on or off based on a variable.

Directives can be used to:

* Hide fields the user can't access
* Skip expensive fields when not needed
* Fetch fewer fields on mobile devices

```graphql
query ListDevices(
  $includeDetails: Boolean!
  $includeAudit: Boolean!
) {
  bdr {
    devices(first: 20) {
      nodes {
        id
        title
        status @include(if: $includeDetails) { code title }
        workspace @include(if: $includeDetails) { title }
        type @include(if: $includeAudit) { code }
        version @include(if: $includeAudit)
      }
    }
  }
}
```

## See also

* [GraphQL basics](/docs/navixy-graphql-api/graphql-basics.md): Learn GraphQL fundamentals, from queries and mutations to the type system
* [Directives](/docs/navixy-graphql-api/core-api-reference/directives.md): Complete reference for the standard and custom directives
* [Common resources](/docs/navixy-graphql-api/core-api-reference/common.md): Complete reference for shared scalars, interfaces, and types
* [Error handling](/docs/navixy-graphql-api/error-handling.md): Understand error structure, codes, and common error scenarios


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://navixy.com/docs/navixy-graphql-api/graphql-basics/graphql-tips-and-patterns.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
