Hi folks!
Let’s imagine an application for scheduling service appointments.
A Customer can use the mobile app to create an appointment, but the same appointment can also be scheduled by an Employee (or Receptionist) on behalf of a customer via the company’s internal system.
I’m exploring schema design options for the createAppointment
mutation and would love to hear your thoughts.
Option 1: Single mutation for all roles
type Mutation {
createAppointment(data: CreateAppointmentInput!): CreateAppointmentResponse!
}
- This mutation is used by both customers and employees.
- If the user is a customer, their
customerId
is inferred from the token/context. - If the user is an employee, the input needs to include a
customerId
.
The problem: A customer could pass a customerId
manually, even though they shouldn’t. It opens the door to misuse if not strictly validated.
Option 2: Role-specific mutations
type Mutation {
createAppointmentByCustomer(
data: CreateAppointmentByCustomerInput!
): CreateAppointmentResponse! @auth(roles: [CUSTOMER])
createAppointmentByEmployee(
data: CreateAppointmentByEmployeeInput!
): CreateAppointmentResponse! @auth(roles: [EMPLOYEE, ADMIN])
# Optional default
createAppointment(
data: CreateAppointmentInput!
): CreateAppointmentResponse!
}
- Clear separation of use cases.
- Inputs can be tailored for each role.
- Easier to apply role-based logic or validation at the schema level.
- If we have multiple features, the root
Query
andMutation
types can become overloaded with fields, making it harder to navigate or organize operations efficiently.
Option 3: Role-based namespacing
type Mutation {
employees: EmployeesMutation! @auth(roles: [EMPLOYEE, ADMIN])
customers: CustomersMutation! @auth(roles: [CUSTOMER])
}
type EmployeesMutation {
createAppointment(data: CreateAppointmentByEmployeeInput!): CreateAppointmentResponse!
}
- Encapsulates mutations by role.
- Makes it clear at the top level who is allowed to perform what.
- Scales well if each role has many operations.
This logic also applies to queries (e.g., listing appointments, orders, etc.). An employee would need to pass the customerId
, but the customer shouldn’t.
How would you do?