CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-strawberry-graphql

A library for creating GraphQL APIs using dataclasses and type annotations with extensive framework integration support.

Overview
Eval results
Files

fields-resolvers.mddocs/

Field Definitions and Resolvers

Field definition system with custom resolvers, descriptions, permissions, and advanced configuration options for GraphQL fields. This system allows fine-grained control over how GraphQL fields are resolved and secured.

Capabilities

Field Decorator

Defines GraphQL fields with custom resolvers and configuration options.

def field(
    resolver: Callable = None,
    *,
    name: str = None,
    description: str = None,
    deprecation_reason: str = None,
    permission_classes: List[Type[BasePermission]] = None,
    extensions: List[FieldExtension] = None,
    default: Any = dataclasses.NOTHING,
    default_factory: Callable = dataclasses.NOTHING
) -> Any:
    """
    Decorator to define GraphQL fields with custom configuration.
    
    Args:
        resolver: Custom resolver function for the field
        name: Custom field name (defaults to function/attribute name)
        description: Field description for GraphQL schema
        deprecation_reason: Deprecation message if field is deprecated
        permission_classes: List of permission classes for field-level authorization
        extensions: List of field extensions to apply
        default: Default value for the field
        default_factory: Factory function for default value
    
    Returns:
        Configured GraphQL field
    """

Usage Examples:

@strawberry.type
class User:
    id: strawberry.ID
    name: str
    email: str = strawberry.field(description="User's email address")
    
    @strawberry.field(description="User's full display name")
    def display_name(self) -> str:
        return f"{self.name} <{self.email}>"
    
    @strawberry.field(
        description="User's posts",
        permission_classes=[IsAuthenticated]
    )
    def posts(self, info: strawberry.Info) -> List[Post]:
        return get_user_posts(self.id, info.context.user)
    
    @strawberry.field(deprecation_reason="Use display_name instead")
    def full_name(self) -> str:
        return self.display_name()

    # Field with resolver arguments
    @strawberry.field
    def posts_by_tag(self, tag: str, limit: int = 10) -> List[Post]:
        return get_posts_by_tag(self.id, tag, limit)

Mutation Decorator

Defines GraphQL mutation fields for data modification operations.

def mutation(
    resolver: Callable = None,
    *,
    name: str = None,
    description: str = None,
    permission_classes: List[Type[BasePermission]] = None,
    extensions: List[FieldExtension] = None
) -> Any:
    """
    Decorator to define GraphQL mutation fields.
    
    Args:
        resolver: Resolver function for the mutation
        name: Custom mutation name
        description: Mutation description
        permission_classes: Permission classes for authorization
        extensions: Field extensions to apply
    
    Returns:
        Configured GraphQL mutation field
    """

Usage Example:

@strawberry.type
class Mutation:
    @strawberry.mutation(
        description="Create a new user account",
        permission_classes=[IsAdmin]
    )
    def create_user(
        self,
        name: str,
        email: str,
        age: int = 18
    ) -> User:
        # Validation and user creation logic
        if not email or "@" not in email:
            raise ValueError("Invalid email address")
        
        return User(
            id=generate_id(),
            name=name,
            email=email,
            age=age
        )
    
    @strawberry.mutation
    def update_user(
        self,
        id: strawberry.ID,
        input: UpdateUserInput
    ) -> User:
        user = get_user(id)
        if input.name is not strawberry.UNSET:
            user.name = input.name
        if input.email is not strawberry.UNSET:
            user.email = input.email
        save_user(user)
        return user

Subscription Decorator

Defines GraphQL subscription fields for real-time data streaming.

def subscription(
    resolver: Callable = None,
    *,
    name: str = None,
    description: str = None,
    permission_classes: List[Type[BasePermission]] = None,
    extensions: List[FieldExtension] = None
) -> Any:
    """
    Decorator to define GraphQL subscription fields.
    
    Args:
        resolver: Async generator function for the subscription
        name: Custom subscription name
        description: Subscription description
        permission_classes: Permission classes for authorization
        extensions: Field extensions to apply
    
    Returns:
        Configured GraphQL subscription field
    """

Usage Example:

@strawberry.type
class Subscription:
    @strawberry.subscription(description="Real-time user updates")
    async def user_updates(self, user_id: strawberry.ID) -> AsyncIterator[User]:
        # Subscribe to user updates from message broker/database
        async for update in subscribe_to_user_updates(user_id):
            yield User(**update)
    
    @strawberry.subscription
    async def message_stream(
        self,
        room_id: strawberry.ID,
        info: strawberry.Info
    ) -> AsyncIterator[Message]:
        # Check permissions
        if not can_access_room(info.context.user, room_id):
            raise PermissionError("Access denied")
        
        async for message in message_broker.subscribe(f"room:{room_id}"):
            yield Message(**message)

Argument Definition

Defines GraphQL field arguments with validation and default values.

def argument(
    name: str = None,
    description: str = None,
    default: Any = dataclasses.NOTHING,
    default_factory: Callable = dataclasses.NOTHING
) -> Any:
    """
    Define GraphQL field arguments with metadata.
    
    Args:
        name: Custom argument name (defaults to parameter name)
        description: Argument description
        default: Default value for the argument
        default_factory: Factory function for default value
    
    Returns:
        Configured GraphQL argument
    """

Usage Example:

@strawberry.type
class Query:
    @strawberry.field
    def users(
        self,
        limit: int = strawberry.argument(
            default=10,
            description="Maximum number of users to return"
        ),
        offset: int = strawberry.argument(
            default=0,
            description="Number of users to skip"
        ),
        filter_name: str = strawberry.argument(
            default=None,
            description="Filter users by name (case-insensitive)"
        )
    ) -> List[User]:
        return get_users(limit=limit, offset=offset, name_filter=filter_name)

Permission System

Base Permission Class

class BasePermission:
    """Base class for field-level permissions."""
    
    message: str = "Permission denied"
    
    def has_permission(
        self,
        source: Any,
        info: Info,
        **kwargs
    ) -> bool:
        """
        Synchronous permission check.
        
        Args:
            source: Parent object being resolved
            info: GraphQL execution info
            **kwargs: Field arguments
        
        Returns:
            True if permission granted, False otherwise
        """
    
    async def has_permission_async(
        self,
        source: Any,
        info: Info,
        **kwargs
    ) -> bool:
        """
        Asynchronous permission check.
        
        Args:
            source: Parent object being resolved
            info: GraphQL execution info
            **kwargs: Field arguments
        
        Returns:
            True if permission granted, False otherwise
        """

Usage Example:

class IsAuthenticated(strawberry.BasePermission):
    message = "You must be authenticated to access this field"
    
    def has_permission(self, source: Any, info: strawberry.Info, **kwargs) -> bool:
        return info.context.user is not None

class IsOwner(strawberry.BasePermission):
    message = "You can only access your own data"
    
    def has_permission(self, source: Any, info: strawberry.Info, **kwargs) -> bool:
        return info.context.user and source.user_id == info.context.user.id

class IsAdmin(strawberry.BasePermission):
    message = "Admin access required"
    
    async def has_permission_async(self, source: Any, info: strawberry.Info, **kwargs) -> bool:
        user = info.context.user
        if not user:
            return False
        
        # Async database check
        return await is_user_admin(user.id)

@strawberry.type
class User:
    id: strawberry.ID
    name: str
    
    @strawberry.field(permission_classes=[IsAuthenticated, IsOwner])
    def email(self) -> str:
        return self._email
    
    @strawberry.field(permission_classes=[IsAdmin])
    def admin_notes(self) -> str:
        return self._admin_notes

Resolver Context

Info Object

The Info object provides context and metadata to resolvers.

class Info:
    """GraphQL execution info passed to resolvers."""
    
    context: Any  # Request context (user, database connections, etc.)
    field_name: str  # Name of the current field being resolved
    field_nodes: List[FieldNode]  # AST nodes for the field
    is_subscription: bool  # Whether this is a subscription field
    operation_name: str  # Name of the GraphQL operation
    path: List[Union[str, int]]  # Path to this field in the result
    return_type: Type  # Expected return type of the field
    root_value: Any  # Root value passed to the schema
    schema: Schema  # GraphQL schema instance
    variable_values: Dict[str, Any]  # Variables passed to the operation

Usage Example:

@strawberry.type
class Query:
    @strawberry.field
    def current_user(self, info: strawberry.Info) -> Optional[User]:
        # Access request context
        return info.context.user
    
    @strawberry.field
    def field_info(self, info: strawberry.Info) -> str:
        return f"Resolving field '{info.field_name}' at path {info.path}"
    
    @strawberry.field
    def debug_info(self, info: strawberry.Info) -> Dict[str, Any]:
        return {
            "operation_name": info.operation_name,
            "variables": info.variable_values,
            "is_subscription": info.is_subscription
        }

Parent Object Access

Parent: TypeVar  # Type hint for parent object in resolvers

Usage Example:

@strawberry.type
class Post:
    id: strawberry.ID
    title: str
    author_id: strawberry.ID
    
    @strawberry.field
    def author(self) -> User:
        # 'self' is the parent Post object
        return get_user(self.author_id)

@strawberry.type
class User:
    id: strawberry.ID
    name: str
    
    @strawberry.field
    def posts(self, parent: strawberry.Parent[User]) -> List[Post]:
        # Explicit parent type annotation
        return get_posts_by_author(parent.id)

Advanced Field Configuration

Field Extensions

Field extensions allow custom logic to be applied to individual fields.

class FieldExtension:
    """Base class for field-level extensions."""
    
    def apply(self, field: StrawberryField) -> StrawberryField:
        """Apply extension logic to a field."""

Default Values and Factories

@strawberry.type
class User:
    id: strawberry.ID
    name: str
    created_at: datetime = strawberry.field(
        default_factory=datetime.utcnow,
        description="Account creation timestamp"
    )
    is_active: bool = strawberry.field(
        default=True,
        description="Whether the user account is active"
    )
    preferences: Dict[str, Any] = strawberry.field(
        default_factory=dict,
        description="User preferences and settings"
    )

Complex Resolver Examples

@strawberry.type
class Query:
    @strawberry.field
    async def search_users(
        self,
        query: str,
        limit: int = 20,
        info: strawberry.Info
    ) -> List[User]:
        """Async resolver with database operations."""
        async with info.context.database.transaction():
            results = await search_users_in_database(
                query=query,
                limit=limit,
                user_context=info.context.user
            )
            return [User(**user_data) for user_data in results]
    
    @strawberry.field
    def paginated_posts(
        self,
        after: str = None,
        first: int = 10
    ) -> PostConnection:
        """Cursor-based pagination resolver."""
        posts = get_posts_after_cursor(after, first + 1)  # Get one extra
        
        edges = [
            PostEdge(node=post, cursor=encode_cursor(post.id))
            for post in posts[:first]
        ]
        
        return PostConnection(
            edges=edges,
            page_info=PageInfo(
                has_next_page=len(posts) > first,
                end_cursor=edges[-1].cursor if edges else None
            )
        )

Install with Tessl CLI

npx tessl i tessl/pypi-strawberry-graphql

docs

core-types.md

experimental.md

extensions.md

federation.md

fields-resolvers.md

framework-integrations.md

index.md

relay.md

schema-execution.md

utilities.md

tile.json