Aryan Iyappan
Aryan Iyappan
SGStrawberry GraphQL
Created by Aryan Iyappan on 6/28/2024 in #đŸ¤”questions
relay.GlobalID naming issue?
type CreateTodoPayload {
todoEdge: TodoEdge!
}

"""Date with time (isoformat)"""
scalar DateTime

type DeleteTodoPayload {
deletedTodoId: GlobalID
}

"""
The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
"""
scalar GlobalID @specifiedBy(url: "https://relay.dev/graphql/objectidentification.htm")

type Mutation {
"""Create a new todo."""
createTodo(
"""The content of the todo."""
content: String!
): CreateTodoPayload!

"""Delete a todo by ID."""
deleteTodo(
"""The ID of the todo to delete."""
todoId: GlobalID!
): DeleteTodoPayload!
}

"""An object with a Globally Unique ID"""
interface Node {
"""The Globally Unique ID of this object"""
id: GlobalID!
}

"""Information to aid in pagination."""
type PageInfo {
"""When paginating forwards, are there more items?"""
hasNextPage: Boolean!

"""When paginating backwards, are there more items?"""
hasPreviousPage: Boolean!

"""When paginating backwards, the cursor to continue."""
startCursor: String

"""When paginating forwards, the cursor to continue."""
endCursor: String
}

type Query {
node(
"""The ID of the object."""
id: GlobalID!
): Node!

"""Get all todos available."""
todos(before: String = null, after: String = null, first: Int = null, last: Int = null): TodoConnection!
}
type CreateTodoPayload {
todoEdge: TodoEdge!
}

"""Date with time (isoformat)"""
scalar DateTime

type DeleteTodoPayload {
deletedTodoId: GlobalID
}

"""
The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
"""
scalar GlobalID @specifiedBy(url: "https://relay.dev/graphql/objectidentification.htm")

type Mutation {
"""Create a new todo."""
createTodo(
"""The content of the todo."""
content: String!
): CreateTodoPayload!

"""Delete a todo by ID."""
deleteTodo(
"""The ID of the todo to delete."""
todoId: GlobalID!
): DeleteTodoPayload!
}

"""An object with a Globally Unique ID"""
interface Node {
"""The Globally Unique ID of this object"""
id: GlobalID!
}

"""Information to aid in pagination."""
type PageInfo {
"""When paginating forwards, are there more items?"""
hasNextPage: Boolean!

"""When paginating backwards, are there more items?"""
hasPreviousPage: Boolean!

"""When paginating backwards, the cursor to continue."""
startCursor: String

"""When paginating forwards, the cursor to continue."""
endCursor: String
}

type Query {
node(
"""The ID of the object."""
id: GlobalID!
): Node!

"""Get all todos available."""
todos(before: String = null, after: String = null, first: Int = null, last: Int = null): TodoConnection!
}
29 replies
SGStrawberry GraphQL
Created by Aryan Iyappan on 6/27/2024 in #đŸ¤”questions
Should I use dataloaders in relay.Node.resolve_nodes?
I've got a node type like this:
@strawberry.type(name="Todo")
class TodoType(BaseNodeType):
content: str
completed: bool
created_at: datetime
updated_at: datetime | None

@classmethod
def from_orm(cls, todo: Todo) -> Self:
"""Construct a node from an ORM instance."""
return cls(
id=todo.id,
content=todo.content,
completed=todo.completed,
created_at=todo.created_at,
updated_at=todo.updated_at,
)

@classmethod
async def resolve_nodes( # noqa: ANN206
cls,
*,
info: Info,
node_ids: Iterable[str],
required: bool = False, # noqa: ARG003
):
todos = await info.context.loaders.todo_by_id.load_many(node_ids)
return list(map(cls.from_orm, [todo for todo in todos if todo is not None]))
@strawberry.type(name="Todo")
class TodoType(BaseNodeType):
content: str
completed: bool
created_at: datetime
updated_at: datetime | None

@classmethod
def from_orm(cls, todo: Todo) -> Self:
"""Construct a node from an ORM instance."""
return cls(
id=todo.id,
content=todo.content,
completed=todo.completed,
created_at=todo.created_at,
updated_at=todo.updated_at,
)

@classmethod
async def resolve_nodes( # noqa: ANN206
cls,
*,
info: Info,
node_ids: Iterable[str],
required: bool = False, # noqa: ARG003
):
todos = await info.context.loaders.todo_by_id.load_many(node_ids)
return list(map(cls.from_orm, [todo for todo in todos if todo is not None]))
Should I be using dataloaders to resolve my nodes here? If so, should I use a separate dataloader when required=False and a separate dataloader when required=True? Or am I completely wrong and should I just use my repository layer directly here?
7 replies
SGStrawberry GraphQL
Created by Aryan Iyappan on 6/22/2024 in #đŸ¤”questions
AioInject errors while overriding resolve_connection method (relay)
I wanted to create my own relay connection class like so: I get this mypy error which shows an error in the method signature:
Signature of "resolve_connection" incompatible with supertype "Connection"Mypyoverride
Superclass:
def resolve_connection(cls, nodes: Iterator[T] | Iterable[T] | AsyncIterator[T] | AsyncIterable[T], *, info: Info[Any, Any], before: str | None = ..., after: str | None = ..., first: int | None = ..., last: int | None = ..., **kwargs: Any) -> Awaitable[KeysetConnection[T]] | KeysetConnection[T]
Subclass:
def resolve_connection(nodes: Iterator[T] | Iterable[T] | AsyncIterator[T] | AsyncIterable[T], session: AsyncSession, *, info: Info[Context, None], before: str | None = ..., after: str | None = ..., first: int | None = ..., last: int | None = ..., **kwargs: Any) -> Coroutine[Any, Any, KeysetConnection[T]]
Signature of "resolve_connection" incompatible with supertype "Connection"Mypyoverride
Superclass:
def resolve_connection(cls, nodes: Iterator[T] | Iterable[T] | AsyncIterator[T] | AsyncIterable[T], *, info: Info[Any, Any], before: str | None = ..., after: str | None = ..., first: int | None = ..., last: int | None = ..., **kwargs: Any) -> Awaitable[KeysetConnection[T]] | KeysetConnection[T]
Subclass:
def resolve_connection(nodes: Iterator[T] | Iterable[T] | AsyncIterator[T] | AsyncIterable[T], session: AsyncSession, *, info: Info[Context, None], before: str | None = ..., after: str | None = ..., first: int | None = ..., last: int | None = ..., **kwargs: Any) -> Coroutine[Any, Any, KeysetConnection[T]]
How could this be fixed? I need to get my session within the resolver
12 replies
SGStrawberry GraphQL
Created by Aryan Iyappan on 11/12/2022 in #đŸ¤”questions
descriptions for arguments
Is there any way to add descriptions to arguments currently? I think it's a drawback that we cannot add stuff like deprecated directives and descriptions to arguments just because we use typehints.
@strawberry.field()
def my_field(parent, info, my_arg: str):
pass
@strawberry.field()
def my_field(parent, info, my_arg: str):
pass
Instead of this, does python support something like:
@strawberry.field()
def my_field(parent, info, my_arg: GraphQLString(description="", deprecated=True)):
pass
@strawberry.field()
def my_field(parent, info, my_arg: GraphQLString(description="", deprecated=True)):
pass
That would be cool
11 replies