graphql-hive / graphql-hive/SOFA

Relay support

Open
#571 0 comments 1 reaction 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.