Package: django-json-api
django-json-apidjango-json-apiuses Django's ORM interfaces as inspiration to serialize, request and
deserialize entities from databases of other microservices using (and benefiting from) theJSON:APIspecification.InstallationTo install via pip:pipinstalldjango-json-apiYou can also install from the source:gitclonegit@github.com:reveal-co/django-json-api.gitcddjango-json-api
gitcheckoutmain
pipinstall-e.Getting startedSuppose you have adjango.db.models.Modelclass inside microservice A, such as:fromdjango.dbimportmodelsclassCompany(models.Model):name=models.CharField(max_length=256)domain=models.CharField(max_length=256)deleted_at=models.DateTimeField(null=True,default=None)If you wish to consume it from microservice B, first add this inside the aforementioned model's
definition:classJSONAPIMeta:resource_name='companies'and define an instance of adjango_json_api.models.JSONAPIModelinside microservice B:fromdjango_json_api.modelsimportJSONAPIModelfromdjango_json_api.fieldsimportAttributeclassCompany(JSONAPIModel):classMeta:api_url=MICROSERVICE_A_API_URLresource_type='companies'name=Attribute()domain=Attribute()PS:api_urlexpects a url with protocol (i.e. starting withhttp(s)://) and ending with a trailing slash/.Now, querying companies from microservice B is as easy as:Company.objects.all()Company.objects.filter(name="Reveal")Company.objects.iterator()...You can also have entities in one microservice relate to entities in another by leveraging bothRelatedJSONAPIFieldandWithJSONAPIQuerySet. Take a look at this model definition from microservice B:fromdjango.dbimportmodelsfromdjango_json_api.djangoimportRelatedJSONAPIFieldclassUser(models.Model):name=models.CharField(max_length=256)company=RelatedJSONAPIField(json_api_model=Company)deleted_at=models.DateTimeField(null=True,default=None)Here,Companyis theJSONAPIModeldefined above. This makes it possible, when querying for a user, to also
fetch its related company:user=User.objects.get(pk=1)user.company# This will be resolved through an underlying HTTP requestIn case of larger querysets, you might want to prefetch the relations as you do with django'sprefetch_related. For
that, you imbueUser's manager usingWithJSONApiQuerySet, which will grant the manager a new
method:prefetch_jsonapi.If the remote microservice API supports PATCH request, you can save a record's attributes:user=User.objects.get(pk=1)print(user.name)# Joeuser.name="Jack"user.save(update_fields=["name"])# This will perform a PATCH HTTP requestupdated_user=User.from_cache(pk=1)print(updated_user.name)# Jack: the updated record with its new attributes is cachedAuthenticationIt is possible to path aauthparameter to theJSONAPIClientin order to dynamically set the authorization headers on
requests before sending them to the remote HTTP server.In a similar way, it is possible to specifyauthin the models'Meta.importjwtimporttimeclassCustomJWTAuth:def__init__(self:"CustomJWTAuth",subject:str,secret:str,audience:str)->None:self.audience=audienceself.secret=secretself.subject=subjectdef__call__(self:"CustomJWTAuth",request:requests.Request)->requests.Request:iat=int(time.time())token=jwt.encode({"sub":self.subject,"iat":iat,"exp":iat+60,"aud":self.audience},self.secret,"HS256",)request.headers["Authorization"]=f"Bearer{token}"returnrequest# This client will generate a new signed JWT for each requestclient=JSONAPIClient(auth=CustomJWTAuth("myService","*******","jsonapi"))# This model will rely on JWT as well when fetching data from the remote serviceclassModelWithJWT(JSONAPIModel):classMeta:resource_type="examples"auth=CustomJWTAuth("myService","*****","jsonapi")LicenseMIT