graphql-hive / graphql-hive/SOFA
Relay support
- Dominant language
- TypeScript
- Stars
- 1.1k
- Forks
- 91
- Avg merge
- 5h 10m
- Merged PRs (30d)
- 1
Description
Sofa is very opinionated on what it considers a model, it's a good thing to consider the Relay Design Pattern for Node, we don't need to have a method to query for each model, we simply have a node method that query all types that implements the Node interface.
```graphql
interface Node {
id: ID!
}
type User implements Node {
id: ID!
displayName: String!
}
type UserEdge {
cursor: String!
node: User!
}
type PageInfo {
startCursor: String!
endCursor: String!
hasNextPage: Boolean!
hasPrevPage: Boolean!
}
type UserConnection {
edges: [UserEdge!]!
nodes: [User!]!
info: PageInfo!
}
type Query {
node(id: ID!): Node!
userConnection(
first: Int
last: Int
after: String
before: String
): UserConnection!
}
```
So my workaround while SOFA doesn't support this officially is the following:
```typescript
import { useSofa, createSofa } from 'sofa-api';
import { wrapSchema, FilterObjectFields } from '@graphql-tools/wrap';
const nodes = schema.getImplementations(schema.getType('Node') as any)
.objects.map(({ name }) => name);
const sofaIgnore: string[] = [];
const sofaSchema = wrapSchema(graphSchema, [
new FilterObjectFields(
(typeName, fieldName) => {
if (!typeName) {
return true;
}
if (typeName.endsWith('Connection') && fieldName === 'nodes') {
// it will omit nodes, only listing edges for all connections
return false;
}
if (typeName.endsWith('Edge') && fieldName === 'node') {
// it will ignore and let a node inside an edge to retrieve full object node
sofaIgnore.push(`${typeName}.node`);
}
return true;
},
),
]);
const sofa = createSofa({
schema: sofaSchema,
ignore: sofaIgnore,
});
// Include nodes as models
sofa.models = Array.from(new Set(sofa.models.concat(nodes)));
app.use('/rest', useSofa(sofa));
```
The only problema that still remains that the workaround wont fix is the Node interface or interfaces in general, since Node only has the id field it only returns the id, interface should be spreading implemented object fields in the root level like:
```graphql
query FetchNode ($id: ID!) {
node(id: $id) {
__typename
id
...on User {
displayName
}
}
}
```
Sure we can overwrite this with the execute option inside Sofa, but would be great if we could come with a better solution for Relay without the need to create a method for each model (node).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at createSofa and useSofa, then inspect how the schema, models, and ignore options handle interfaces and Relay-style connections. Define what a node query should return for an interface implementation, including inline-fragment fields, without requiring a method per model; verify that existing edge and connection behavior remains supported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, typescript
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100