Architectural Layer
Principle
Domain Service method should not be tightly coupled with another domain's service or repository.
- Should be injected
When structuring a return shape of a resolver, avoid coupling multiple methods or bundling return in a single field:
- Should instead be called as a dedicated field in the resolver layer.
Architectural Layer
API schema
and database schemas
are decoupled within GraphQL architecture.
- e.g.
resolver
can be used to create a missingcountry
field on anaddress
schema even when it is missing in the database.
This is why a type
can transform across the layers in the architecture.
- e.g. type on
client
layer is different than on theserver
layer. - This is why you can also call multiple resources from a single graph (e.g. DB can be SQL, NoSQL, someArbitraryDbTech).
At times, even data layer
types and server layer
types may be different for the same field
- e.g. SQL has a dedicated
uuid
type while server would interpret it just as astring
type - This would require a type to be "transformed" to be layer-compatible
Data
to Service
Layer
When the data is pulled as a response to a request, it first gets pulled from the database
to the repository layer
- The
repository
layer should mirror the DB Schema because we're simply pulling the data-layer into the server layer at this step
Repository layer
method is then called by the service layer
method
- Service layer should scope strictly to the service method as a unit
- Meaning, the service method should return data shape that is compliant to the service layer.
Service layer should NOT do everything needed to fulfill the graphql schema expectations
- This is a role of the resolver
Within the Service
Layer
Shape the
return shape
in theresolver
, not in other parts of the service layer
When you need to define a graph connection of a field, you must do this in the resolver
layer
- You DO NOT define this in the
server layer
- You HAVE to define it in the
resolver layer
If you don't place the relationships in the resolver layer, you are violating domain boundary and entangling the relationship in domain definition, not based on return
- you will also have a tough time typing the return shape on a service and multiple service calls will get tangled in a single service method.
- "service layer trying to do much"
- By resolving the field relationships at the resolver, the field relationships are split to each fields and a single service method is called for a single relationship (keeping a single version/integrity of a service method unless another method is defined)
- Especially when using a codegen on gql, generated types would need to be heavily manipulated when it is used to cater multiple
// resolver return shape { primitiveField1: UUID, primitiveField2: number, // return type of service1.getMethod relationshipField1: service1.getMethod(), // return type of service2.getMethod relationshipField2: service2.getMethod() }