Package: typegql
TypeGQLA PythonGraphQLlibrary that makes use of type hinting and concurrency support with the new async/await syntax.
With the help of type hints and dataclass it’s easy to build a GraphQL schema using nothing but Python objects and primitivesConsider the following:fromgraphqlimport(GraphQLSchema,GraphQLObjectType,GraphQLField,GraphQLString)schema=GraphQLSchema(query=GraphQLObjectType(name='RootQueryType',fields={'hello':GraphQLField(GraphQLString,resolve=lambdaobj,info:'world')}))Versus:fromdataclassesimportdataclassfromtypegqlimportSchema@dataclass(init=False)classRootQuery:hello:strdefresolve_hello(info):return'worldschema=Schema(query=RootQuery)Clearly the second one looks more “Pythonic” and it’s easier to maintain for complex structuresInstallationpipinstalltypegqlUsageThe following demonstrates how to usetypegqlfor implementing aGraphQL APIfor a library of books.
The example can be found intypegql/core/examplesand you can run it with Sanic by executingpython<path_to_example>/server.pyDefine your queryfromdataclassesimportdataclassfromtypingimportListfromtypegqlimportConnectionfromtypegql.examples.library.typesimportAuthor,Categoryfromtypegql.examples.library.typesimportBookfromtypegql.examples.libraryimportdb@dataclass(init=False,repr=False)classQuery:books:List[Book]authors:List[Author]categories:List[Category]books_connection:Connection[Book]asyncdefresolve_authors(self,info,**kwargs):returndb.get('authors')asyncdefresolve_books(self,info,**kwargs):returndb.get('books')asyncdefresolve_categories(self,info,**kwargs):returndb.get('categories')asyncdefresolve_books_connection(self,info,**kwargs):data=db.get('books')return{'edges':[{'node':node}fornodeindata]}Define your typesfromdataclassesimportdataclass,fieldfromdatetimeimportdatetimefromdecimalimportDecimalfromenumimportEnumfromtypingimportListfromexamples.libraryimportdbclassGender(Enum):MALE='male'FEMALE='female'@dataclassclassGeoLocation:latitude:Decimallongitude:Decimal@dataclassclassAuthor:"""Person that is usually a writer"""id:ID=field(metadata={'readonly':True})name:strgender:Optional[Gender]=Nonegeo:Optional[GeoLocation]=Nonebooks:Optional[List[Book]]=None@dataclassclassCategory:id:ID=field(metadata={'readonly':True})name:str@dataclassclassBook:"""A book... for reading :|"""id:ID=field(metadata={'readonly':True})author_id:IDtitle:strauthor:Optional[Author]=field(default=None,metadata={'description':'The author of this book'})categories:Optional[List[Category]]=Nonepublished:Optional[datetime]=Nonetags:Optional[List[str]]=Nonedef__post_init__(self):self.published=datetime.strptime(self.published,'%Y-%m-%d%H:%M:%S')asyncdefresolve_author(self,info):data=filter(lambdax:x['id']==self.author_id,db.get('authors'))data=next(data)author=Author(**data)author.gender=Gender(author.gender)if'geo'indata:author.geo=GeoLocation(**data.get('geo'))returnauthorasyncdefresolve_categories(self,selections,name=None):data=filter(lambdax:x['id']inself.categories,db.get('categories'))fordindata:# showcasing async generatoryieldCategory(**d)defresolve_tags(self,selections):return['testing','purpose']Run your queryfromtypegqlimportSchemafromexamples.library.queryimportQueryschema=Schema(Query)query='''
query BooksConnection {
  books_connection {
    edges {
      node {
        id
        title
        published
        author {
          id
          name
        }
      }
    }
  }
}
'''asyncdefrun():result=awaitschema.run(query)ClientTypeGQL supports DSL client for working with a GraphQL API.
The client automatically converts snake to camelcase. Setcamelcase=Falseif this is not desired.pipinstalltypegql[client]For example:fromtypegql.clientimportClientasyncwithClient(url,camelcase=True)asclient:awaitclient.introspection()dsl=client.dslquery=dsl.Query.books_connection.select(dsl.BooksConnection.total_count)doc=dsl.query(query)status,result=awaitclient.execute(doc)Change Log4.0.2 [2020-04-06]updates graphql-core to 3.1.04.0.1 [2020-03-17]fixes enum return value4.0.0 [2020-03-16]BREAKING CHANGES:Schemanow accepts a more granular list of custom graphql types. Signature is:def__init__(self,query:Type,mutation:Optional[Type]=None,subscription:Optional[Type]=None,scalars:Optional[GraphQLScalarMap]=None,enums:Optional[GraphQLEnumMap]=None,interfaces:Optional[GraphQLInterfaceMap]=None,query_types:Optional[GraphQLObjectTypeMap]=None,mutation_types:Optional[GraphQLInputObjectTypeMap]=None,camelcase=True):3.1.0 [2020-01-29]fixes an issue with camelcase parameters when aloadmethod is provided3.0.9 [2020-01-13]fix client execution functionupdatedslselections to work withFrozenList3.0.8 [2020-01-07]added ability to ignore attributes in building the schema by usingfield(metadata={‘skip’: True}). This can be useful when you don’t want to expose certain fields in GraphQL, like a user’spasswordfor example.3.0.5 [2019-12-16]added support for subscriptions3.0.4 [2019-12-04]updatesgraphql-core-nexttograpqhl-core>= 3use Sequence instead of List where possible3.0.3 [2019-11-29]fixed a bug where a custom connection arguments don’t include the relay pagination arguments as well3.0.2 [2019-11-26]PEP 561 compliant3.0.1 [2019-11-26]BREAKING: RemovedGraphas a baseclassnow makes use ofdataclasses.dataclassanddataclasess.fieldsfor building theSchemabug fixing and improvements2.0.9 [2019-10-29]changed the name of an input object from ObjectMuation to ObjectInput2.0.8 [2019-10-15]allows forward reference between graph types (ie:Bookhas anauthorand anAuthorhasbooks).this only works with python 3.7(usingfrom __future__ import annotations, or python 3.82.0.6 [2019-06-24]updates uvloop dependency2.0.5 [2019-04-24]fixed a bug when sendingintrospection schema2.0.4 [2019-04-24]updates assert for introspection add message with status and resultadds support for enum objects inresolve_field_velue_or_error2.0.3 [2019-02-08]changesConnection,Edge,NodeandPageInfoto interfacesIConnection,IEdge, etc.implements defaultConnectionandPageInfoobjectsremoveshas_next,has_previousfromPageInfo2.0.1 [2019-01-19]all properties that don’t have aFieldinstance assigned to them will be ignored by theSchemaupdates docs & example to reflect 2.0 changesfixed a bug when using aListargument in mutations1.0.7 [2018-12-09]bug fixingadds support for camelcase in Client1.0.1 [2018-11-19]adds support for client DSLInitialaddedgraphql-core-nextas a baseline for all GraphQL operationsTODOtestingtravismore testingplease help with testing :|