create-graphql-layer
Create GraphQL Operations classes (BaseOperations subclass with auto-fragment injection) and Pydantic GqlModel types for response/input types
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Create GraphQL Operations classes (BaseOperations subclass with auto-fragment injection) and Pydantic GqlModel types for response/input types
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Review test files for pattern compliance, code quality, correctness, coverage gaps, and best practices — produces actionable feedback
Scaffold E2E UI test files following project patterns — Playwright assertions, Page Objects, Components, markers, fixtures, Allure decorators, BrowserStorage
Scaffold GraphQL API test files following project patterns — markers, fixtures, Allure decorators, Pydantic assertions, try-finally cleanup
Scaffold REST API test files and factory fixture conftest files — admin auth, RestClient, factory fixtures with auto-teardown, Allure steps, CRUD patterns
Create Page Objects (MainLayout/CheckoutLayout subclasses) and UI Components (Component subclasses) with Playwright locators and data-test-id conventions
Migrate a Katalon REST API test module from vc-quality-gate-katalon into the refactored Pytest project — end-to-end flow from inventory to CI-verified PR
| name | create-graphql-layer |
| description | Create GraphQL Operations classes (BaseOperations subclass with auto-fragment injection) and Pydantic GqlModel types for response/input types |
| argument-hint | <entity> |
When creating GraphQL Operations classes or Pydantic types, follow these patterns exactly.
gql/operations/<entity>_operations.pygql/types/<entity>.pygql/types/<entity>_input.pygql/fragments/<entity>.graphqlgql/operations/__init__.py, gql/types/__init__.pyAll GraphQL types MUST inherit from GqlModel:
from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel
class GqlModel(BaseModel):
model_config = ConfigDict(
alias_generator=to_camel, # snake_case -> camelCase
populate_by_name=True, # Accept both forms
)
from gql.types.base import GqlModel
from gql.types.money import Money
from gql.types.line_item import LineItem
class Cart(GqlModel):
id: str
store_id: str # Alias: storeId
is_anonymous: bool # Alias: isAnonymous
has_physical_products: bool
customer_id: str
total: Money
sub_total: Money
items_count: int
items_quantity: int
items: list[LineItem]
payments: list[Payment] = [] # Optional lists default to []
shipments: list[Shipment] = []
coupons: list[Coupon] = []
Key patterns:
GqlModel — never BaseModel directlyto_camel auto-aliases to camelCasefield: str | None = Nonefield: list[Type] = []from pydantic import ConfigDict, Field
from gql.types.base import GqlModel
class CartItemInput(GqlModel):
model_config = ConfigDict(alias_generator=None, populate_by_name=True)
product_id: str = Field(serialization_alias="productId")
quantity: int = 1
Key patterns:
alias_generator=None to prevent auto-aliasing on deserializationField(serialization_alias="productId") for explicit output aliasingmodel_dump(by_alias=True) — produces {"productId": "...", "quantity": 1}from gql.operations.base_operations import BaseOperations, gql
from gql.types.cart import Cart
from gql.types.cart_item_input import CartItemInput
class CartOperations(BaseOperations):
def get_cart(
self,
store_id: str,
user_id: str,
currency_code: str,
culture_name: str,
cart_id: str | None = None,
) -> Cart | None:
# fmt: off
query = gql("""
query GetCart($storeId: String!, $userId: String!, $currencyCode: String!, $cultureName: String!, $cartId: String) {
cart(storeId: $storeId, userId: $userId, currencyCode: $currencyCode, cultureName: $cultureName, cartId: $cartId) {
...CartFragment
}
}
""")
# fmt: on
result = self._client.execute(
self._build_query(query),
variables={
"storeId": store_id,
"userId": user_id,
"currencyCode": currency_code,
"cultureName": culture_name,
"cartId": cart_id,
},
)
data = result["data"]["cart"]
return Cart.model_validate(data) if data else None
def add_items_to_cart(
self,
store_id: str,
user_id: str,
items: list[CartItemInput],
currency_code: str | None = None,
culture_name: str | None = None,
) -> Cart:
# fmt: off
mutation = gql("""
mutation AddItemsCart($command: InputAddItemsType!) {
addItemsCart(command: $command) {
...CartFragment
}
}
""")
# fmt: on
command = {
"storeId": store_id,
"userId": user_id,
"cartItems": [i.model_dump(by_alias=True) for i in items],
**({"currencyCode": currency_code} if currency_code else {}),
**({"cultureName": culture_name} if culture_name else {}),
}
result = self._client.execute(
self._build_query(mutation),
variables={"command": command},
)
return Cart.model_validate(result["data"]["addItemsCart"])
def delete_cart(self, cart_id: str, user_id: str) -> bool:
# fmt: off
mutation = gql("""
mutation RemoveCart($command: InputRemoveCartType!) {
removeCart(command: $command)
}
""")
# fmt: on
result = self._client.execute(
self._build_query(mutation),
variables={"command": {"cartId": cart_id, "userId": user_id}},
)
return result["data"]["removeCart"]
BaseOperations._build_query(operation) automatically:
gql/fragments/*.graphql for fragment definitions...FragmentName spreads in the operationFragment file example (gql/fragments/cart.graphql):
fragment CartFragment on CartType {
id
storeId
isAnonymous
hasPhysicalProducts
customerId
total { ...MoneyFragment }
subTotal { ...MoneyFragment }
itemsCount
itemsQuantity
items { ...LineItemFragment }
payments { ...PaymentFragment }
shipments { ...ShipmentFragment }
coupons { ...CouponFragment }
}
You only write ...CartFragment in operations — _build_query() handles the rest.
# gql/operations/__init__.py
from gql.operations.cart_operations import CartOperations
from gql.operations.order_operations import OrderOperations
# gql/types/__init__.py
from gql.types.cart import Cart
from gql.types.cart_item_input import CartItemInput
from gql.types.order import Order
BaseOperations — constructor: __init__(self, client: GraphQLClient)gql("""...""")# fmt: off / # fmt: on around multi-line GraphQL stringsself._build_query(query) for auto-fragment injection — ALWAYS use thisCart.model_validate(data)None for nullable queries: return Cart.model_validate(data) if data else Nonemodel_dump(by_alias=True): [i.model_dump(by_alias=True) for i in items]**({"key": val} if val else {})GqlModel — never BaseModel__init__.py exports.graphql file for any new entity type