Python: post JSON data containing a datetime object with requests to flask



Spoiler: My main point in this post is not given away by the title. But first things first: What are all those words? <span id="more-4316"></span> * *Flask* is a Microframework for web applications often used for REST(-like) APIs. * *requests* is simply the best library to make HTTP requests there is. * *JSON* (JavaScript Object Notation) is a file format I prefer to XML in almost all of the case. * And finally *POST* is a HTTP verb often used in the context of REST to create new entry in a database. In Flask one can simply call `request.get_json()` if `POST`ed content is encoded in JSON. On the client side of things, one can query such a `POST` endpoint for example with the following shell command: ```bash curl -X POST https://example.com/ -d @some-file.json --header 'Content-Type: application/json' ``` The requests library has the `post` function which accepts data through the `json` kwarg. The library then takes care of a few things (like setting the content type for example): ```python some_data = {'foo': 123} requests.post('https://example.com/api', json=some_data) ``` All dandy so far. But things break when the `some_data` contains a `datetime.datetime` object. You will get the well-googled exception `TypeError: datetime.datetime(1985, 1, 26, 0, 0, 0) is not JSON serializable`. The behavior is exactly the same as if you would call `json.dumps` on such data. Of course there is a way to tell `dumps` how to encode this in a sane way (copying & pasting from StackOverflow here): ```python from datetime import datetime import json class DateTimeEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, datetime): return o.isoformat() return json.JSONEncoder.default(self, o) json.dumps({'foo': datetime(1985, 1, 26, 0, 0, 0)}, cls=DateTimeEncoder) ``` outputs `{"foo": "1985-01-26T00:00:00"}` which looks perfect. The naive "enterprise software engineering" way would now of course be to make `requests.post` accept a similar argument as `cls` and pass that to the `json.dumps` call that probably is buried somewhere deep in requests. There also is an issue on github requesting such a feature ((https://github.com/requests/requests/issues/3947)). But the developer of the library politely asked the OP to `dumps` himself. And I really like that! It saves the requests library from bloating away and I strongly think more developers should reason like this more often. All right. You got it. That was the point. You can go now. Oh you landed here because of a google search for the title? Here you go: ```python import json import requests class DateTimeEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, datetime): return o.isoformat() return json.JSONEncoder.default(self, o) r = requests.post( 'https://example.com/api', data=json.dumps(out, cls=DateTimeEncoder), headers={'Content-type': 'application/json'} ) ```

Tags: - - -

4 Replies to “Python: post JSON data containing a datetime object with requests to flask”

  1. LC, I think it is correct as it is: did you do `import datetime` instead of `from datetime import datetime` maybe?
  2. Having read your blog, you obviously know what you are talking about. I'm sure visiting my page <a href="https://www.captiveinsurancetimes.com/citimes/issue.php?issuelink=http://87n.de/flyingstar/flughafentransfer-frankfurt-bingen" rel="nofollow ugc">87N</a> about Airport Transfer will be worth your time!
  3. The way you put together the information on your posts is commendable. I would highly recommend this site. You might also want to check my page <a href="http://fd61.s6.domainkunden.de/cgi-bin/trackclicks.asp?id=7&amp;cct=209&amp;5779=962309&amp;url=http://qn6.de/" rel="nofollow ugc">QN6</a> for some noteworthy inputs about Thai-Massage.

Leave a Reply

Your email address will not be published. Required fields are marked *