Skip to content

Commit

Permalink
Merge pull request #46 from dapper91/dev
Browse files Browse the repository at this point in the history
- request and response loggers separated.
- alternative json-rpc content types support added.
  • Loading branch information
dapper91 authored Nov 3, 2021
2 parents cbf5c9e + 00651db commit bd63b72
Show file tree
Hide file tree
Showing 18 changed files with 58 additions and 35 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Changelog
=========

1.3.5 (2021-11-03)
------------------

- request and response loggers separated.
- alternative json-rpc content types support added.


1.3.4 (2021-09-11)
------------------
Expand Down
4 changes: 2 additions & 2 deletions docs/source/pjrpc/extending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ an JSON-RPC server implementation based on :py:mod:`http.server` standard python
class JsonRpcHandler(http.server.BaseHTTPRequestHandler):
def do_POST(self):
content_type = self.headers.get('Content-Type')
if content_type != 'application/json':
if content_type not in pjrpc.common.JSONRPC_REQUEST_CONTENT_TYPES:
self.send_response(http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE)
return
Expand All @@ -35,7 +35,7 @@ an JSON-RPC server implementation based on :py:mod:`http.server` standard python
self.send_response(http.HTTPStatus.OK)
else:
self.send_response(http.HTTPStatus.OK)
self.send_header("Content-type", "application/json")
self.send_header("Content-type", pjrpc.common.DEFAULT_CONTENT_TYPE)
self.end_headers()
self.wfile.write(response_text.encode())
Expand Down
4 changes: 2 additions & 2 deletions examples/httpserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def do_POST(self):
"""

content_type = self.headers.get('Content-Type')
if content_type != 'application/json':
if content_type not in pjrpc.common.REQUEST_CONTENT_TYPES:
self.send_response(http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE)
return

Expand All @@ -33,7 +33,7 @@ def do_POST(self):
self.send_response(http.HTTPStatus.OK)
else:
self.send_response(http.HTTPStatus.OK)
self.send_header("Content-type", "application/json")
self.send_header("Content-type", pjrpc.common.DEFAULT_CONTENT_TYPE)
self.end_headers()

self.wfile.write(response_text.encode())
Expand Down
2 changes: 1 addition & 1 deletion pjrpc/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
__description__ = 'Extensible JSON-RPC library'
__url__ = 'https://github.com/dapper91/pjrpc'

__version__ = '1.3.4'
__version__ = '1.3.5'

__author__ = 'Dmitry Pershin'
__email__ = '[email protected]'
Expand Down
6 changes: 3 additions & 3 deletions pjrpc/client/backend/aio_pika.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ async def _on_result_message(self, message: aio_pika.IncomingMessage) -> None:
logger.warning("unexpected or outdated message received: %r", message)
return

if message.content_type != 'application/json':
if message.content_type not in pjrpc.common.RESPONSE_CONTENT_TYPES:
future.set_exception(
pjrpc.exc.DeserializationError(f"unexpected response content type: {message.content_type}"),
)
Expand All @@ -116,7 +116,7 @@ async def _request(self, request_text: str, is_notification: bool = False, **kwa
message = aio_pika.message.Message(
body=request_text.encode(),
content_encoding='utf8',
content_type='application/json',
content_type=pjrpc.common.DEFAULT_CONTENT_TYPE,
**kwargs,
)
exchange = self._exchange or channel.default_exchange
Expand All @@ -139,7 +139,7 @@ async def _request(self, request_text: str, is_notification: bool = False, **kwa
correlation_id=request_id,
reply_to=result_queue.name,
content_encoding='utf8',
content_type='application/json',
content_type=pjrpc.common.DEFAULT_CONTENT_TYPE,
**kwargs,
)

Expand Down
4 changes: 2 additions & 2 deletions pjrpc/client/backend/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async def _request(self, request_text: str, is_notification: bool = False, **kwa
"""

kwargs = {
'headers': {'Content-Type': 'application/json'},
'headers': {'Content-Type': pjrpc.common.DEFAULT_CONTENT_TYPE},
**kwargs,
}

Expand All @@ -46,7 +46,7 @@ async def _request(self, request_text: str, is_notification: bool = False, **kwa
return None

content_type = resp.headers.get('Content-Type', '')
if response_text and content_type.split(';')[0] != 'application/json':
if response_text and content_type.split(';')[0] not in pjrpc.common.RESPONSE_CONTENT_TYPES:
raise pjrpc.exc.DeserializationError(f"unexpected response content type: {content_type}")

return response_text
Expand Down
8 changes: 4 additions & 4 deletions pjrpc/client/backend/httpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A
"""

kwargs = {
'headers': {'Content-Type': 'application/json'},
'headers': {'Content-Type': pjrpc.common.DEFAULT_CONTENT_TYPE},
**kwargs,
}

Expand All @@ -40,7 +40,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A

response_text = resp.text
content_type = resp.headers.get('Content-Type', '')
if response_text and content_type.split(';')[0] != 'application/json':
if response_text and content_type.split(';')[0] not in pjrpc.common.RESPONSE_CONTENT_TYPES:
raise pjrpc.exc.DeserializationError(f"unexpected response content type: {content_type}")

return response_text
Expand Down Expand Up @@ -84,7 +84,7 @@ async def _request(self, request_text: str, is_notification: bool = False, **kwa
"""

kwargs = {
'headers': {'Content-Type': 'application/json'},
'headers': {'Content-Type': pjrpc.common.DEFAULT_CONTENT_TYPE},
**kwargs,
}

Expand All @@ -100,7 +100,7 @@ async def _request(self, request_text: str, is_notification: bool = False, **kwa
return None

content_type = resp.headers.get('Content-Type', '')
if response_text and content_type.split(';')[0] != 'application/json':
if response_text and content_type.split(';')[0] not in pjrpc.common.RESPONSE_CONTENT_TYPES:
raise pjrpc.exc.DeserializationError(f"unexpected response content type: {content_type}")

return response_text
Expand Down
6 changes: 3 additions & 3 deletions pjrpc/client/backend/kombu.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A
request_text,
exchange=self._exchange or '',
routing_key=self._routing_key,
content_type='application/json',
content_type=pjrpc.common.DEFAULT_CONTENT_TYPE,
**kwargs,
)
return None
Expand All @@ -93,7 +93,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A
routing_key=self._routing_key,
reply_to=result_queue.name,
correlation_id=request_id,
content_type='application/json',
content_type=pjrpc.common.DEFAULT_CONTENT_TYPE,
**kwargs,
)

Expand All @@ -107,7 +107,7 @@ def on_response(message: kombu.Message) -> None:
logger.warning("unexpected message received: %r", message)
return

if message.content_type != 'application/json':
if message.content_type not in pjrpc.common.RESPONSE_CONTENT_TYPES:
raise pjrpc.exc.DeserializationError(f"unexpected response content type: {message.content_type}")
else:
response = message.body
Expand Down
4 changes: 2 additions & 2 deletions pjrpc/client/backend/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A
"""

kwargs = {
'headers': {'Content-Type': 'application/json'},
'headers': {'Content-Type': pjrpc.common.DEFAULT_CONTENT_TYPE},
**kwargs,
}

Expand All @@ -40,7 +40,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A

response_text = resp.text
content_type = resp.headers.get('Content-Type', '')
if response_text and content_type.split(';')[0] != 'application/json':
if response_text and content_type.split(';')[0] not in pjrpc.common.RESPONSE_CONTENT_TYPES:
raise pjrpc.exc.DeserializationError(f"unexpected response content type: {content_type}")

return response_text
Expand Down
17 changes: 17 additions & 0 deletions pjrpc/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@
from .common import UNSET, UnsetType, JSONEncoder
from .v20 import Request, Response, BatchRequest, BatchResponse

DEFAULT_CONTENT_TYPE = 'application/json'
REQUEST_CONTENT_TYPES = ('application/json', 'application/json-rpc', 'application/jsonrequest')
RESPONSE_CONTENT_TYPES = ('application/json', 'application/json-rpc')


def set_default_content_type(content_type: str) -> None:
"""
Sets default json-rpc client request / json-rpc server response content type.
"""

global DEFAULT_CONTENT_TYPE

DEFAULT_CONTENT_TYPE = content_type


__all__ = [
'Request',
Expand All @@ -16,5 +30,8 @@
'UNSET',
'UnsetType',
'JSONEncoder',
'DEFAULT_CONTENT_TYPE',
'REQUEST_CONTENT_TYPES',
'RESPONSE_CONTENT_TYPES',
'generators',
]
8 changes: 4 additions & 4 deletions pjrpc/server/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def dispatch(self, request_text: str, context: Optional[Any] = None) -> Optional
:return: response text representation
"""

logger.debug("request received: %s", request_text)
logger.getChild('request').debug("request received: %s", request_text)

try:
request_json = self._json_loader(request_text, cls=self._json_decoder)
Expand Down Expand Up @@ -371,7 +371,7 @@ def dispatch(self, request_text: str, context: Optional[Any] = None) -> Optional

if response is not UNSET:
response_text = self._json_dumper(response.to_json(), cls=self._json_encoder)
logger.debug("response sent: %s", response_text)
logger.getChild('response').debug("response sent: %s", response_text)

return response_text

Expand Down Expand Up @@ -442,7 +442,7 @@ async def dispatch(self, request_text: str, context: Optional[Any] = None) -> Op
:return: response text representation
"""

logger.debug("request received: %s", request_text)
logger.getChild('request').debug("request received: %s", request_text)

try:
request_json = self._json_loader(request_text, cls=self._json_decoder)
Expand Down Expand Up @@ -472,7 +472,7 @@ async def dispatch(self, request_text: str, context: Optional[Any] = None) -> Op

if response is not UNSET:
response_text = self._json_dumper(response.to_json(), cls=self._json_encoder)
logger.debug("response sent: %s", response_text)
logger.getChild('response').debug("response sent: %s", response_text)

return response_text

Expand Down
2 changes: 1 addition & 1 deletion pjrpc/server/integration/aio_pika.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async def _rpc_handle(self, message: aio_pika.IncomingMessage) -> None:
body=response_text.encode(),
reply_to=reply_to,
correlation_id=message.correlation_id,
content_type='application/json',
content_type=pjrpc.common.DEFAULT_CONTENT_TYPE,
),
routing_key=reply_to,
)
Expand Down
2 changes: 1 addition & 1 deletion pjrpc/server/integration/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ async def _rpc_handle(self, http_request: web.Request, dispatcher: pjrpc.server.
:returns: :py:class:`aiohttp.web.Request`
"""

if http_request.content_type != 'application/json':
if http_request.content_type not in pjrpc.common.REQUEST_CONTENT_TYPES:
raise web.HTTPUnsupportedMediaType()

try:
Expand Down
4 changes: 2 additions & 2 deletions pjrpc/server/integration/django/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def _rpc_handle(self, request: HttpRequest) -> HttpResponse:
:returns: http response
"""

if request.content_type != 'application/json':
if request.content_type not in pjrpc.common.REQUEST_CONTENT_TYPES:
return HttpResponse(status=415)

try:
Expand All @@ -102,7 +102,7 @@ def _rpc_handle(self, request: HttpRequest) -> HttpResponse:
if response_text is None:
return HttpResponse()
else:
return HttpResponse(response_text, content_type='application/json')
return HttpResponse(response_text, content_type=pjrpc.common.DEFAULT_CONTENT_TYPE)


class JsonRPCSites(django.utils.functional.LazyObject):
Expand Down
4 changes: 2 additions & 2 deletions pjrpc/server/integration/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def _generate_spec(self) -> flask.Response:

return current_app.response_class(
json.dumps(schema, indent=2, cls=specs.JSONEncoder),
mimetype=current_app.config["JSONIFY_MIMETYPE"],
mimetype=pjrpc.common.DEFAULT_CONTENT_TYPE,
)

def _ui_index_page(self) -> flask.Response:
Expand Down Expand Up @@ -148,4 +148,4 @@ def _rpc_handle(self, dispatcher: pjrpc.server.Dispatcher) -> flask.Response:
if response_text is None:
return current_app.response_class()
else:
return current_app.response_class(response_text, mimetype=current_app.config["JSONIFY_MIMETYPE"])
return current_app.response_class(response_text, mimetype=pjrpc.common.DEFAULT_CONTENT_TYPE)
4 changes: 2 additions & 2 deletions pjrpc/server/integration/kombu.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def get_consumers(self, Consumer, channel) -> List[kombu.Consumer]:
Consumer(
queues=[self._rpc_queue],
on_message=self._rpc_handle,
accept={'application/json'},
accept={pjrpc.common.DEFAULT_CONTENT_TYPE},
prefetch_count=self._prefetch_count,
),
]
Expand All @@ -80,7 +80,7 @@ def _rpc_handle(self, message: kombu.Message) -> None:
response_text,
routing_key=reply_to,
correlation_id=message.properties.get('correlation_id'),
content_type='application/json',
content_type=pjrpc.common.DEFAULT_CONTENT_TYPE,
content_encoding='utf8',
**(self._publish_args or {})
)
Expand Down
4 changes: 2 additions & 2 deletions pjrpc/server/integration/starlette.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ async def _rpc_handle(self, http_request: Request, dispatcher: pjrpc.server.Asyn
:returns: :py:class:`aiohttp.web.Request`
"""

if http_request.headers['Content-Type'] != 'application/json':
if http_request.headers['Content-Type'] not in pjrpc.common.REQUEST_CONTENT_TYPES:
raise exceptions.HTTPException(415)

try:
Expand All @@ -145,4 +145,4 @@ async def _rpc_handle(self, http_request: Request, dispatcher: pjrpc.server.Asyn
if response_text is None:
return Response()
else:
return Response(content=response_text, media_type='application/json')
return Response(content=response_text, media_type=pjrpc.common.DEFAULT_CONTENT_TYPE)
4 changes: 2 additions & 2 deletions pjrpc/server/integration/werkzeug.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def _rpc_handle(self, request: werkzeug.Request) -> werkzeug.Response:
:returns: werkzeug response
"""

if request.content_type != 'application/json':
if request.content_type not in pjrpc.common.REQUEST_CONTENT_TYPES:
raise exceptions.UnsupportedMediaType()

try:
Expand All @@ -54,4 +54,4 @@ def _rpc_handle(self, request: werkzeug.Request) -> werkzeug.Response:
if response_text is None:
return werkzeug.Response()
else:
return werkzeug.Response(response_text, mimetype='application/json')
return werkzeug.Response(response_text, mimetype=pjrpc.common.DEFAULT_CONTENT_TYPE)

0 comments on commit bd63b72

Please sign in to comment.