When the internet is ruling the world and mobile and web apps are became essential part of our life. The need of high performing, robust applications are required. which comes with redundant functionality being implemented by different applications. can we avoid rebuild same functionality which is well tested and performing well.
can we request the host application for the required information and the service serves the same information if both the party agrees to exchange the information.
RESTFull API is one of the ways to serve this kind of information. Rest API is a light weight Interface to exchange the information between client/clients and server.
REST API will have different API end points to serve each functionality. This is good in 90% of the cases.
lets discuss a requirement to query employee and department details from a service running in a remote server.
we can develop two end points one for getting the employee details ( /employee/{empid} ) and other for department details ( /department/{depid} ).
client can make first REST API call to ( /employee/{empid} ) and parse the response (may be json) to get the department id. and make the second API call to ( /department/{depid} ) by passing department id as @Pathparameters and get the department details. finally client may use just empid and name from the first call, and department id and name from the second response. all good, we got all the information required.
But here There are two potential problems with this approach
- we had to make two REST API call to retrieve all the information we want, though both employee and depart entities has many-to-one relation defined at the database layer.
- Though client just need empid, empname and dept id and dept name. we had to get the complete employee and department information and parse to take just what is require and leave the other data.
Lets get introduced to GraphQL:
GraphQL is a specification to enable query ability on API server to get just what is required for the client.
initially it was developed by Facebook and used as in house application. later on, this was release as a specification so that many languages like javascript, java, python and php can have its's own implementation for the specification.
the advantage of using GraphQL is we can query the related data and retrieve just the fields which client is looking for between the related models. and can avoid hitting the multiple endpoints and shipping over the complete response to client. basically it tries to address 2 basic problems discussed in the REST API.
Note: I have used Django-graphene module to explain the GraphQL. some of the code syntax would be extracted directly from the repository.
some of the main components in GraphQL
Schema:
GraphQL schema defines the implementation for Query and Mutation for API.
Register GraphQL schema:
class Query(omquery.schema.Query, graphene.ObjectType):
# This class will inherit from multiple Queries
# as we begin to add more apps to our project
pass
class Mutation(omquery.schema.Mutation, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query, mutation=Mutation)
ObjectType:
This describers Type of the Object we return from GraphQL, every ObjectType will have a name and more importantly all the class attributes will have implicit Fields.
Object Type can be overridden by providing Meta inner-class with model object reference.
sample of GraphQL ObjectType:
class CellOMType(DjangoObjectType): class Meta: model = CellOM
in simplest form GraphQL is all about querying fields from the ObjectType, by default all the members of the ObjectType are mounted to Field.
each Field will have resolve_<FieldName> method attached.
sample of GraphQL Filed:
cellom = graphene.Field(CellOMType, cellid=graphene.Int())
def resolve_cellom(self, info, **kwargs):
cellid = kwargs.get('cellid')
if cellid is not None:
return CellOM.objects.get(cellid=cellid)
List:
List is used to return multiple ObjectTypes from the resolver
sample of GraphQL List:
all_celloms = graphene.List(CellOMType)
def resolve_all_celloms(self, info, **kwargs):
return CellOM.objects.select_related('enb').all()
Queries:
Queries is the GraphQL schema to "query" different Fields available in the ObjectType (Querya fields are highlighted),
Sample code for Query schema:
class Query(graphene.ObjectType):
all_celloms = graphene.List(CellOMType)
def resolve_all_celloms(self, info, **kwargs):
return CellOM.objects.select_related('enb').all()
cellom = graphene.Field(CellOMType, cellid=graphene.Int())
def resolve_cellom(self, info, **kwargs):
cellid = kwargs.get('cellid')
if cellid is not None:
return CellOM.objects.get(cellid=cellid)
Mutations:
Mutation is the GraphQL schema to "update/insert" Model information and persist on database.
Sample code for Mutation schema:
class EnbOMInput(graphene.InputObjectType):
enbid = graphene.Int()
key = graphene.String()
om10 = graphene.Float()
om11 = graphene.Float()
om12 = graphene.Float()
class CreateEnbOM(graphene.Mutation):
ok = graphene.Boolean()
enb = graphene.Field(EnbOMType)
class Arguments:
input = EnbOMInput(required=True)
@staticmethod
def mutate(root, info, input=None):
ok = True
enb_obj = EnbOM(enb=input.enbid, key=input.key, om10= input.om10, om11= input.om11, om12= input.om12)
enb_obj.save()
return CreateEnbOM(ok= ok, enb = enb_obj)
class Mutation(graphene.ObjectType):
create_enbom = CreateEnbOM.Field()
Relay
Relay is javascript framework built with GraphQL server to enable more interactive query with filters, pagination and mutation for the data.
usually Relay requires one or more "Environment" setup to fire off the requests to GraphQL to perform the necessary actions.
Graphene Django comes with Relay implementation which makes the developer life easy.
sample code snippet:
import graphene.relay as relay from graphene_django.filter.fields import DjangoFilterConnectionField
class Query(graphene.ObjectType): ##Connect to Relay Node to apply filter filds and pagination all_nimsrecs = DjangoFilterConnectionField(NimsTmusType)
sample Request and Response:
if we observe the request and response, it has few additional things added.
every Relay field response will have
1. unique node id: this is base64 unique id for each of the record returns from the GraphQL
2. cursor: This is used for pagination through the Relay cached results, cursor will have "first,last,before,after" to select through the result set and limit the number of results from the complete set.
3. pageinfo: This holds the cursor start and end id's to get the complete information of a single page and query the next pages
Request and Response format from GraphQL View:
Django-graphane comes with GraphQL view, which is very helpful for the GraphQL developers to test the API during development.
please refer to the code for GraphQL implementation here
0 comments:
Post a Comment