Re: Re: Simple RESTful API - make a patch

"Joseph S. Tate" <[email protected]> Tue, 15 Nov 2016 22:55:29 +0000
Newsgroups gmane.comp.python.cherrypy
Message-ID <CA+WDQbFaBqEpvvGwZ9oWvymG5U2PWfeARpHmo+0PeRkXFSf3cA@mail.gmail.com>
you're almost there. Go to https://github.com/cherrypy/cherrypy/ and click
the "New Pull Request" button. Then click the "compare across forks" link.
Then you can pick your repo and branch as the "head fork".

On Tue, Nov 15, 2016 at 8:15 AM Kearney Taaffe <[email protected]>
wrote:

> Man, I feel stupid. I work with Git at work, but, all we do is just branch
> and merge. I forked the project (since I couldn't seem to branch) and made
> a branch with the ticket number.
>
> https://github.com/gitKearney/cherrypy/tree/feature/1516_fix_get_PATCH_body
>
> I don't know if you can check that out and merge it. I created a tests
> folder, with a simple server and controller, and a caller file that uses
> "requests" to send a PATCH request.
>
>
>
>
> Kearney J. Taaffe
> (817) 239-2783
>
> On Tue, Nov 15, 2016 at 12:43 AM, Joseph S. Tate <[email protected]>
> wrote:
>
> Ideally you'd submit a pull request from your branch with a test that
> proves that the fix works. Perhaps by copying and modifying a test for PUT
> or POST. Then I'll merge it in.
>
> Joseph
>
> On Mon, Nov 14, 2016 at 11:24 AM Kearney Taaffe <[email protected]>
> wrote:
>
> @Josheph, sorry, my response wasn't very explicit. Changing the line 315
> in cherrypy._cprequest.py from
>
> methods_with_bodies = ('POST', 'PUT')
>
>
> to
>
> methods_with_bodies = ('POST', 'PUT', 'PATCH')
>
>
> worked.
>
> I posted the new PATCH() method to show that the body and route param were
> printed to the log
>
>
>
> On Thursday, November 10, 2016 at 10:10:32 AM UTC-6, Kearney Taaffe wrote:
>
> I'm making an API in CherryPy. I must admit, it's super easy, and I'd like
> to turn this example into something that the CherryPy community puts on
> it's website as a "how to API"
>
> The problem I'm having is how to handle an HTTP PATCH request. The
> following code fails with the error for HTTP PATCH requests
>
> AttributeError: 'Request' object has no attribute 'json'
>
>
> Here's my main.py
> import cherrypy
>
>
> from controllers.userController import UserController
>
>
>
>
> def CORS():
>     """Allow web apps not on the same server to use our API
>     """
>     cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"
>     cherrypy.response.headers["Access-Control-Allow-Headers"] = (
>         "content-type, Authorization, X-Requested-With"
>     )
>
>     cherrypy.response.headers["Access-Control-Allow-Methods"] = (
>         'GET, POST, PUT, DELETE, OPTIONS'
>     )
>
> if __name__ == '__main__':
>     """Starts a cherryPy server and listens for requests
>     """
>
>     userController = UserController()
>
>     cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
>
>     cherrypy.config.update({
>         'server.socket_host': '0.0.0.0',
>         'server.socket_port': 8080,
>         'tools.CORS.on': True,
>     })
>
>
>     # API method dispatcher
>     # we are defining this here because we want to map the HTTP verb to
>     # the same method on the controller class. This _api_user_conf will
>     # be used on each route we want to be RESTful
>     _api_conf = {
>         '/': {
>             'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
>         }
>     }
>
>
>     # _api_user_conf better explained
>     # The default dispatcher in CherryPy stores the HTTP method name at
>     # :attr:`cherrypy.request.method<cherrypy._cprequest.Request.method>`.
>
>
>     # Because HTTP defines these invocation methods, the most direct
>     # way to implement REST using CherryPy is to utilize the
>     # :class:`MethodDispatcher<cherrypy._cpdispatch.MethodDispatcher>`
>     # instead of the default dispatcher. To enable
>     # the method dispatcher, add the
>     # following to your configuration for the root URI ("/")::
>
>
>     #     '/': {
>     #         'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
>     #     }
>
>
>     # Now, the REST methods will map directly to the same method names on
>     # your resources. That is, a GET method on a CherryPy class implements
>     # the HTTP GET on the resource represented by that class.
>
>
>     # http://cherrypy.readthedocs.org/en/3.2.6/_sources/progguide/REST.txt
>
>
>     cherrypy.tree.mount(userController, '/api/users', _api_conf)
>
>
>
>     cherrypy.engine.start()
>     cherrypy.engine.block()
>
>
>
> Here's the user controller (controllers/userController.py) (*NOTE: be
> sure the file __init__.py is in the controllers directory and is blank)*
>
> import cherrypy
>
>
> # from services.userServiceProvider import UserServiceProvider
>
>
> from typing import Dict, List
>
>
> '''
> NOTES
>  + @cherrypy.tools.json_out() - automatically outputs response in JSON
>  + @cherrypy.tools.json_in()  - automatically parses JSON body
> '''
> class UserController():
>
>
>     # expose all the class methods at once
>     exposed = True
>
>     def __init__(self):
>         # create an instance of the service provider
>         # self.userService = UserServiceProvider()
>         pass
>
>
>     '''
>     This code allows for our routes to look like
> http://example.com/api/users/uuid
>     and the uuid will be made available to the routes like the user input
>     http://example.com/api/users?uuid=uuid
>     '''
>     def _cp_dispatch(self, vpath: List[str]):
>
>         # since our routes will only contain the GUID, we'll only have 1
>         # path. If we have more, just ignore it
>         if len(vpath) == 1:
>             cherrypy.request.params['uuid'] = vpath.pop()
>
>         return self
>
>
>     @cherrypy.tools.json_out()
>     def GET(self, **kwargs: Dict[str, str]) -> str:
>         """
>         Either gets all the users or a particular user if ID was passed in.
>         By using the cherrypy tools decorator we can automagically output
> JSON
>         without having to using json.dumps()
>         """
>
>
>         # our URI should be /api/users/{GUID}, by using _cp_dispatch,
> this
>         # changes the URI to look like /api/users?uuid={GUID}
>
>         if 'uuid' not in kwargs:
>             # if no GUID was passed in the URI, we should get all users'
> info
>             # from the database
>             # results =  self.userService.getAllUsers()
>             results = {
>                 'status' : 'getting all users'
>             }
>         else:
>             # results = self.userService.getUser(kwargs['uuid'])
>             results = {
>                 'status' : 'searching for user ' + kwargs['uuid']
>             }
>
>
>         return results
>
>     @cherrypy.tools.json_in()
>     @cherrypy.tools.json_out()
>     def POST(self):
>         """Creates a new user
>         """
>         input = cherrypy.request.json
>         inputParams = {}
>
>         # convert the keys from unicode to regular strings
>         for key, value in input.items():
>            inputParams[key] = str(value)
>
>         try:
>             # result = self.userService.addUser(inputParams)
>             result = {
>                 'status' : 'inserting new record'
>             }
>
>
>             if len(inputParams) == 0:
>                 raise Exception('no body')
>         except Exception as err:
>             result = {'error' : 'Failed to create user. ' + err.__str__()}
>
>
>         return result
>
>     @cherrypy.tools.json_out()
>     def DELETE(self, **kwargs: Dict[str, str]):
>         # convert the keys from unicode to regular strings
>         uuid = ''
>         if 'uuid' not in kwargs:
>             result = {
>                 'success' : False,
>                 'message' : 'You must specfy a user.'
>             }
>
>
>             return result
>
>
>         uuid = kwargs['uuid']
>
>
>         try:
>             if len(uuid) == 0:
>                 raise Exception('must pass in user ID')
>
>             # result = self.userService.deleteUser(inputParams)
>             result = {
>                 'status' : 'deleting user with ID: ' + uuid
>             }
>         except Exception as err:
>             result = {'error' : 'could not delete. ' + err.__str__()}
>
>
>         return result
>
>
>     @cherrypy.tools.json_in()
>     @cherrypy.tools.json_out()
>     def PUT(self):
>         # get the request body
>         data = cherrypy.request.json
>         print('BODY:\n' + str(data))
>         # result = self.userService.updateUser(data)
>         result = {
>             'status' : 'updating user'
>         }
>
>
>         return result
>
>
>     @cherrypy.tools.json_in()
>     @cherrypy.tools.json_out()
>     def PATCH(self, **kwargs: Dict[str, str]):
>
>
>         # the _cp_dispatch() method
>         if 'uuid' not in kwargs:
>             result = {
>                 'success' : False,
>                 'message' : 'You must specfy a user.'
>             }
>
>
>             return result
>         else:
>             print('found uuid: ' + kwargs['uuid'])
>
>
>         # get the request body
>         data = cherrypy.request.json
>
>         # result = self.userService.updateUser(data, kwargs['uuid'])
>         result = {
>             'status' : 'patching user ({})'.format(kwargs['uuid'])
>         }
>
>
>         return result
>
>
>     def OPTIONS(self):
>         return 'Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT'
>
>
>     def HEAD(self):
>         return ''
>
>
>
> By the way, feel to kang this code all you want. And, if I'm doing
> something wrong, please tell me.
>
> --
> You received this message because you are subscribed to the Google Groups
> "cherrypy-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to cherrypy-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
> To post to this group, send email to cherrypy-users-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
> Visit this group at https://groups.google.com/group/cherrypy-users.
> For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "cherrypy-users" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/cherrypy-users/-HvSQC0Lmas/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> cherrypy-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
>
>
> To post to this group, send email to cherrypy-users-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
> Visit this group at https://groups.google.com/group/cherrypy-users.
> For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups
> "cherrypy-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to cherrypy-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
> To post to this group, send email to cherrypy-users-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
> Visit this group at https://groups.google.com/group/cherrypy-users.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "cherrypy-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cherrypy-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
To post to this group, send email to cherrypy-users-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
Visit this group at https://groups.google.com/group/cherrypy-users.
For more options, visit https://groups.google.com/d/optout.