Simple Python server to process GET and POST requests with JSON
Asked Answered
S

3

12

I'm trying to create a simple Python server in order to test my frontend. It should be able to handle GET and POST requests. The data should be always in JSON format until they are translated to HTTP request/response. A script with corresponding name should be called to handle each request.

server.py

#!/usr/bin/env python

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import SocketServer
import json
import urlparse
import subprocess

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()
        parsed_path = urlparse.urlparse(self.path)
        request_id = parsed_path.path
        response = subprocess.check_output(["python", request_id])
        self.wfile.write(json.dumps(response))

    def do_POST(self):
        self._set_headers()
        parsed_path = urlparse.urlparse(self.path)
        request_id = parsed_path.path
        response = subprocess.check_output(["python", request_id])
        self.wfile.write(json.dumps(response))

    def do_HEAD(self):
        self._set_headers()

def run(server_class=HTTPServer, handler_class=S, port=8000):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print 'Starting httpd...'
    httpd.serve_forever()

if __name__ == "__main__":
    from sys import argv

    if len(argv) == 2:
        run(port=int(argv[1]))
    else:
        run()

Example of testscript.py for handling requests, which in this case just returns a JSON object.

#!/usr/bin/env python
return {'4': 5, '6': 7}

The server should for example return {'4': 5, '6': 7} for a response in format http://www.domainname.com:8000/testscript.

My problem is that I can't figure out how to pass variables in between and I need help to make it work.

Snake answered 12/11, 2015 at 1:15 Comment(3)
Where do you want to pass variables? to server or between definitions in classesAkers
In this question mainly return variables between python scripts. But ideally I would like to pass json between Httprequest -> server -> handler script -> server -> http responseSnake
Have a look at this related post which provides a working HTTP server providing POST support for Python2.7 #31371666Oidea
A
10

Here is an example of server client in python. I am using bottle library to handle requests to server and create server.

Server Code

import subprocess
from bottle import run, post, request, response, get, route

@route('/<path>',method = 'POST')
def process(path):
    return subprocess.check_output(['python',path+'.py'],shell=True)

run(host='localhost', port=8080, debug=True)

It starts server on localhost:8080. You can pass file name you want to run run. Make sure that file is in the same path for above code to work or change path appropriately to run from different directory. Path corresponds to file name and it invokes process function when any path is given. If it cannot find file it raises exception Internal server error. You can call scripts from subdirectories too.

Client Code

import httplib, subprocess

c = httplib.HTTPConnection('localhost', 8080)
c.request('POST', '/return', '{}')
doc = c.getresponse().read()
print doc

It invokes a POST request to localhost:8080/return

return.py

def func():
    print {'4': 5, '6': 7}
func()

Make sure you print your output response as we are using subprocess.check_output() as it catches only print statements.

Use Popen in subprocess to open a continuous connection instead of check_output to pass arguments to function in server

Check this documentation on how to extract POST or GET values

Akers answered 12/11, 2015 at 12:6 Comment(5)
@route('/<path>',method = 'GET') def process(path): response.content_type = 'text/html' return 'Hello World GET' is still giving me an internal server error and there's no way to debug it. your server runs on port 800 but there is no sign of activity, while the other server was active.Snake
Can you elaborate your problem? GET method you posted doesn't give any errors on my server and server runs on 8080 not 800Akers
Yes, it worked fine from localhost and I only had problems accessing it from outside. Changing host='localhost' to host='0.0.0.0' solved my problem and I can now access from external sources. All is good now.Snake
yes it's in documentation changing it to 0.0.0.0 will make server listen on all addressesAkers
I found out through terminal, but good point with the documentationSnake
I
6

I use this:

https://gist.github.com/earonesty/ab07b4c0fea2c226e75b3d538cc0dc55

from apiserve import ApiServer, ApiRoute

class MyServer(ApiServer): 
        @ApiRoute("/popup")
        def addbar(req):
            return {"boo":req["bar"]+1}

        @ApiRoute("/baz")
        def justret(req):
            if req:
                 raise ApiError(501,"no data in for baz")
            return {"obj":1}

MyServer("127.0.0.1",8000).serve_forever()

That particular wrapper allows you to easily listen on port 0 (random high port) which some frameworks obfuscate. It automatically handles GET/POST requests for all routes, and it merges in URI arguments with the top level JSON object arguments. Which is good enough for me in most cases.

It's a lot lighter weight than most frameworks. Test cases in the gist show better how it works.

Indemnification answered 27/11, 2017 at 22:28 Comment(0)
H
2

Just one more option for those who prefer Flask. This framework is very popular and quite well documented.

Create file wsgi.py (name is important to not to have a deal with environment variables later) with the content like the following:

from flask import Flask, request

app = Flask(__name__)


@app.route('/object/<path_param>')
def get_object(path_param):
    return {
        'path_param': path_param,
        'query_param': request.args.get('q', "'q' not set"),
    }


if __name__ == '__main__':
    app.run()

Run server in terminal like: flask run --reload --host "127.0.0.1" --port 7777

Send queries like: curl -i http://localhost:7777/object/something?q=q

Also don't forget to do pip3 install flask to make this work.

Heyerdahl answered 23/9, 2021 at 3:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.