Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active March 22, 2024 09:51
  • Star 96 You must be signed in to star a gist
  • Fork 28 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save nitaku/10d0662536f37a087e1b to your computer and use it in GitHub Desktop.
Minimal JSON HTTP server in python

A minimal HTTP server in python. It sends a JSON Hello World for GET requests, and echoes back JSON for POST requests.

python server.py 8009
Starting httpd on port 8009...
curl http://localhost:8009
{"received": "ok", "hello": "world"}
curl --data "{\"this\":\"is a test\"}" --header "Content-Type: application/json" http://localhost:8009
{"this": "is a test", "received": "ok"}

Adapted from this Gist, with the addition of code for reading the request body taken from this article.

Please be careful when using a server like this on production environments, because it lacks many important features (threading to name one). You can consult the python documentation about BaseHTTPServer to learn something useful to improve it.

If you are on Ubuntu, you can install this code as a service with an init script (hopefully, with some modifications that make it actually do something useful). Just modify the include server.conf to suit your needs (possibly renaming it and redirecting output to some log files instead of /dev/null), and copy it into /etc/init/. You can then start/stop/restart the server with the usual service command:

sudo service server start
description "Example JSON HTTP server"
author "nitaku - matteo.abrate@gmail.com"
start on started mountall
stop on shutdown
respawn
respawn limit 99 5
script
exec sudo -u www-data /usr/bin/python /data/examples/python_minimal_http/server.py 8009 >> /dev/null 2>> /dev/null
end script
post-start script
end script
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import SocketServer
import json
import cgi
class Server(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
def do_HEAD(self):
self._set_headers()
# GET sends back a Hello world message
def do_GET(self):
self._set_headers()
self.wfile.write(json.dumps({'hello': 'world', 'received': 'ok'}))
# POST echoes the message adding a JSON field
def do_POST(self):
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
# refuse to receive non-json content
if ctype != 'application/json':
self.send_response(400)
self.end_headers()
return
# read the message and convert it into a python dictionary
length = int(self.headers.getheader('content-length'))
message = json.loads(self.rfile.read(length))
# add a property to the object, just to mess with data
message['received'] = 'ok'
# send the message back
self._set_headers()
self.wfile.write(json.dumps(message))
def run(server_class=HTTPServer, handler_class=Server, port=8008):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print 'Starting httpd on port %d...' % port
httpd.serve_forever()
if __name__ == "__main__":
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
@saiprasad2210
Copy link

How to expand this to say a custom get request.
curl http://localhost:8009/get_all_configs

@gitvipin
Copy link

@mfickett : We also need to convert response to bytes as following. Without it we get error , TypeError: a bytes-like object is required, not 'str'

    def do_GET(self):
        self._set_headers()
        response = json.dumps({'hello': 'world', 'received': 'ok'})
        response = bytes(response, 'utf-8')
        self.wfile.write(response)

@gitvipin
Copy link

@saiprasad2210 : You get access to path as self.path inside handler. You can process it as you like. An example is here : https://github.com/gitvipin/sql30/blob/master/sql30/api.py#L45

@alexzanderr
Copy link

in do_GET function:
this line is missing encoding to bytes object

self.wfile.write(json.dumps({'hello': 'world', 'received': 'ok'}))

should be:

self.wfile.write(json.dumps({'hello': 'world', 'received': 'ok'}).encode('utf-8'))

@janzheng
Copy link

janzheng commented Jan 9, 2022

self.wfile.write(json.dumps({'hello': 'world', 'received': 'ok'}).encode('utf-8')) is incorrect — you have to encode the json itself, not the output. So this should actually be:
self.wfile.write(json.dumps({'hello': 'world', 'received': 'ok'}).encode('utf-8'))

@NateFerrero
Copy link

@janzheng your second example is the same code as your first if I'm seeing correctly

@janzheng
Copy link

self.wfile.write(json.dumps({'hello'

somehow I also missed the comment on Mar 24 by Alex. I'm going to excuse myself from this conversation hahah...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment