Skip to main content

GraphQL API

Hub provides a GraphQL API layer that automatically generates a schema from all registered database models. Every query and mutation is authorization-checked against the caller's token.

Architecture​

The GraphQL system consists of three components:

ComponentFileRole
GraphQLDAO/GraphQL/GraphQL.tsSchema builder and query executor
GraphQLResolverHttpProcessor/Resolvers/GraphQLResolver.tsHTTP endpoint (GET + POST)
GraphiQLLoaderHttpProcessor/Resolvers/GraphiQLLoader.tsInteractive IDE at /graphiql

Libraries used: graphql (core), graphql-compose (schema composition), graphql-compose-mongoose (Mongoose integration).

Schema Generation​

The GraphQL.RegisterModels() method is called during onDbConnected() and builds the schema automatically:

RegisterModels()
├── For each DB model:
│ ├── getSchemaType(model) → Create GraphQL type from @Property decorators
│ └── generateInnerSchema() → Register Mongoose-based findMany resolvers
├── For custom @GQLMethod:
│ └── generateSchema() → Register query/mutation from @GQLMethod decorators
└── buildSchema() → Compile final executable schema

Type Mapping​

Model @Property types are mapped to GraphQL types:

TypeScript / MongooseGraphQL Type
StringString
BooleanBoolean
NumberFloat
DateDate
BaseModel subclassNested object type (recursive)
Array<T>[T] (list type)

Custom Queries and Mutations​

Use the @GQLMethod decorator to register custom GraphQL operations:

@GQLMethod({
symbol : "myCustomQuery",
description: "Fetch filtered data",
args : [{ name: "filter", type: String }],
returnType: [MyModel]
})
public MyCustomQuery($filter : string) : IAuthPromise {
return {
auth : "MyConnector.MyCustomQuery",
resolve: async ($token : string) => {
// query logic
}
};
}

The decorator type determines placement: GQLMethod.Query for queries, GQLMethod.Mutation for mutations.

Global Model Registration​

Solution projects can register additional models for GraphQL via the global registry:

globalThis.oidisAPIGraphQLModels = [
() => MyCustomModel
];

These are picked up during RegisterModels() alongside the standard DB models.

Authorization​

Every GraphQL field resolution is wrapped in an authorization check. The Execute() method provides an invoker context function:

contextValue: {
invoker: async ($entity, $args, $method) => {
const promise = $method.apply($entity, $args);
if (await AuthManager.IsAuthorizedFor(promise.auth, this.currentToken)) {
return promise.resolve(this.currentToken);
} else {
throw new Error("Not authorized for " + promise.auth);
}
},
token: this.currentToken
}

This ensures that even if a user can access the GraphQL endpoint, they can only execute operations their group permissions allow.

HTTP Endpoint​

The GraphQLResolver at /graphql handles both request methods:

MethodQuery Source
GETQuery string parameter
POSTRequest body (JSON)

The resolver extends RESTResolver, inheriting Bearer token authentication. Unauthorized requests receive a GraphQL-formatted error response.

Auto-Generated Queries​

For each registered model, a {ModelName}All query is automatically available via graphql-compose-mongoose:

query {
UserAll {
_id
userName
email
firstName
lastName
}
}

GraphiQL IDE​

The GraphiQLLoader resolver serves the GraphiQL interactive IDE at /graphiql. This provides:

  • Schema exploration with auto-complete
  • Query building and execution
  • Documentation browser for all types and fields
tip

GraphiQL is useful during development for discovering available queries and testing API calls. In production, access should be restricted via group permissions.


See also: HTTP Server & Resolvers | Hub Database Models | Authentication