> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom API extensions

> Extend a Squid SDK GraphQL API with custom resolvers — add aggregations, computed fields, and ad-hoc queries beyond the schema-derived entities.

# Custom GraphQL resolvers

One can extend the GraphQL API generated by OpenReader with custom queries. To do that, one can define GraphQL [query resolvers](https://www.apollographql.com/docs/apollo-server/data/resolvers/) in the designated module `src/server-extension/resolvers`. **Note that all resolver classes (including any additional types) must be exported by `src/server-extension/resolvers/index.ts`.**

A custom resolver should import [TypeGraphQL](https://typegraphql.com) types and [use annotations](https://typegraphql.com/docs/resolvers.html) provided by the library to define query arguments and return types. If your squid lacks a `type-graphql` dependency, add it with:

```bash theme={"system"}
npm i type-graphql
```

Custom resolvers are normally used in combination with [TypeORM EntityManager](https://typeorm.io/entity-manager-api) for accessing the API server target database. It is automatically injected when defined as a single constructor argument of the resolver.

## Examples

#### Simple entity counter

```typescript theme={"system"}
import { Query, Resolver } from 'type-graphql'
import type { EntityManager } from 'typeorm'
import { Burn } from '../model'

@Resolver()
export class CountResolver {
  constructor(private tx: () => Promise<EntityManager>) {}

  @Query(() => Number)
  async totalBurns(): Promise<number> {
    const manager = await this.tx()
    return await manager.getRepository(Burn).count()
  }
}
```

This example is designed to work with the `evm` template:

1. grab a test squid as described [here](/en/sdk/squid-sdk/how-to-start/squid-development);
2. install `type-graphql`;
3. save the example code to `src/server-extension/resolver.ts`;
4. re-export `CountResolver` at `src/server-extension/resolvers/index.ts`:
   ```ts theme={"system"}
   export { CountResolver } from '../resolver'
   ```
5. rebuild the squid with `npm run build`;
6. (re)start the GraphQL server with `npx squid-graphql-server`.

`totalBurns` selection will appear in the [GraphiQL playground](http://localhost:4350/graphql).

#### Custom SQL query

```typescript theme={"system"}
import { Arg, Field, ObjectType, Query, Resolver } from 'type-graphql'
import type { EntityManager } from 'typeorm'
import { MyEntity } from '../model'

// Define custom GraphQL ObjectType of the query result
@ObjectType()
export class MyQueryResult {
  @Field(() => Number, { nullable: false })
  total!: number

  @Field(() => Number, { nullable: false })
  max!: number

  constructor(props: Partial<MyQueryResult>) {
    Object.assign(this, props);
  }
}

@Resolver()
export class MyResolver {
  // Set by depenency injection
  constructor(private tx: () => Promise<EntityManager>) {}

  @Query(() => [MyQueryResult])
  async myQuery(): Promise<MyQueryResult[]> {
    const manager = await this.tx()
    // execute custom SQL query
    const result: = await manager.getRepository(MyEntity).query(
      `SELECT 
        COUNT(x) as total, 
        MAX(y) as max
      FROM my_entity 
      GROUP BY month`)
    return result
  }
}
```

#### More examples

Some great examples of `@subsquid/graphql-server`-based custom resolvers can be spotted in the wild in the [Rubick repo](https://github.com/kodadot/rubick/tree/main/src/server-extension/resolvers) by [KodaDot](https://github.com/kodadot).

For more examples of resolvers, see [TypeGraphQL examples repo](https://github.com/MichalLytek/type-graphql/tree/master/examples).

## Logging

To keep logging consistent across the entire GraphQL server, use `@subsquid/logger`:

```ts theme={"system"}
import {createLogger} from '@subsquid/logger'

// using a custom namespace ':my-resolver' for resolver logs
const LOG = createLogger('sqd:graphql-server:my-resolver')
LOG.info('created a dedicated logger for my-resolver')
```

`LOG` here is a [logger object](/en/sdk/squid-sdk/reference/logger) identical to `ctx.log` interface-wise.

## Interaction with global settings

* `--max-response-size` used for [DoS protection](/en/sdk/squid-sdk/reference/openreader-server/configuration/dos-protection) is ignored in custom resolvers.
* [Caching](/en/sdk/squid-sdk/reference/openreader-server/configuration/caching) works on custom queries in exactly the same way as it does on the schema-derived queries.

## Troubleshooting

#### `Reflect.getMetadata is not a function`

Add `import 'reflect-metadata'` on top of your custom resolver module and install the package if necessary.
