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:
| Component | File | Role |
|---|---|---|
GraphQL | DAO/GraphQL/GraphQL.ts | Schema builder and query executor |
GraphQLResolver | HttpProcessor/Resolvers/GraphQLResolver.ts | HTTP endpoint (GET + POST) |
GraphiQLLoader | HttpProcessor/Resolvers/GraphiQLLoader.ts | Interactive 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 / Mongoose | GraphQL Type |
|---|---|
String | String |
Boolean | Boolean |
Number | Float |
Date | Date |
BaseModel subclass | Nested 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:
| Method | Query Source |
|---|---|
GET | Query string parameter |
POST | Request 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
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