Building a JSON:API backend with Django REST Framework JSON API (2023)

Django REST Framework JSON APIis a library for creating JSON:API backends using thedjango structure, built on top ofDjango REST Frameworklibrary.

To test it, let's create a web service for rating dishes in restaurants. Let's call it "Ate Opinion".

First,Install Python.

Create a new Python project with a virtual environment:

psmkdirdjango_jsonapipscddjango_jsonapipspython3-metrovenvenvironmentpssource environment/bin/activate

Install Django itself:


Now create a Django project and application:

psdjango-admin startproject django_jsonapi. # Notice the ending '.' characterpsdjango-admin startapp look_ate

Updatedjango_jsonapi/settings.pyto indicate thatopinar_ateis an installed application:

INSTALLED_APPLICATIONS = [+ 'opinion_ate.apps.OpinionAteConfig','django.contrib.admin',


Django maintains the data in the database using classes called Models. The Django REST Framework JSON API uses the same templates, so to start building our app, we'll create templates in the typical Django way.

Replace the content ofopinion_ate/modelos.pywith the following:

of django.db matter modelsclassroom restaurant(models.Model): name = models.CharFieldName(maximum length=200) ADDRESS = models.CharFieldName(maximum length=200)classroom Prato(models.Model): name = models.CharFieldName(maximum length=200) assessment = models.CampoEntero() restaurant = models.foreign key(restaurant, on_delete=models.WATERFALL)

This defines two new models,restaurantmiPrato.restaurantIt has onenamemiADDRESSfield in it, both character fields.PratoIt has onenamecharacter field, aassessmentinteger and a foreign key pointing to the relatedrestaurant.

Then create a database migration to update the database to match our current model definitions:

pspython makemigrations opinion_ate

By default, a new Django application is configured with an SQLite database, which is just a flat file. This is the easiest way to do it for experimentation purposes. If you want to use another SQL database like Postgres or MySQL, follow the Django docs atinstall the appropriate database links.

Run the following command to perform these migrations on the SQLite database:

psmove python

Now that our templates are set up, we can create some records. You can do this manually, but Django has the concept of plugin files, which allow you to import sample data into Django's database. We are going to use this to configure some data. Create oneopinion_ate/accessories/folder then arestaurants.jsonfile inside it with the following content:

[ { "model": "opinion_ate.restaurante", "package": 1, "Campos": { "name": "sushi place", "ADDRESS": "123 Main Street" } }, { "model": "opinion_ate.prato", "package": 1, "Campos": { "name": "Rollo Volcano", "assessment": 3, "restaurant_id": 1 } }, { "model": "opinion_ate.prato", "package": 2, "Campos": { "name": "Salmon nigiri", "assessment": 4, "restaurant_id": 1 } }, { "model": "opinion_ate.restaurante", "package": 2, "Campos": { "name": "burger place", "ADDRESS": "456 another street" } }, { "model": "opinion_ate.prato", "package": 3, "Campos": { "name": "BBQ Burger", "assessment": 5, "restaurant_id": 2 } }, { "model": "opinion_ate.prato", "package": 4, "Campos": { "name": "Slider", "assessment": 3, "restaurant_id": 2 } }]

Load the data from the device with the following command:

pspython loaddata restaurants

Web service configuration

Now that we have all of our data set up, let's set up the Django REST Framework JSON API (DJA) so that we can access it through a web service.

Install the following dependencies:

psnuggetinstalldjangorestframeworkpsnuggetinstalldjangorestframework-jsonapipsnuggetinstalldjango filter

To addrest_frameworkas an installed application for your project indjango_jsonapi/

INSTALLED_APPS = [ 'opinion_ate.apps.OpinionAteConfig',+ 'rest_frame','django.contrib.admin',

Then configure Django REST Framework to use the JSON API by pasting this large part of the configuration indjango_jsonapi/ This comes directly from the DJA docs, with one exception: we've disabled pagination here for simplicity.

REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'rest_framework_json_api.excepciones.exception_handler', 'DEFAULT_PAGINATION_CLASS': 'rest_framework_json_api.pagination.JsonApiPageNumberPagination', 'DEFAULT_PARSER_CLASSES': ( 'rest_framework_json_api.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ), 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework_json_api.renderers.JSONRenderer', # If you are testing performance, you may want to use the browsable API # without forms, since forms can generate their own queries. # If you are testing performance, enable: # 'ejemplo.utils.BrowsableAPIRendererWithoutForms', # Otherwise, to play with the browsable API, enable: 'rest_framework.renders.BrowsableAPIRenderer' ), 'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata', 'DEFAULT_FILTER_BACKENDS': ( 'rest_framework_json_api.filters.QueryParameterValidationFilter', 'rest_framework_json_api.filters.OrderingFilter', 'rest_framework_json_api.django_filters.DjangoFilterBackend', 'rest_framework.filters.SearchFilter', ), 'BUSCAR_PARAM': 'filter [search]', 'TEST_REQUEST_RENDERER_CLASSES': ( 'rest_framework_json_api.renderers.JSONRenderer', ), 'TEST_REQUEST_DEFAULT_FORMAT': 'vnd.api+json'}

To set up a DJA web service, we must first create "serializers", which translate the templates into their format for the end user. Create oneseem_ate/serializers.pyfile and add the following content:

of rest_framework_json_api matter serializersof models_ate.models review matter restaurant, Pratoclassroom RestaurantSerializer(serializers.HyperlinkedModelSerializerHyperlinkedModelSerializer): classroom meta: model = restaurant Campos = ('name', 'ADDRESS', 'plate_set')classroom DishSerializer(serializers.HyperlinkedModelSerializerHyperlinkedModelSerializer): classroom meta: model = Prato Campos = ('name', 'assessment', 'restaurant')

DJA doesn't want to make assumptions about the data we want to expose to end users; we have to say this explicitly. EITHERCamposThe values ​​we provide mean that these fields will be exposed to the end user.

but what is thecrockeryfield inrestaurant? This is the inverse ofplate.restaurantforeign key; is the set of dishes associated with a restaurant. We didn't need to declare this in the model; it is automatically available under a dish in a restaurant.

Now that our serializers are defined, we need to create views that handle HTTP requests for restaurants and dishes. DJA provides basic viewset classes that will give us what we need with just a little configuration. To replaceopinion_ate/views.pywith the following:

of models_ate.models review matter restaurant, Pratoof parecer_ate.serializers matter RestaurantSerializer, DishSerializerof rest_framework matter see setsclassroom RestauranteVistaConjunto(see sets.ModelViewSet): query set = restaurant.objects.all() serializer_class = RestaurantSerializerclassroom PlatoVerConjunto(see sets.ModelViewSet): query set = Prato.objects.all() serializer_class = DishSerializer

The last piece of the puzzle is connecting the URLs. Opendjango_json / URLand replace the content with the following:

of django.urls matter include, caminoof rest_framework matter routersof opinar_ate matter Points of viewrouter = routers.default router()router.record(r'restaurants', Points of view.RestauranteVistaConjunto)router.record(r'dishes', Points of view.PlatoVerConjunto)url pattern = [ camino('', include(router.URL)),]

This will connect all the necessary URLs. For example, for restaurants, the following main URLs are now available:

  • GET /restaurants/ — lists all restaurants
  • POST /restaurants/ — creates a new restaurant
  • GET /restaurants/:id — get a restaurant
  • PATCH /restaurants/:id — updates a restaurant
  • DELETE /restaurants/:id — deletes a restaurant

That's a lot we can accomplish without having to write almost any code!


Now let's try. Start the Django server:

pspython runtime server

Visithttp://localhost:8000/platos/1in your browser. You should see something like the following:

{ "data": { "type": "Praton", "I was going": "1", "attributes": { "name": "Rollo Volcano", "assessment": 3 }, "relations": { "restaurant": { "data": { "type": "Restaurant", "I was going": "1" }, "connections": { "related": "http://localhost:8000/restaurantes/1/" } } } }}

if you are usingfire foxyou should see the JSON data formatted correctly. If your browser doesn't automatically format JSON, you can find a browser extension to do it. For example, for Chrome you can useJSONVer.

This is a JSON:API response for a single record. Let's talk about what's going on here:

  • the upper leveldataThe property contains the main data of the response. In this case, it's a record; can also be an array.
  • Although you can infer the record type from the context, JSON:API records always have atypefield record of what type they are. In some contexts, records of different types will be mixed in an array, so this keeps them distinct.
  • The record contains aI was goingA property that provides the publicly exposed ID of the record, which by default is the full database ID. But JSON:API IDs are always exposed as strings, to allow for the possibility of slugs or UUIDs.
  • attributesis an object that contains all the attributes that we have exposed. They are nested instead of being directly in the record to avoid collision with other standard JSON:API properties, such astype.
  • relationsprovides data about relationships for this record. In this case, the record has arestaurantrelationship. We receive a "resource identifier object", which contains the type and id of the record, but not its attributes.

try to visithttp://localhost:8000/restaurantes/, in the browser. You will see the following:

{ "data": [ { "type": "Restaurant", "I was going": "1", "attributes": { "name": "sushi place", "ADDRESS": "123 Main Street" }, "relations": { "plate_game": { "data": [ { "type": "Praton", "I was going": "1" }, { "type": "Praton", "I was going": "2" } ], "meta": { "say": 2 } } } }, { "type": "Restaurant", "I was going": "2", "attributes": { "name": "burger place", "ADDRESS": "456 another street" }, "relations": { "plate_game": { "data": [ { "type": "Praton", "I was going": "3" }, { "type": "Praton", "I was going": "4" } ], "meta": { "say": 2 } } } } ]}

Note that this time thedatais an array of two records. Each of them also has its ownrelationsgoing back to the dishes associated with the restaurant. These relationships are where DJA really shines. Instead of manually creating URLs, views, and queries for all of these relationships, DJA exposes them for you. And since it uses the standard JSON:API format, there are pre-built client tools that can save the same type of code on the front-end!

Next, let's try to create a record. We won't be able to do this in the browser; we'll need a more sophisticated web service client to do this. A good option isMailman- download and run it.

You can also use Postman for GET requests: set up a GET request forhttp://localhost:8000/restaurantes/and see how it shows the same data as the browser.

Next, let's create a POST request to the same URL,http://localhost:8000/restaurantes/. Go to the Headers tab and enter the key "Content-type" and the value "application/vnd.api+json"; this is the content type that JSON:API requires.

Then switch to the Body tab. Click the "none" dropdown menu and change it to "raw." Another "Text" dropdown will appear; change it to "JSON". Enter the following:

{ "data": { "type": "Restaurant", "attributes": { "name": "Spaghetti Place", "ADDRESS": "Calle 3 789", "plate_game": [] } }}

Please note that you do not need to provide aI was goingbecause we trust the server to generate it. And we don't have to provide therelationsolinks, soloattributeswe want to set the new record.

Now that our request is set up, click Submit and you should get a "201 Created" response, with the following body:

{ "data": { "type": "Restaurant", "I was going": "3", "attributes": { "name": "Spaghetti Place", "ADDRESS": "Calle 3 789" }, "relations": { "plate_game": { "data": [], "meta": { "say": 0 } } } }}

Our new record is created and the data is returned to us!

If you want to try updating and deleting records:

  • make aCORRECTIONapplicationhttp://localhost:8000/restaurantes/3/, passing updatedattributes.
  • make aDELETEapplicationhttp://localhost:8000/restaurantes/3/there is no body to clear the record.

Has more

We saw a lot of help from the Django REST Framework JSON API: the ability to create, read, update, and delete records, including relationships between records. But it also offers much more! It allows you to request only a subset of the required fields, allows you to include related records in the response, as well as sort, filter, and paginate. For more information, seethe DJ guide.

Now that you have a JSON:API backend, try connecting to it from the frontend. Choose a tutorialAs JSON: API home page!

Top Articles
Latest Posts
Article information

Author: Greg Kuvalis

Last Updated: 01/04/2023

Views: 6459

Rating: 4.4 / 5 (55 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Greg Kuvalis

Birthday: 1996-12-20

Address: 53157 Trantow Inlet, Townemouth, FL 92564-0267

Phone: +68218650356656

Job: IT Representative

Hobby: Knitting, Amateur radio, Skiing, Running, Mountain biking, Slacklining, Electronics

Introduction: My name is Greg Kuvalis, I am a witty, spotless, beautiful, charming, delightful, thankful, beautiful person who loves writing and wants to share my knowledge and understanding with you.