strawberry icon indicating copy to clipboard operation
strawberry copied to clipboard

Support for context sharing between parent and child types/fields

Open metatick opened this issue 4 months ago • 1 comments

Feature Request Type

  • [ ] Core functionality
  • [ ] Alteration (enhancement/optimization) of existing feature(s)
  • [x] New behavior

Description

In some cases it would be helpful if child objects/fields could access information about a parent object, especially for deeply nested types.

For example:

@strawberry.type
class User:
    id: int
    editor: bool
    pages: List[Page]

@strawberry.type
class Page:
   id: int
   title: str
   comments: List[Comment]

@strawberry.type
class Comment:
    id: int
    comment: str
    @strawberry.field()
    def can_edit(self) -> bool:
        # get the user from current context, somehow
        user = get_user_from_context()
        if not user:
            raise Exception("This field is only valid when queried under a User object")
        return user.editor

@strawberry.type
class Query:
    users: List[User]
    pages: List[Page]

query {
    users {
        id
        pages {
            id
            title
            comments {
                id
                comment
                canEdit
            }
        }
    }
}

This can sort-of be achieved by storing information on info.context, but as far I can tell there isn't a safe way for this to be done for (at least) two reasons:

  1. In async context fields may not be resolved deterministically, so the information in info may or may not be valid for the current ancestor of the field
  2. There isn't a straightforward way, at least that I can see, to easily remove information from context after all fields in an object have been resolved

It would be nice if there was some sort of context available on info that could be automatically pushed/popped as fields are resolved, so that something like this could work as expected:

@strawberry.type
class User:
    id: int
    editor: bool
    @strawberry.field()
    def pages(self, info) -> List[Page]:
        # user would be available to all descendants of User.pages, and be removed after User.pages completes
        info.field_context.set('user', self)         
        return get_pages()

metatick avatar Aug 14 '25 06:08 metatick

Another (admittedly, non DevX-friendly) workaround for this is to add a strawberry.Private field to the parent and also add it to all the children down the chain. That only works for certain use cases though, so I agree it would be great to have something else here.

erikwrede avatar Sep 13 '25 08:09 erikwrede