'http post request + response from localhost in python

Many questions regarding http post requests, but I can't make a complete example running.

$ tree
.
└── src
    └── main.py # <----- this is the file I want to send data to
$ cat src/main.py
from typing import Dict, List
class Handler: # <----- (Probably should inherit from some class ?!)
    def post(self, data: Dict[str, int]) -> List[str]:
        return "+++".join([k for k in data])
$ python -m http.server 8001

Now I try to send data (from some other terminal)

$ cat send_something.py
import requests
x = requests.post("http://localhost:8001/src/main.py", data={"name": 700, "id": 99})
print(x)

And I get a 501 response which means I'm doing something wrong:

$ python send_something.py
<Response [501]>

On the localhost server I do see the post request, but with an error message:

127.0.0.1 - - [20/Apr/2022 09:29:22] code 501, message Unsupported method ('POST')
127.0.0.1 - - [20/Apr/2022 09:29:22] "POST /src/main.py HTTP/1.1" 501 -

Any help is very much appreciated, thanks.



Solution 1:[1]

Turns out I was missing many things. Here is the server code. It will receive json data and tweak it a bit as proof of concept.

import json

from typing import List

from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler

from attrs import asdict
from attrs import define

HOST = "127.0.0.1"
PORT = 8027 # <----- nailed it in the 27th try :)

@define
class Entry:

    name: str
    some_list: List[int]

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        
        # read incoming sent data
        data = self.rfile.read(self._sent_data_size)
        
        # do something with it ...
        response = self._process(data.decode("utf-8"))

        # perpare the (json) response
        jsonbytes = self._prepare_json_response(response)
                    
        # send the (json) response back ...
        self.wfile.write(jsonbytes)

    def _process(self, data: str) -> List[Entry]:
        return [
            Entry("employee"+str(i), [d["id"], d["salary"]])
            for i, d in enumerate(json.loads(data))
        ]

    def _prepare_json_response(self, response: List[Entry]) -> bytes:
        self.send_response(200)
        self.send_header("Content-type", "application/json")
        self.end_headers()
        jsonstr = json.dumps(
            response,
            indent=4,
            default=asdict
        )
        return jsonstr.encode()

    @property
    def _sent_data_size(self) -> int:
        return int(self.headers.get("Content-Length"))

server = HTTPServer((HOST, PORT), Handler)
server.serve_forever()
server.serve_close()

Here is the client code:

import requests

with open("input.json") as fl:
    data = json.load(fl)

x = requests.post("http://localhost:8027", json=data)
print(x.json())

The server is started, then the client sends the json data (from another terminal). the client receives the tweaked json properly and that's the happy end.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 OrenIshShalom