strawberry-graphql / strawberry

A GraphQL library for Python that leverages type annotations 🍓
https://strawberry.rocks
MIT License
4.01k stars 531 forks source link

(Relay) Output ID instead of GlobalID in GraphQL schema #3551

Open aryaniyaps opened 4 months ago

aryaniyaps commented 4 months ago

Request to output the ID scalar instead of GlobalID, while generating the GraphQL schema

My understanding is that GlobalID was meant to be an internal helper that resolves nodes, but ended up being a custom scalar.

Feature Request Type

Description

Currently, while using the relay integration, and working with node types, like the example code below:

import strawberry
from strawberry import relay

@strawberry.type
class Fruit(relay.Node):
    code: relay.NodeID[int]
    name: str
    weight: float

    @classmethod
    def resolve_nodes(
        cls,
        *,
        info: strawberry.Info,
        node_ids: Iterable[str],
        required: bool = False,
    ):
        return [
            all_fruits[int(nid)] if required else all_fruits.get(nid)
            for nid in node_ids
        ]

We get a schema output like this:

scalar GlobalID

interface Node {
  id: GlobalID!
}

type Fruit implements Node {
  id: GlobalID!
  name: String!
  weight: Float!
}

But in the relay specification, which the GlobalID scalar is based on: https://relay.dev/graphql/objectidentification.htm

calls this scalar by the name ID, and not GlobalID.

I think that there is no mention of a custom scalar to be returned for object identification.

This leads to a lot of issues while working with client libraries such as relay, where directives expect the return type to be the scalar type of ID, and not GlobalID.

An example relay compiler error is shown below:

> client@0.0.0 relay
> relay-compiler

[INFO] [default] compiling...
[ERROR] Error: ✖︎ Invalid use of @deleteEdge on field 'deletedTodoId'. Expected field type 'ID', got 'GlobalID'.

  client/src/components/home-page/Todo.tsx:20:21
   19 │     deleteTodo(todoId: $todoId) {
   20 │       deletedTodoId @deleteEdge(connections: $connections)
      │                     ^^^^^^^^^^^
   21 │     }

[ERROR] Compilation failed.
[ERROR] Unable to run relay compiler. Error details: 
Failed to build:
 - Validation errors: 1 error(s) encountered above.

Output GraphQL schema (After requested change)


 interface Node {
  id: ID!
}

type Fruit implements Node {
  id: ID!
  name: String!
  weight: Float!
}

It would be nice if we could change the GlobalID scalar being generated to ID

Upvote & Fund

Fund with Polar

aryaniyaps commented 4 months ago

Here is a temporary solution for anyone who has the same issue, until this has been resolved:

import strawberry
from strawberry.relay import GlobalID

# temporary hack until strawberry fixes relay ID scalar generation
ID = strawberry.scalar(
    strawberry.ID,
    serialize=lambda value: str(value),
    parse_value=lambda value: GlobalID.from_id(value=value),
)

schema = Schema(
    query=query,
    mutation=mutation,
    scalar_overrides={GlobalID: ID},
)
DoctorJohn commented 4 months ago

Thanks for creating an issue for this. There is already a discussion (#3177) and a PR (#3180) for this. Feel free to join the conversation over there as well.

rodaan commented 4 months ago

@aryaniyaps your temporary solution doesn't seem to work for me. I'm getting this: TypeError: Query fields cannot be resolved.

What version of strawberry are you using?

aryaniyaps commented 4 months ago

@aryaniyaps your temporary solution doesn't seem to work for me. I'm getting this: TypeError: Query fields cannot be resolved.

What version of strawberry are you using?

I think the issue is, after creating a scalar like this;

ID = strawberry.scalar(
    strawberry.ID,
    serialize=lambda value: str(value),
    parse_value=lambda value: GlobalID.from_id(value=value),
)

You are using strawberry.ID in your schema. You should be using your own ID scalar instead.

I'm on version 0.235.0 btw

pfcodes commented 4 months ago

Here is a temporary solution for anyone who has the same issue, until this has been resolved:

import strawberry
from strawberry.relay import GlobalID

# temporary hack until strawberry fixes relay ID scalar generation
ID = strawberry.scalar(
    strawberry.ID,
    serialize=lambda value: str(value),
    parse_value=lambda value: GlobalID.from_id(value=value),
)

schema = Schema(
    query=query,
    mutation=mutation,
    scalar_overrides={GlobalID: ID},
)

This was helpful, thank you