librelist archives

« back to archive

Base Resource class to implement JSONTranslate middleware functionality?

Base Resource class to implement JSONTranslate middleware functionality?

From:
William Hayes
Date:
2015-10-05 @ 17:14
JSON conversion from request and to responses seems like a basic 
requirement - putting it in middleware and magically inserting new 
attributes on the Request object seems wrong to me.  

I’ve started a BaseResource class for JSON, but this is not really what I 
want. I’d prefer to override the Request object to add the JSON payload 
directly and provide an easy way to dump the response payload as JSON in 
resp.body.  Is this less magical? or does it make sense to just build this
into Falcon?  If the response Content-Type is application/json - 
automatically convert resp.body to JSON?

For now, I’m using the JSONTranslate middleware with some warnings in my 
code about what it is doing.  I like the Falcon approach, clean design and
fast processing very much - so I’m nit-picking not tearing apart.  It just
took me a bit to understand what is going on. 

import logging
import json

class JsonBaseResource(object):
    def __init__(self):
        self.logger = logging.getLogger('api.' + __name__)

    def get_json_payload(self, req):
        """Get JSON payload of request object body

        :param req: Falcon request object
        :return: JSON version of request object payload
        """
        return json.loads(req.stream.read().decode('utf-8'))

    def make_json_payload(self, resp, payload):
        """Create resp.body from payload data structure

        :param resp: Falcon response object
        :param payload: data structure to add to resp.body
        :return:
        """
        resp.body = json.dumps(payload)

Re: [falcon] Base Resource class to implement JSONTranslate middleware functionality?

From:
Ben Meyer
Date:
2015-10-05 @ 17:40
Question: how would you have it determine that the response content is
application/json?

I ask because projects I've been on in the past were bitten by this and
moving to Falcon solved the issue.
For instance, Pecan relies on (a) decorators, and (b) WebOb detection,
and can be a real PITA to get it to generate the response you want all
the time.

Are you just going to check the 'content-type' response header? (That
would seem the simpliest approach.) Or do something more?

$0.02

Ben

On 10/05/2015 01:14 PM, William Hayes wrote:
> JSON conversion from request and to responses seems like a basic
> requirement - putting it in middleware and magically inserting new
> attributes on the Request object seems wrong to me.  
>
> I’ve started a BaseResource class for JSON, but this is not really
> what I want. I’d prefer to override the Request object to add the JSON
> payload directly and provide an easy way to dump the response payload
> as JSON in resp.body.  Is this less magical? or does it make sense to
> just build this into Falcon?  If the response Content-Type is
> application/json - automatically convert resp.body to JSON?
>
> For now, I’m using the JSONTranslate middleware with some warnings in
> my code about what! it is do ing.  I like the Falcon approach, clean
> design and fast processing very much - so I’m nit-picking not tearing
> apart.  It just took me a bit to understand what is going on. 
> import logging
> import json
>
> class JsonBaseResource(object):
>     def __init__(self):
>         self.logger = logging.getLogger('api.' + __name__)
>
>     def get_json_payload(self, req):
>         """Get JSON payload of request object body :paramreq: Falcon request
> object :return: JSON version of request object payload """ return 
json.loads(req.stream.read().decode('utf-8'))
>
>     def make_json_payload(self, resp, payload):
>         """Create resp.body from payload data structure :paramresp: 
Falcon response object :parampayload: data structure to add to
> resp.body :return: """ resp.body = json.dumps(payload)
>
>

Re: [falcon] Base Resource class to implement JSONTranslate middleware functionality?

From:
William Hayes
Date:
2015-10-05 @ 17:55
That’s what I proposed (in a question) below.  I’m just getting to know 
Falcon and don’t know the history of it.  I have not built many REST API 
backends either so I defer to the expertise of the mailing list.

> On Oct 5, 2015, at 1:40 PM, Ben Meyer <ben.meyer@rackspace.com> wrote:
> 
> Question: how would you have it determine that the response content is 
application/json?
> 
> I ask because projects I've been on in the past were bitten by this and 
moving to Falcon solved the issue.
> For instance, Pecan relies on (a) decorators, and (b) WebOb detection, 
and can be a real PITA to get it to generate the response you want all the
time.
> 
> Are you just going to check the 'content-type' response header? (That 
would seem the simpliest approach.) Or do something more?
> 
> $0.02
> 
> Ben
> 
> On 10/05/2015 01:14 PM, William Hayes wrote:
>> JSON conversion from request and to responses seems like a basic 
requirement - putting it in middleware and magically inserting new 
attributes on the Request object seems wrong to me.  
>> 
>> I’ve started a BaseResource class for JSON, but this is not really what
I want. I’d prefer to override the Request object to add the JSON payload 
directly and provide an easy way to dump the response payload as JSON in 
resp.body.  Is this less magical? or does it make sense to just build this
into Falcon?  If the response Content-Type is application/json - 
automatically convert resp.body to JSON?
>> 
>> For now, I’m using the JSONTranslate middleware with some warnings in 
my code about what! it is do ing.  I like the Falcon approach, clean 
design and fast processing very much - so I’m nit-picking not tearing 
apart.  It just took me a bit to understand what is going on. 
>> import logging
>> import json
>> 
>> class JsonBaseResource(object):
>>     def __init__(self):
>>         self.logger = logging.getLogger('api.' + __name__)
>> 
>>     def get_json_payload(self, req):
>>         """Get JSON payload of request object body
>> 
>>         :param req: Falcon request object
>>         :return: JSON version of request object payload
>>         """
>>         return json.loads(req.stream.read().decode('utf-8'))
>> 
>>     def make_json_payload(self, resp, payload):
>>         """Create resp.body from payload data structure
>> 
>>         :param resp: Falcon response object
>>         :param payload: data structure to add to resp.body
>>         :return:
>>         """
>>         resp.body = json.dumps(payload)
>> 
>> 
> 

Re: [falcon] Base Resource class to implement JSONTranslate middleware functionality?

From:
Ben Meyer
Date:
2015-10-05 @ 19:17
I can think of two good approaches:

 1. (okay) Have something that looks at the response header's
    content-type and applies the json.dumps() appropriately
 2. (best) Add a json property (get/set) to the falcon.Response object
    so instead of "resp.body = json.dumps(content)" one can just do
    "resp.json = content" and to have the Response object jsonify the
    content and set content-type appropriately.

Personally I like #2 best, and would suggest the same be done on the
falcon.Request object to easily get a python dict of the json data from
the Request - e.g instead of doing "json_data = json.loads(req.content)"
one can just do "json_data = req.json()".

The biggest issue I ran into with Pecan+WebOb the WebOb detection for
what kind of content to send back. The decorator helped, but there were
still many instances that were problematic - especially if you had no
content and were trying to send back an empty body (204) response; it
just didn't like it (it wanted a 200 and a valid empty body JSON
document - "[]" - instead). So leave the freedom to the developer on how
to get there, and then document it well so devs know how to either avoid
it or use it, and don't force the same kind of response all the time -
e.g there's no reason to force a 200+empty json document when a 204 is a
more appropriate and desired response.

So, KISS principle.

$0.02

Ben

On 10/05/2015 01:55 PM, William Hayes wrote:
> That’s what I proposed (in a question) below.  I’m just getting to
> know Falcon and don’t know the history of it.  I have not built many
> REST API backends either so I defer to the expertise of the mailing list.
>
>> On Oct 5, 2015, at 1:40 PM, Ben Meyer <ben.meyer@rackspace.com
>> <mailto:ben.meyer@rackspace.com>> wrote:
>>
>> Question: how would you have it determine that the response content
>> is application/json?
>>
>> I ask because projects I've been on in the past were bitten by this
>> and moving to Falcon solved the issue.
>> For instance, Pecan relies on (a) decorators, and (b) WebOb
>> detection, and can be a real PITA to get it to generate the response
>> you want all the time.
>>
>> Are you just going to check the 'content-type' response header? (That
>> would seem the simpliest approach.) Or do something more?
>>
>> $0.02
>>
>> Ben
>>
>> On 10/05/2015 01:14 PM, William Hayes wrote:
>>> JSON conversion from request and to responses seems like a basic
>>> requirement - putting it in middleware and magically inserting new
>>> attributes on the Request object seems wrong to me.  
>>>
>>> I’ve started a BaseResource class for JSON, but this is not really
>>> what I want. I’d prefer to override the Request object to add the
>>> JSON payload directly and provide an easy way to dump the response
>>> payload as JSON in resp.body.  Is this less magical? or does it make
>>> sense to just build this into Falcon?  If the response Content-Type
>>> is application/json - automatically convert resp.body to JSON?
>>>
>>> For now, I’m using the JSONTranslate middleware with some warnings
>>> in my code about what! it is do ing.  I like the Falcon approach,
>>> clean design and fast processing very much - so I’m nit-picking not
>>> tearing apart.  It just took me a bit to understand what is going on. 
>>> import logging
>>> import json
>>>
>>> class JsonBaseResource(object):
>>>     def __init__(self):
>>>         self.logger = logging.getLogger('api.' + __name__)
>>>
>>>     def get_json_payload(self, req):
>>>         """Get JSON payload of request object body :paramreq: Falcon request
>>> object :return: JSON version of request object payload """ return 
json.loads(req.stream.read().decode('utf-8'))
>>>
>>>     def make_json_payload(self, resp, payload):
>>>         """Create resp.body from payload data structure :paramresp: 
Falcon response object :parampayload: data structure to add to
>>> resp.body :return: """ resp.body = json.dumps(payload)
>>>
>>>
>>
>

Re: [falcon] Base Resource class to implement JSONTranslate middleware functionality?

From:
Kurt Griffiths
Date:
2015-10-05 @ 21:08
You could certainly create custom Request and Response child classes that 
add properties or methods as needed. That sounds like a pretty good 
short-term solution while we work out how we want to do this natively in 
the framework. I’d love to get everyone’s thoughts on the relevant GH 
issue: https://github.com/falconry/falcon/issues/145.

-Kurt

From: <falcon@librelist.com<mailto:falcon@librelist.com>> on behalf of Ben Meyer
Reply-To: "falcon@librelist.com<mailto:falcon@librelist.com>"
Date: Monday, October 5, 2015 at 2:17 PM
To: "falcon@librelist.com<mailto:falcon@librelist.com>"
Subject: Re: [falcon] Base Resource class to implement JSONTranslate 
middleware functionality?

I can think of two good approaches:

  1.  (okay) Have something that looks at the response header's 
content-type and applies the json.dumps() appropriately
  2.  (best) Add a json property (get/set) to the falcon.Response object 
so instead of "resp.body = json.dumps(content)" one can just do "resp.json
= content" and to have the Response object jsonify the content and set 
content-type appropriately.

Personally I like #2 best, and would suggest the same be done on the 
falcon.Request object to easily get a python dict of the json data from 
the Request - e.g instead of doing "json_data = json.loads(req.content)" 
one can just do "json_data = req.json()".

The biggest issue I ran into with Pecan+WebOb the WebOb detection for what
kind of content to send back. The decorator helped, but there were still 
many instances that were problematic - especially if you had no content 
and were trying to send back an empty body (204) response; it just didn't 
like it (it wanted a 200 and a valid empty body JSON document - "[]" - 
instead). So leave the freedom to the developer on how to get there, and 
then document it well so devs know how to either avoid it or use it, and 
don't force the same kind of response all the time - e.g there's no reason
to force a 200+empty json document when a 204 is a more appropriate and 
desired response.

So, KISS principle.

$0.02

Ben

On 10/05/2015 01:55 PM, William Hayes wrote:
That’s what I proposed (in a question) below.  I’m just getting to know 
Falcon and don’t know the history of it.  I have not built many REST API 
backends either so I defer to the expertise of the mailing list.

On Oct 5, 2015, at 1:40 PM, Ben Meyer 
<<mailto:ben.meyer@rackspace.com>ben.meyer@rackspace.com<mailto:ben.meyer@rackspace.com>>
wrote:

Question: how would you have it determine that the response content is 
application/json?

I ask because projects I've been on in the past were bitten by this and 
moving to Falcon solved the issue.
For instance, Pecan relies on (a) decorators, and (b) WebOb detection, and
can be a real PITA to get it to generate the response you want all the 
time.

Are you just going to check the 'content-type' response header? (That 
would seem the simpliest approach.) Or do something more?

$0.02

Ben

On 10/05/2015 01:14 PM, William Hayes wrote:
JSON conversion from request and to responses seems like a basic 
requirement - putting it in middleware and magically inserting new 
attributes on the Request object seems wrong to me.

I’ve started a BaseResource class for JSON, but this is not really what I 
want. I’d prefer to override the Request object to add the JSON payload 
directly and provide an easy way to dump the response payload as JSON in 
resp.body.  Is this less magical? or does it make sense to just build this
into Falcon?  If the response Content-Type is application/json - 
automatically convert resp.body to JSON?

For now, I’m using the JSONTranslate middleware with some warnings in my 
code about what! it is do ing.  I like the Falcon approach, clean design 
and fast processing very much - so I’m nit-picking not tearing apart.  It 
just took me a bit to understand what is going on.

import logging
import json

class JsonBaseResource(object):
    def __init__(self):
        self.logger = logging.getLogger('api.' + __name__)

    def get_json_payload(self, req):
        """Get JSON payload of request object body
        :param req: Falcon request object
        :return: JSON version of request object payload
        """
        return json.loads(req.stream.read().decode('utf-8'))

    def make_json_payload(self, resp, payload):
        """Create resp.body from payload data structure
        :param resp: Falcon response object
        :param payload: data structure to add to resp.body
        :return:
        """
        resp.body = json.dumps(payload)