Open hcharley opened 1 year ago
Hi @hcharley! This is expected, but i think we can add a feature to support private arguments :)
What's your use case for them?
In this case my_private_field
has a static value (so it could be replaced with something else, for example with a constant), are you using some kind of decorator to do something with that field?
My usecase is that we're calling a query internally from inside another query, but we need an argument that can be changed so that the info selector's name aligns with the calling query's name.
@strawberry.type
class ResourceQuery:
@strawberry.field(permission_classes=[IsAuthenticated])
def resources(
self, info: Info,
filters: Optional[ResourceFilterInput] = None,
pagination: Optional[PaginationRequest] = None,
sort: Optional[PaginationSort] = None,
selector_field_override: strawberry.Private[str] = "resources"
) -> Edges[Resource]:
filters = filters if filters else ResourceFilterInput()
resource_search_map = get_input_map(filters, remove_null_values=True)
if "resource_uuid" in resource_search_map:
resource_search_map["uuid"] = (
resource_search_map.pop("resource_uuid")
)
results = info.orm.get_resources(
name="res",
selector=selector_field_override,
relationship_args=[],
)
# ...
page_info = PageInfo(total_results=results.total, pagination=pagination)
edges = Edges(edges=results.items, page_info=page_info)
return edges
@strawberry.field(permission_classes=[IsAuthenticated])
def resource(
self, info: Info, uuid: str
) -> Optional[Resource]:
resources = ResourceQuery.resources(
self=self,
info=info,
filters=ResourceFilterInput(
resource_uuid=uuid
),
pagination=PaginationRequest(
first=1,
after=0,
),
selector_field_override="resource"
)
if len(resources.edges) == 0:
return None
return resources.edges[0].node
Hi @hcharley! This is expected, but i think we can add a feature to support private arguments :)
What's your use case for them?
In my case I would love to have the ability to mark arguments as private (excluded from schema completely) for dependency injection purposes. So I can do something like this using the dependcy-injector library:
@strawberry.type
class Query:
@strawberry.field
@inject
def get_books(
self,
author: str,
search_service: strawberry.Private[SearchService] = Closing[
Provide[Container.service]
],
) -> list[Book]:
return search_service.get_by_author(author)
Technically it is currently possible with code like this:
@strawberry.type
class Query:
@strawberry.field
@inject
def get_books(
self,
author: str,
search_service: str = Closing[Provide[Container.service]],
) -> list[Book]:
return search_service.get_by_author(author)
I can't type hint the search_service arg as SearchService because of "Unexpected type '<class 'main.SearchService'>'". It has to be type hinted as some strawberry scalar eg. str. It is being visible as valid argument from docs/graphiql etc. and can be passed with query, overriding the injected service.
I've managed to hack it but it requires external boilerplate code which other team members would have to know about. I would rather avoid that and use only strawberries' native code.
class GetBooks:
def __new__(cls, *args, **kwargs):
self = super().__new__(cls)
signature = inspect.signature(self.__call__.__func__.func_dict["__wrapped__"])
args_to_ignore = []
for k, v in signature.parameters.items():
if isinstance(v.default, _Marker):
args_to_ignore.append(ReservedName(k))
self.__annotations__ = {**self.__call__.__annotations__}
self = StrawberryResolver(self)
self.RESERVED_PARAMSPEC = self.RESERVED_PARAMSPEC + tuple(args_to_ignore)
self = strawberry.field(self)
return self
@inject
@staticmethod
def __call__(
self,
author: str,
search_service: SearchService = Closing[Provide[Container.service]],
) -> list[Book]:
return search_service.get_by_author(author)
@strawberry.type
class Query:
get_books = GetBooks()
Describe the Bug
^ This code will still expose
myPrivateField
to the GraphQL schema. It should not expose it.System Information
Additional Context
Upvote & Fund