Documentation Index
Fetch the complete documentation index at: https://www.orionjs.com/llms.txt
Use this file to discover all available pages before exploring further.
Orionjs provides a clean, decorator-based approach to define GraphQL resolvers. The @Resolvers() decorator along with @Query(), @Mutation(), and other decorators make it easy to create type-safe GraphQL APIs with minimal boilerplate.
Structure and Naming
- Use
@Resolvers() decorator from @orion-js/graphql
- Each resolver class should handle only one operation
- Follow naming conventions:
- Resolver classes:
{Action}{Entity}Resolvers (e.g., GetUserResolvers, UpdateProductResolvers)
- Mutations: descriptive of the operation (e.g.,
listProducts, createUser)
- Queries: only the name of the entity (e.g.,
user, productsList, blogPosts)
- Put resolvers in
app/{component}/controllers/resolvers/{Entity}/{Action}/index.ts
File Organization
The resolvers folder should have an index.ts that exports all resolvers as a single array:
controllers/
└── resolvers/
├── users/
│ ├── GetUser/index.ts
│ └── CreateUser/index.ts
├── orders/
│ ├── GetOrder/index.ts
│ └── CreateOrder/index.ts
└── index.ts # Exports all resolvers as a single array
The controllers/resolvers/index.ts file:
import {GetUserResolvers} from './users/GetUser'
import {CreateUserResolvers} from './users/CreateUser'
import {GetOrderResolvers} from './orders/GetOrder'
import {CreateOrderResolvers} from './orders/CreateOrder'
export default [
GetUserResolvers,
CreateUserResolvers,
GetOrderResolvers,
CreateOrderResolvers
]
Best Practices
- Use
@Inject(() => ServiceName) for dependency injection of services
- Always define proper schemas for parameters and return values
- Use
createQuery(), createMutation() and createModelResolver() functions
- Provide descriptive names and descriptions for GraphQL schema documentation
- Always use
schemaWithName() for schemas that will be used in GraphQL
- When creating a schema for params, prefer to clone another schema with
cloneSchema()
Query Example
import {Query, Resolvers, createQuery} from '@orion-js/graphql'
import {Inject} from '@orion-js/services'
import {schemaWithName} from '@orion-js/schema'
import {WebsiteConfigsRepo} from 'app/providers/repos/WebsiteConfigs'
import {WebsiteConfigSchema} from 'app/providers/schemas/WebsiteConfig'
const WebsiteConfigParams = schemaWithName('WebsiteConfigParams', {
websiteId: {type: String}
})
@Resolvers()
export class WebsiteConfigResolvers {
@Inject(() => WebsiteConfigsRepo)
private websiteConfigsRepo: WebsiteConfigsRepo
@Query()
websiteConfig = createQuery({
params: WebsiteConfigParams,
returns: WebsiteConfigSchema,
resolve: async params => {
return await this.websiteConfigsRepo.getWebsiteConfigByWebsiteId(params.websiteId)
}
})
}
Mutation with cloneSchema
Use cloneSchema to create parameter schemas based on existing schemas:
import {Mutation, Resolvers, createMutation} from '@orion-js/graphql'
import {Inject} from '@orion-js/services'
import {schemaWithName, cloneSchema} from '@orion-js/schema'
import {WebsiteConfigsRepo} from 'app/providers/repos/WebsiteConfigs'
import {WebsiteConfigSchema} from 'app/providers/schemas/WebsiteConfig'
// Define a schema with only the fields we want to update
const UpdatesSchema = cloneSchema({
name: 'WebsiteConfigUpdates',
schema: WebsiteConfigSchema,
pickFields: ['name', 'description'],
})
const UpdateWebsiteConfigParams = schemaWithName('UpdateWebsiteConfigParams', {
websiteId: {type: String},
updates: {type: UpdatesSchema}
})
@Resolvers()
export class UpdateWebsiteConfigResolvers {
@Inject(() => WebsiteConfigsRepo)
private websiteConfigsRepo: WebsiteConfigsRepo
@Mutation()
updateWebsiteConfig = createMutation({
params: UpdateWebsiteConfigParams,
returns: WebsiteConfigSchema,
resolve: async params => {
return await this.websiteConfigsRepo.updateWebsiteConfig(params.websiteId, params.updates)
}
})
}
Simple Mutation with cloneSchema
import {Mutation, Resolvers, createMutation} from '@orion-js/graphql'
import {Inject} from '@orion-js/services'
import {cloneSchema} from '@orion-js/schema'
import {WebsiteConfigsRepo} from 'app/providers/repos/WebsiteConfigs'
import {WebsiteConfigSchema} from 'app/providers/schemas/WebsiteConfig'
const SetWebsiteConfigNameParams = cloneSchema({
name: 'SetWebsiteConfigNameParams',
schema: WebsiteConfigSchema,
pickFields: ['websiteId', 'name']
})
@Resolvers()
export class SetWebsiteConfigNameResolvers {
@Inject(() => WebsiteConfigsRepo)
private websiteConfigsRepo: WebsiteConfigsRepo
@Mutation()
setWebsiteConfigName = createMutation({
params: SetWebsiteConfigNameParams,
returns: WebsiteConfigSchema,
resolve: async params => {
return await this.websiteConfigsRepo.updateWebsiteConfig(params.websiteId, {name: params.name})
}
})
}
Mutation Using a Service
import {Mutation, Resolvers, createMutation} from '@orion-js/graphql'
import {Inject} from '@orion-js/services'
import {schemaWithName} from '@orion-js/schema'
import {SendToInboxService} from 'app/services/SendToInbox'
const SendToInboxParams = schemaWithName('SendToInboxParams', {
email: {type: String},
message: {type: String}
})
@Resolvers()
export class SendToInboxResolvers {
@Inject(() => SendToInboxService)
private sendToInboxService: SendToInboxService
@Mutation()
sendToInbox = createMutation({
params: SendToInboxParams,
returns: String,
resolve: async params => {
return await this.sendToInboxService.execute(params)
}
})
}
Model Resolver
import {ModelResolver, ModelResolvers} from '@orion-js/graphql'
import {InferSchemaType} from '@orion-js/schema'
import {createModelResolver} from '@orion-js/resolvers'
import {PersonSchema} from 'app/providers/schemas/Person'
type Person = InferSchemaType<typeof PersonSchema>
@ModelResolvers(PersonSchema)
export class PersonResolvers {
@ModelResolver()
sayHi = createModelResolver<Person>({
returns: String,
resolve: async person => {
return `My name is ${person.name}`
}
})
}
Paginated Query
import {Query, Resolvers} from '@orion-js/graphql'
import {Inject} from '@orion-js/services'
import {createPaginatedResolver} from '@orion-js/paginated-mongodb'
import {ProductsRepo} from 'app/providers/repos/Products'
import {ProductSchema} from 'app/providers/schemas/Product'
import {ProductsListParams} from 'app/providers/schemas/params/ProductsList'
@Resolvers()
export class ProductsListResolvers {
@Inject(() => ProductsRepo)
private productsRepo: ProductsRepo
@Query()
productsList = createPaginatedResolver({
returns: ProductSchema,
params: ProductsListParams,
allowedSorts: ['createdAt', 'name'],
getCursor: async (params) => {
return {
cursor: this.productsRepo.loadProductsListCursor(params),
count: () => this.productsRepo.loadProductsListCount(params)
}
}
})
}
Complex cloneSchema for Params
import {cloneSchema, InferSchemaType} from '@orion-js/schema'
import {ArticleSchema} from '../Article'
export const ArticlesListParamsSchema = cloneSchema({
name: 'ArticlesListParams',
schema: ArticleSchema,
extendSchema: {
filter: {
type: String,
optional: true,
},
},
pickFields: ['websiteId', 'type'],
})
export type ArticlesListParamsType = InferSchemaType<typeof ArticlesListParamsSchema>
Subscription Resolvers
For real-time functionality:
import {Subscription, Subscriptions} from '@orion-js/graphql'
import {createSubscription} from '@orion-js/subscriptions'
@Subscriptions()
export class UserSubscriptions {
@Subscription()
userCreated = createSubscription({
params: ParamsSchema,
returns: UserSchema,
async canSubscribe(params) {
return params.name === 'test'
}
})
}
Error Handling
Orionjs automatically handles errors in resolvers:
@Query()
riskyOperation = createQuery({
returns: String,
resolve: async () => {
try {
const result = await this.someService.performOperation()
return result
} catch (error) {
throw new Error(`Operation failed: ${error.message}`)
}
}
})
Context and Viewer
All resolver methods receive the viewer object as the second parameter:
@Query()
userProfile = createQuery({
returns: UserProfile,
resolve: async (_, viewer) => {
if (!viewer.user) {
throw new Error('Unauthorized')
}
return await this.userService.getProfile(viewer.user._id)
}
})
Starting GraphQL Server
import {startGraphQL, startGraphiQL} from '@orion-js/graphql'
startGraphQL({
path: '/graphql'
})
// Optional: Start GraphiQL (GraphQL IDE)
startGraphiQL({
path: '/graphiql',
graphqlUrl: '/graphql'
})
Query vs Mutation
- Use
@Query() for operations that fetch data without side effects
- Use
@Mutation() for operations that create, update, or delete data