How to Return a JSON Response in Django
Tags: django, python, tutorial
Published: 2020-11-09 08:30:42

## What is JSON?

JSON stands for JavaScript Object Notation and is a common and lightweight data format returned from APIs. One of the main benefits of JSON is its easy readability for developers and workability using JavaScript. 

```json
{ 
    "name":"John", 
    "age":30, 
    "car":null 
}
```

## Protecting API keys

A common use case as to why we might want to return a JSON response in Django is to protect API keys. Client-side JavaScript is directly editable in the developer tools, while code on the server isn't accessible to the client.

Malicious people may steal your API key and start using the service under your account, so you will be charged for all the API usage, ending up with hundreds or thousands of lost dollars depending on the usage volume. 

## Returning a JSON Response from an API

Django provides a built-in class JsonResponse that makes returning JSON easy.  By default, the JsonResponse class sets a Content-Type header of application/json. 

Let's make an API call to the [CocktailDB API](https://www.thecocktaildb.com/) that will return a list of cocktails and their ingredients to pass on as a JsonResponse to our frontend. 

```python
# views.py
import requests
from django.http import JsonResponse

# In production, this should be set as an environment variable
API_KEY = 1

def cocktail_list(request):
    res = requests.get(f"https://www.thecocktaildb.com/api/json/v1/{ API_KEY }/search.php?s=margarita")
    return JsonResponse(res.json())
```

First, we import the requests library to make an HTTP GET request to the CoctailDB endpoint to get a list of all the margarita drinks. If you don't have requests already installed, you can install it by running pip install requests. Then we import the JsonResponse class to return the margaritas as JSON.

We call .json() on the response, we get back to convert it into a JSON object and pass that to our JsonResponse(), which will return it to our client.

We can verify that we have a list of margaritas in JSON by wiring up the view in our urls.py and accessing the URL in our browser. You should see a list of JSON objects.

By default, the first parameter in the JsonResponse class is *data* that accepts an instance of dict.  If you pass data that isn't a dictionary, you will have to set the safe parameter to False.

Let's say you want to return a list of dictionaries. Since the list isn't an instance of dict, we will have to set safe=False.

```json
[
  { 
    "name":"John", 
    "age":30, 
    "car":null 
  },
  { 
    "name":"Joel", 
    "age":33, 
    "car":true 
  }
]
```
```python
return JsonResponse(data, safe=False)
```

## Returning a JSON response from a Django Model.

To return a queryset of python object as JSON, we first have to convert it into a Python dictionary. The process of converting one data type to another is called serialization.

```python
# views.py
from django.core.serializers import serialize
from django.http import HttpResponse
from .models import Post

def django_models_json(request):
    qs = Post.objects.all()
    data = serialize("json", qs, fields=('title', 'content'))
    return HttpResponse(data, content_type="application/json")
```

We import the serialize function. This function accepts the following parameters: format, queryset, and an optional fields parameter.

In the example, above our format is "json". Our queryset is qs, which are all the posts objects in the database, and we specified only to return the title and content fields from the model.

Why did I use an HttpResponse here instead of JsonResponse? The JsonResponse class takes a second parameter encoder, which is set to DjangoJSONEncoder by default. This encoder converts our data to JSON. So if we pass JSON to our JsonResponse class, it will encode it again, causing our JSON output to contain backslashes due to double serialization.

Conversely, the HttpResponse class does not have an encoder. So when we pass our already serialized JSON to it, it does not serialize it again. 

If we wire up the view and test it out in the browser, we will see our model objects returned to us in JSON format.

If you would like to return a JSON response of a single model object, we would do it like this:

```python
# views.py
from django.core.serializers import serialize
from django.http import HttpResponse
from .models import Post

def django_models_json(request):
    obj = Post.objects.first()
    data = serialize("json", [obj], fields=('title', 'content'))
    return HttpResponse(data, content_type="application/json")
```

Instead of passing in a queryset, we pass in a single object wrapped in a list so that the output will look like this:

```json
[
  { 
    "title":"Super Cool Title",  
    "content":"Some really cool content" 
  }
]
```
The object doesn't have to be wrapped in a list. If we passed the object not wrapped in a list, we would get an output like this:

```json
{ 
    "title":"Super Cool Title",  
    "content":"Some really cool content" 
}
```

I hope you guys enjoyed the tutorial and found it useful. If you have any questions, let me know in the comments, and I will try my best to answer them.

For more tutorials like this one, check out my blog [EngineerToDeveloper]().