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.
resolvercan be used to create a missingcountryfield on anaddressschema 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
clientlayer is different than on theserverlayer. - 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
uuidtype while server would interpret it just as astringtype - 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
repositorylayer 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 shapein 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() }