Skip to content

Commit

Permalink
Accept Request(json=...) and provide Response.json().
Browse files Browse the repository at this point in the history
  • Loading branch information
nmlorg committed Sep 8, 2024
1 parent dc0878f commit 350d703
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 8 deletions.
5 changes: 3 additions & 2 deletions nh2/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ def __init__(self, host, port):

self.streams = {}

def request(self, method, path, *, headers=(), body=None):
def request(self, method, path, *, headers=(), body=None, json=None): # pylint: disable=too-many-arguments
"""Send a method request for path."""

return self.send(nh2.rex.Request(method, self.host, path, headers=headers, body=body))
return self.send(
nh2.rex.Request(method, self.host, path, headers=headers, body=body, json=json))

def send(self, request):
"""Send the given Request."""
Expand Down
14 changes: 13 additions & 1 deletion nh2/rex.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""HTTP/2 requests and responses."""

import json as _json


class ContentType:
"""A structured view of the content-type header."""
Expand All @@ -25,7 +27,7 @@ def __str__(self):
class Request:
"""An HTTP/2 request."""

def __init__(self, method, host, path, *, headers=(), body=None): # pylint: disable=too-many-arguments
def __init__(self, method, host, path, *, headers=(), body=None, json=None): # pylint: disable=too-many-arguments
self.method = method
self.host = host
self.path = path
Expand All @@ -37,6 +39,11 @@ def __init__(self, method, host, path, *, headers=(), body=None): # pylint: dis
}
self.headers.update(headers)
self.contenttype = ContentType(self.headers.get('content-type', ''))
if json is not None:
assert not body
assert self.contenttype.mediatype is None
self.contenttype = ContentType('application/json')
body = _json.dumps(json, separators=(',', ':'))
if body and isinstance(body, str):
assert self.contenttype.charset is None
if self.contenttype.mediatype is None:
Expand All @@ -57,3 +64,8 @@ def __init__(self, request, headers, body):
self.status = int(headers[':status'])
self.contenttype = ContentType(headers.get('content-type', ''))
self.body = body

def json(self):
"""Parse (and return) self.body as a JSON object."""

return _json.loads(self.body)
8 changes: 3 additions & 5 deletions nh2/test_connection.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Tests for nh2.connection."""

import json

import nh2.connection
import nh2.rex

Expand All @@ -19,18 +17,18 @@ def test_simple():
assert len(responses) == 1
assert responses[0].status == 200
assert responses[0].headers['content-type'] == 'application/json'
response = json.loads(responses[0].body)
response = responses[0].json()
assert response['args'] == {'a': 'b'}

conn.request('POST', '/post', body='{"c": "d"}')
conn.request('POST', '/post', json={'c': 'd'})
responses = None
while not responses:
responses = conn.read()
assert not conn.streams
assert len(responses) == 1
assert responses[0].status == 200
assert responses[0].headers['content-type'] == 'application/json'
response = json.loads(responses[0].body)
response = responses[0].json()
assert response['json'] == {'c': 'd'}
finally:
conn.close()
Expand Down
17 changes: 17 additions & 0 deletions nh2/test_rex.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ def test_request_simple():
assert request.body == b'\xe2\x80\xa2'


def test_request_json():
"""Verify JSON-related logic."""

request = nh2.rex.Request('PUT', 'example.com', '/test', json={'a': '\u2022'})
assert request.contenttype.mediatype == 'application/json'
assert request.body == b'{"a":"\\u2022"}'


def test_response_simple():
"""Basic Response functionality."""

Expand All @@ -72,3 +80,12 @@ def test_response_simple():
assert response.contenttype.charset is None
assert response.contenttype.boundary is None
assert response.body == b''


def test_response_json():
"""Verify JSON-related logic."""

request = nh2.rex.Request('PUT', 'example.com', '/test')
response = nh2.rex.Response(request, {':status': '200'}, b'{"a": "\\u2022 \xe2\x80\xa2"}')
assert response.body == b'{"a": "\\u2022 \xe2\x80\xa2"}'
assert response.json() == {'a': '\u2022 \u2022'}

0 comments on commit 350d703

Please sign in to comment.