Skip to content

Commit 2c59e9e

Browse files
committed
Tweaks docs and deployment
1 parent 3711fdb commit 2c59e9e

File tree

2 files changed

+294
-11
lines changed

2 files changed

+294
-11
lines changed

Diff for: README.md

-4
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,6 @@ Fields on final type will be ordered alphabetically.
306306

307307
We are welcoming contributions to Ariadne! If you've found a bug or issue, feel free to use [GitHub issues](https://github.com/mirumee/ariadne/issues). If you have any questions or feedback, don't hesitate to catch us on [GitHub discussions](https://github.com/mirumee/ariadne/discussions/).
308308

309-
For guidance and instructions, please see [CONTRIBUTING.md](CONTRIBUTING.md).
310-
311-
Website and the docs have their own GitHub repository: [mirumee/ariadne-website](https://github.com/mirumee/ariadne-website)
312-
313309
Also make sure you follow [@AriadneGraphQL](https://twitter.com/AriadneGraphQL) on Twitter for latest updates, news and random musings!
314310

315311
**Crafted with ❤️ by [Mirumee Software](http://mirumee.com)**

Diff for: REFERENCE.md

+294-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# API Reference
2+
3+
- [ObjectType](#ObjectType)
4+
- [SubscriptionType](#SubscriptionType)
5+
- [InputType](#InputType)
6+
- [ScalarType](#ScalarType)
7+
- [InterfaceType](#InterfaceType)
8+
- [UnionType](#UnionType)
9+
- [DirectiveType](#DirectiveType)
10+
- [DeferredType](#DeferredType)
11+
- [BaseType](#BaseType)
12+
- [make_executable_schema](#make_executable_schema)
13+
- [convert_case](#convert_case)
114

215

316
## `ObjectType`
@@ -38,8 +51,6 @@ class QueryType(ObjectType):
3851
return 2022
3952
```
4053

41-
> `ObjectType` could look up return type of `Int` scalar's `serialize` method and compare it with resolver's return type as extra safety net.
42-
4354
If resolver function is not present for field, default resolver implemented by `graphql-core` will be used in its place.
4455

4556
In situations when field's name should be resolved to different value, custom mappings can be defined via `__aliases__` attribute:
@@ -81,8 +92,6 @@ class UserType(ObjectType):
8192
return None
8293
```
8394

84-
> `ObjectType` could raise error if resolver can't be matched to any field on type.
85-
8695

8796
### `__requires__`
8897

@@ -150,12 +159,13 @@ class ChatSubscriptions(SubscriptionType):
150159
"""
151160
__requires__ = [ChatType]
152161

153-
async def resolve_chat(chat_id, *_):
154-
return await get_chat_from_db(chat_id)
155-
156162
async def subscribe_chat(*_):
157163
async for event in subscribe("chats"):
158164
yield event["chat_id"]
165+
166+
async def resolve_chat(chat_id, *_):
167+
# Optional
168+
return await get_chat_from_db(chat_id)
159169
```
160170

161171

@@ -412,3 +422,280 @@ schema = make_executable_schema(
412422
merge_roots=False,
413423
)
414424
```
425+
426+
## `DeferredType`
427+
428+
`DeferredType` names required GraphQL type as provided at later time:
429+
430+
- Via `make_executable_schema` call
431+
- Or via other type's `__requires__`
432+
433+
It's mostly used to define lazy relationships in reusable modules and to break circular relationships.
434+
435+
436+
### Type with `DeferredType` and other type passed to `make_executable_schema`:
437+
438+
```python
439+
class QueryType(ObjectType):
440+
__schema__ = """
441+
type Query {
442+
id: ID!
443+
users: [User!]!
444+
}
445+
"""
446+
__requires__ = [DeferredType("User")]
447+
448+
449+
class UserType(ObjectType):
450+
__schema__ = """
451+
type User {
452+
id: ID!
453+
dateJoined: String!
454+
}
455+
"""
456+
457+
458+
schema = make_excutable_schema(QueryType, UserType)
459+
```
460+
461+
462+
### Type with `DeferredType` and other type passed as dependency of third type:
463+
464+
```python
465+
class UsersGroupType(ObjectType):
466+
__schema__ = """
467+
type UsersGroup {
468+
id: ID!
469+
users: [User!]!
470+
}
471+
"""
472+
__requires__ = [UserType]
473+
474+
475+
class UserType(ObjectType):
476+
__schema__ = """
477+
type User {
478+
id: ID!
479+
dateJoined: String!
480+
}
481+
"""
482+
483+
484+
class QueryType(ObjectType):
485+
__schema__ = """
486+
type Query {
487+
id: ID!
488+
users: [User!]!
489+
groups: [UsersGroup!]!
490+
}
491+
"""
492+
__requires__ = [DeferredType("User"), UsersGroupType]
493+
494+
495+
schema = make_excutable_schema(QueryType)
496+
```
497+
498+
499+
## `BaseType`
500+
501+
Base type that all other types extend. You can use it to create custom types:
502+
503+
```python
504+
from typing import Dict
505+
506+
from ariadne_graphql_modules import BaseType
507+
from django.db.models import Model
508+
from graphql import GraphQLFieldResolver
509+
510+
class ModelType(BaseType)
511+
__abstract__ = True
512+
__schema__ = str
513+
__model__ = Model
514+
515+
resolvers: Dict[str, GraphQLFieldResolver]
516+
517+
def __init_subclass__(cls) -> None:
518+
super().__init_subclass__()
519+
520+
if cls.__dict__.get("__abstract__"):
521+
return
522+
523+
cls.__abstract__ = False
524+
525+
if not cls.__model__:
526+
raise ValueError(
527+
f"{cls.__name__} was declared without required '__model__' attribute"
528+
)
529+
530+
cls.__schema__ = cls.__create_schema_from_model__()
531+
cls.resolvers = cls.__get_resolvers__()
532+
533+
@classmethod
534+
def __create_schema_from_model__(cls) -> str:
535+
... # Your logic that creates GraphQL SDL from Django model
536+
537+
@classmethod
538+
def __get_resolvers__(cls) -> Dict[str, GraphQLFieldResolver]:
539+
... # Your logic that creates resolvers map from model and cls
540+
541+
@classmethod
542+
def __bind_to_schema__(cls, schema):
543+
# Bind resolvers map to schema, called by `make_executable_schema`
544+
graphql_type = schema.type_map.get(cls.graphql_name)
545+
546+
for field_name, field_resolver in cls.resolvers.items():
547+
graphql_type.fields[field_name].resolve = field_resolver
548+
```
549+
550+
551+
## `make_executable_schema`
552+
553+
```python
554+
def make_executable_schema(
555+
*types: BaseType,
556+
merge_roots: bool = True,
557+
) -> GraphQLSchema:
558+
...
559+
```
560+
561+
Utility function that takes args with types and creates executable schema.
562+
563+
564+
### `merge_roots: bool = True`
565+
566+
If set to true (default), `make_executable_schema` will automatically merge multiple `Query`, `Mutation` and `Subscription` types instead of raising error.
567+
568+
Final merged types fields will be ordered alphabetically:
569+
570+
```python
571+
class YearType(ObjectType):
572+
__schema__ = """
573+
type Query {
574+
year: Int!
575+
}
576+
"""
577+
578+
@classmethod
579+
def resolve_year(*_):
580+
return 2022
581+
582+
583+
class MonthType(ObjectType):
584+
__schema__ = """
585+
type Query {
586+
month: Int!
587+
}
588+
"""
589+
590+
@classmethod
591+
def resolve_month(*_):
592+
return 10
593+
594+
595+
schema = make_executable_schema(YearType, MonthType)
596+
597+
assert print_schema(schema) == """
598+
type Query {
599+
month: Int!
600+
year: Int!
601+
}
602+
"""
603+
```
604+
605+
When `merge_roots=False` is explicitly set, `make_executable_schema` will raise an GraphQL error that `type Query` is defined more than once.
606+
607+
608+
## `convert_case`
609+
610+
Utility function that can be used to automatically setup case conversion rules for types.
611+
612+
613+
#### Resolving fields values
614+
615+
Use `__aliases__ = convert_case` to automatically set aliases for fields that convert case
616+
617+
```python
618+
from ariadne_graphql_modules import ObjectType, convert_case, gql
619+
620+
621+
class UserType(ObjectType):
622+
__schema__ = gql(
623+
"""
624+
type User {
625+
id: ID!
626+
fullName: String!
627+
}
628+
"""
629+
)
630+
__aliases__ = convert_case
631+
```
632+
633+
634+
#### Converting fields arguments
635+
636+
Use `__fields_args__ = convert_case` on type to automatically convert field arguments to python case in resolver kwargs:
637+
638+
```python
639+
from ariadne_graphql_modules import MutationType, convert_case, gql
640+
641+
from my_app import create_user
642+
643+
644+
class UserRegisterMutation(MutationType):
645+
__schema__ = gql(
646+
"""
647+
type Mutation {
648+
registerUser(fullName: String!, email: String!): Boolean!
649+
}
650+
"""
651+
)
652+
__fields_args__ = convert_case
653+
654+
async def resolve_mutation(*_, full_name: str, email: str):
655+
user = await create_user(
656+
full_name=full_name,
657+
email=email,
658+
)
659+
return bool(user)
660+
```
661+
662+
663+
#### Converting inputs fields
664+
665+
Use `__args__ = convert_case` on type to automatically convert input fields to python case in resolver kwargs:
666+
667+
```python
668+
from ariadne_graphql_modules import InputType, MutationType, convert_case, gql
669+
670+
from my_app import create_user
671+
672+
673+
class UserRegisterInput(InputType):
674+
__schema__ = gql(
675+
"""
676+
input UserRegisterInput {
677+
fullName: String!
678+
email: String!
679+
}
680+
"""
681+
)
682+
__args__ = convert_case
683+
684+
685+
class UserRegisterMutation(MutationType):
686+
__schema__ = gql(
687+
"""
688+
type Mutation {
689+
registerUser(input: UserRegisterInput!): Boolean!
690+
}
691+
"""
692+
)
693+
__requires__ = [UserRegisterInput]
694+
695+
async def resolve_mutation(*_, input: dict):
696+
user = await create_user(
697+
full_name=input["full_name"],
698+
email=input["email"],
699+
)
700+
return bool(user)
701+
```

0 commit comments

Comments
 (0)