monadoboi
monadoboi

Reputation: 1811

Returning JSON using a GET request from server

I have a simple server from here, and when the GET function is called, I would like it to return a JSON file, as show in the relevant code snippet below:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import json

class S(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()

    def do_GET(self):
        self._set_headers()
        with open('test.json') as data_file:    
            data = json.load(data_file)
        self.wfile.write(data)

My json file:

{"foo": "bar", "boo": "far"}

The application requesting the file (client.py):

import requests
import json

r = requests.get('http://localhost:8080')
print r.json()

However, when trying to run client.py I get the following error:

ValueError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

Am I correctly loading the test.json file in the do_GET function?

Thanks for your help :)

Upvotes: 3

Views: 10490

Answers (3)

George
George

Reputation: 21

To be able to catch a JSON response from http.server using requests library, another words to use response.json() you should make the following on the server side:

from http.server import BaseHTTPRequestHandler
import json


class GetHandler(BaseHTTPRequestHandler):

def do_GET(self):
    json_data = {'token': 'qfrwefewrtweygds--fefef==wef'}
    json_to_pass = json.dumps(json_data)
    self.send_response(code=200, message='here is your token')
    self.send_header(keyword='Content-type', value='application/json')
    self.end_headers()
    self.wfile.write(json_to_pass.encode('utf-8'))

This thing worked for me.

Upvotes: 2

zwer
zwer

Reputation: 25779

Let's make it a bit better for an answer :)

The whole problem is that you're parsing test.json on in your server and then print string representation of it to your client. Consider a simple JSON like:

{"foo": "bar", "baz": "far"}

When you load and parse it as JSON, and then print it, you'll get a string representation of a Python dict it was parsed into, which, while very similar, is no longer JSON:

import json

data = '{"foo": "bar", "baz": "far"}'  # we'll use a string instead of a file for testing
parsed = json.loads(data)
print(parsed)  # equivalent to printing `str(parsed)`

Which will yield (on Python 2.x, on Python 3.x there are no unicode markings but the rest is the same):

{u'foo': u'bar', u'baz': u'far'}

And that's how your data gets sent from the server - as a string representation of a Python dict. Notice, for example, those u prefixes denoting a unicode string? Those are the culprits (in this instance).

Now, if you were to load it back and try to parse it as JSON:

import json 

data = "{u'foo': u'bar', u'baz': u'far'}"
parsed = json.loads(data)

You would get your ValueError: Expecting property name: line 1 column 2 (char 1) error.

To avoid that, don't parse your JSON if you want to send it over to your client, so a simple:

with open('test.json') as data_file:
    self.wfile.write(data_file.read())

should suffice. In case you need to do some pre-processing to your JSON, then you need to serialize it back to JSON before sending, e.g.:

with open('test.json') as data_file:    
    data = json.load(data_file)
    data["boo"] = "baz"
    self.wfile.write(json.dumps(data))

Upvotes: 5

ewwink
ewwink

Reputation: 19154

json.load is not needed replace it with data_file.read()

def do_GET(self):
    self._set_headers()
    with open('test.json') as data_file:    
        data = data_file.read()
    self.wfile.write(data)

Upvotes: 2

Related Questions