GraphQL Directives¶
GraphQL directives in graphene-django-extras
allow you to transform field values at query execution time. They provide a powerful way to format, manipulate, and transform data without modifying your underlying models or resolvers.
Overview¶
Directives are applied to fields in your GraphQL queries and are processed after the field value is resolved. They enable you to:
- :material-format-text: Format strings: Transform text case, encoding, and structure
- :material-calendar: Format dates: Display dates in various formats and relative time
- :material-calculator: Format numbers: Apply number formatting and currency display
- :material-shuffle-variant: Manipulate lists: Transform and sample list data
Usage¶
Directives are applied in GraphQL queries using the @directive_name
syntax:
query {
user {
name @uppercase
email @lowercase
joinDate @date(format: "MMMM DD, YYYY")
balance @currency(symbol: "€")
}
}
String Directives¶
String directives provide various text transformation capabilities:
Case Conversion¶
Transform text case with these directives:
String Manipulation¶
Default Values¶
Provide fallback values for empty or null fields:
Encoding Directives¶
Handle base64 encoding and decoding:
Number Directives¶
Format numeric values with precision and style:
Basic Number Formatting¶
Currency Formatting¶
Format numbers as currency with customizable symbols:
Date Directives¶
Powerful date and time formatting with multiple options:
Standard Date Formats¶
query GetPost {
post {
createdAt @date(format: "YYYY-MM-DD") # "2023-12-01"
updatedAt @date(format: "MMMM DD, YYYY") # "December 01, 2023"
publishedAt @date(format: "DD/MM/YYYY HH:mm") # "01/12/2023 14:30"
timestamp @date(format: "iso") # "2023-Dec-01T14:30:00"
jsDate @date(format: "javascript") # "Fri Dec 01 2023 14:30:00"
}
}
Relative Time Formatting¶
Custom Date Patterns¶
Build custom date formats using these tokens:
Token | Description | Example |
---|---|---|
YYYY |
4-digit year | 2023 |
YY |
2-digit year | 23 |
MMMM |
Full month name | December |
MMM |
Short month name | Dec |
MM |
Month number (padded) | 12 |
DD |
Day of month (padded) | 01 |
dddd |
Full day name | Friday |
ddd |
Short day name | Fri |
HH |
Hour (24h, padded) | 14 |
hh |
Hour (12h, padded) | 02 |
mm |
Minutes (padded) | 30 |
ss |
Seconds (padded) | 45 |
A |
AM/PM | PM |
List Directives¶
Transform and manipulate list data:
Shuffle Directive¶
Randomly reorder list elements:
Sample Directive¶
Get a random sample from a list:
Math Directives¶
Perform mathematical operations on numbers:
Floor and Ceil¶
Combining Directives¶
Chain multiple directives for complex transformations:
query GetFormattedData {
user {
firstName @default(to: "Anonymous") @titleCase @strip
email @lowercase @strip
bio @default(to: "No bio") @capitalize @replace(old: ".", new: "!")
}
post {
title @titleCase @replace(old: "GraphQL", new: "GQL")
viewCount @number(as: ",.0f")
createdAt @date(format: "MMMM DD, YYYY")
}
}
Custom Directives¶
While graphene-django-extras
provides many built-in directives, you can create custom ones:
from graphene_django_extras.directives.base import BaseExtraGraphQLDirective
from graphql import GraphQLArgument, GraphQLString
class TruncateGraphQLDirective(BaseExtraGraphQLDirective):
"""Truncate string to specified length."""
@staticmethod
def get_args():
return {
"length": GraphQLArgument(
GraphQLString,
description="Maximum length of string"
),
"suffix": GraphQLArgument(
GraphQLString,
description="Suffix to add when truncated (default: '...')"
)
}
@staticmethod
def resolve(value, directive, root, info, **kwargs):
length_arg = next(
(arg for arg in directive.arguments if arg.name.value == "length"),
None
)
suffix_arg = next(
(arg for arg in directive.arguments if arg.name.value == "suffix"),
None
)
length = int(length_arg.value.value) if length_arg else 100
suffix = suffix_arg.value.value if suffix_arg else "..."
if len(str(value)) <= length:
return value
return str(value)[:length - len(suffix)] + suffix
Schema Integration¶
Add directives to your GraphQL schema:
Middleware Integration¶
Enable directive processing with middleware:
Real-World Examples¶
Blog Post Formatting¶
query GetBlogPost {
post(id: "1") {
title @titleCase
content @strip
excerpt @default(to: "No excerpt available") @capitalize
author {
name @titleCase
email @lowercase
bio @default(to: "No bio") @strip
}
publishedAt @date(format: "MMMM DD, YYYY")
updatedAt @date(format: "time ago")
viewCount @number(as: ",.0f")
tags @sample(size: 5) {
name @uppercase
}
}
}
E-commerce Product Display¶
query GetProduct {
product(id: "123") {
name @titleCase
description @strip @default(to: "No description available")
price @currency(symbol: "$")
originalPrice @currency(symbol: "$")
discount @number(as: ".0%")
weight @number(as: ".2f")
dimensions @replace(old: "x", new: " × ")
createdAt @date(format: "YYYY-MM-DD")
lastModified @date(format: "time ago")
reviews @shuffle {
rating @number(as: ".1f")
comment @strip @default(to: "No comment")
createdAt @date(format: "MMM DD, YYYY")
}
}
}
User Profile Display¶
query GetUserProfile {
user {
username @lowercase
displayName @default(to: "Anonymous User") @titleCase
email @lowercase
bio @default(to: "No bio available") @strip @capitalize
location @titleCase
website @lowercase
socialLinks {
twitter @replace(old: "https://twitter.com/", new: "@")
linkedin @lowercase
}
joinDate @date(format: "MMMM YYYY")
lastActive @date(format: "time ago")
postCount @number(as: ",.0f")
followerCount @number(as: ",.0f")
}
}
Performance Considerations¶
Performance Tips
- Directive Order: Directives are processed in order, so place expensive operations last
- Caching: Directive results aren't cached by default - consider caching formatted values
- Complex Formatting: For heavy date/time operations, consider pre-formatting in resolvers
- List Operations: Be cautious with shuffle/sample on very large lists
Error Handling¶
Directives handle errors gracefully:
Best Practices¶
Directive Best Practices
- Use Defaults: Always provide fallback values for nullable fields
- Format Consistently: Use the same date/number formats across your app
- Chain Wisely: Order directive chains logically (clean → transform → format)
- Test Edge Cases: Test with null, empty, and invalid values
- Document Usage: Document custom directive usage in your API documentation
- Consider Performance: Use directives for display formatting, not heavy processing
GraphQL directives in graphene-django-extras
provide a powerful, flexible way to format and transform your API responses, making your GraphQL API more user-friendly and consistent across different client applications.