Skip to main content

JSON API specification for Django services

Project description

django-json-api

PyPI version codecov Reveal License: MIT

django-json-api uses Django's ORM interfaces as inspiration to serialize, request and deserialize entities from databases of other microservices using (and benefiting from) the JSON:API specification.

Installation

To install via pip:

pip install django-json-api

You can also install from the source:

git clone git@github.com:reveal-co/django-json-api.git
cd django-json-api
git checkout main
pip install -e .

Getting started

Suppose you have a django.db.models.Model class inside microservice A, such as:

from django.db import models

class Company(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:

    class JSONAPIMeta:
        resource_name = 'companies'

and define an instance of a django_json_api.models.JSONAPIModel inside microservice B:

from django_json_api.models import JSONAPIModel
from django_json_api.fields import Attribute

class Company(JSONAPIModel):
    class Meta:
        api_url = MICROSERVICE_A_API_URL
        resource_type = 'companies'

    name = Attribute()
    domain = Attribute()

PS: api_url expects a url with protocol (i.e. starting with http(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 both RelatedJSONAPIField and WithJSONAPIQuerySet. Take a look at this model definition from microservice B:

from django.db import models
from django_json_api.django import RelatedJSONAPIField


class User(models.Model):
    name = models.CharField(max_length=256)
    company = RelatedJSONAPIField(json_api_model=Company)
    deleted_at = models.DateTimeField(null=True, default=None)

Here, Company is the JSONAPIModel defined 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 request

In case of larger querysets, you might want to prefetch the relations as you do with django's prefetch_related. For that, you imbue User's manager using WithJSONApiQuerySet, 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)  # Joe
user.name = "Jack"
user.save(update_fields=["name"]) # This will perform a PATCH HTTP request
updated_user = User.from_cache(pk=1)
print(updated_user.name)  # Jack: the updated record with its new attributes is cached

Authentication

It is possible to path a auth parameter to the JSONAPIClient in 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 specify auth in the models' Meta.

import jwt
import time


class CustomJWTAuth:
    def __init__(self: "CustomJWTAuth", subject: str, secret: str, audience: str) -> None:
    	self.audience = audience
    	self.secret = secret
	self.subject = subject

    def __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}"
	return request

# This client will generate a new signed JWT for each request
client = JSONAPIClient(auth=CustomJWTAuth("myService", "*******", "jsonapi"))

# This model will rely on JWT as well when fetching data from the remote service
class ModelWithJWT(JSONAPIModel):
    class Meta:
        resource_type = "examples"
        auth = CustomJWTAuth("myService", "*****", "jsonapi")

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-json-api-1.2.1.tar.gz (26.5 kB view details)

Uploaded Source

Built Distribution

django_json_api-1.2.1-py3-none-any.whl (30.8 kB view details)

Uploaded Python 3

File details

Details for the file django-json-api-1.2.1.tar.gz.

File metadata

  • Download URL: django-json-api-1.2.1.tar.gz
  • Upload date:
  • Size: 26.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.8.7

File hashes

Hashes for django-json-api-1.2.1.tar.gz
Algorithm Hash digest
SHA256 5b5fe1fd7e4ac15a6572fc8b63e14f69ea86d8b83c6e3b95d1106daf3e1b731e
MD5 f1b67c5a4cd44c4eaf5c2c1e2280b195
BLAKE2b-256 ed84cf1ba30b6571119466142f4c57b10001895301ae7523e76d2d5f95de3caf

See more details on using hashes here.

File details

Details for the file django_json_api-1.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for django_json_api-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0c15915ef6e9ba85574e121acbd535a89300fa5e44c856dfeb567a240ec19800
MD5 86a5c26b2363ed04a0462fa18823d636
BLAKE2b-256 c4e0bb209413dd9fa5166c789448ed2cedc9ac93cffff86e34827a0349d165f9

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page