金字塔视图配置中的RESTful设计

the*_*hey 0 python rest uri crud pyramid

这是我第一次尝试设计Web应用程序.我为SQLAlchemy数据库创建了一个CRUD操作API.我现在正在尝试使用Pyramid设计一个RESTful Web框架来支持这个DB及其所有实体.

我一直在努力研究如何进行PUT(更新).我知道我还需要纳入某些条件(例如Code 202).我不确定如何使用PUT处理对象替换.视图配置中的方法有点令人困惑,我相信我正在遵循db CRUD操作.

其次,我认为必须通过查找所有资源{id}.我相信我的get_user方法是正确的. User_id保存用户的所有信息db......因此,如果a user被查找,那么id我不需要拥有所有其他信息(参见delete_user方法).

我已经阅读了一些关于设计RESTful设计的精彩教程,但鉴于我是自学成才,我仍在苦苦挣扎.真的很感谢您的帮助!

以下是一些显示问题的代码示例:

_ init _.py(URIs):

config.add_route('post_user', '/users') # POST (HTTP) / CREATE (CRUD)
config.add_route('get_user', '/users/{id}') #GET (HTTP) / RETRIEVE (CRUD)
config.add_route('put_user', '/users/{id}') # PUT (HTTP) / UPDATE (CRUD)
config.add_route('delete_user', '/users/{id}') # DELETE (HTTP) / DELETE (CRUD)
Run Code Online (Sandbox Code Playgroud)

views.py(查看配置 - RESTful):

@view_defaults(renderer='json')
class RESTView(object):
    api = ConvenienceAPI() # CRUD API for database
    def __init__(self, request):
        self.request = request 

    @view_config(route_name='get_user', request_method='GET')
    def get_user(self):
        user_id = int(request.matchdict['user_id'])
        user = api.retrieve_user('user_id') 
        if user is None:
            raise HTTPNotFound()
        else:
            return user

    @view_config(route_name='post_user', request_method='POST')
    def post_user(self):
        username = request.matchdict['username']
        password = request.matchdict['password']
        firstname = request.matchdict['firstname']
        lastname = request.matchdict['lastname']
        email = request.matchdict['email']
        new_user = api.create_user('username', 'password', 'firstname', 'lastname', 'email')
        return Response{'new_user': user}

    @view_config(route_name='put_user', request_method='PUT')
    def put_user(self):
        user = request.matchdict['user_id']
        new_username = # is this pointing to another URL ???? 
        updated_user = api.update_user('username', 'new_username')
        return Response{status='202 Accepted'}

    @view_config(route_name='delete_user', request_method='DELETE')
    def delete_user(self):
        user = request.matchdict['user_id']
        del_user = api.delete_user('username', 'firstname', 'lastname')
        return Response{'del_user': user}
Run Code Online (Sandbox Code Playgroud)

neR*_*Rok 7

TLDR:你有很多问题.也许花更多时间学习python,然后查看金字塔和REST上的一些博客帖子,如http://www.vargascarlos.com/2013/02/pyramid-and-rest/http://codelike.com/blog/2014/4月27日/ A-REST的API与-蟒蛇和金字塔/

您的代码存在一些问题,我将首先解决.然后我会提供一些建议,以便更好地安排你的观点.

1)您已{id}在路由配置中使用,因此您将访问此通道request.matchdict['id'],而不是request.matchdict['user_id'].

额外提示:如果您想强制ID只是数字,您可以使用{id:\d+}.结肠后的部分是正则表达式.这应该有助于防止SQL注入.

2)您的视图已定义为使用JSON渲染器.这意味着你的视图函数应该返回一个python对象(list,dict等),然后金字塔会将这个对象提供给JSON渲染器,它会随意使用数据并创建一个响应(在这种情况下,转换它)进入有效的json.对于模板渲染器,它将使用模板中的对象).因此,你不需要return Response{},但简单return {}.如果您尚未定义渲染器,那么您的视图必须自己制作并返回响应.

3)在您的类方法中get_user,您需要使用self.request访问请求,因为您已将请求保存到类中__init__.

4)我认为你是python的新手.在post_user例如,已保存的用户名与行的变量名username = request.matchdict['username'](应该是username = self.request.params['username']).当你调用你的API时new_user = api.create_user('username', ...,你传入了一个包含内容'username'的字符串,因此你创建了一个名为'username'的用户.你实际上想传入变量username,例如new_user = api.create_user(username, ....

5)继#5之后,python中的dicts是key:value.所以post_user,如果你想在关键'用户'下的json中返回新用户,那么你真的想要return {'user': new_user}.

所以现在我的主要建议是:你不需要为每个get/post/etc路由定义一个命名路由,你可以定义1个路由,然后利用视图谓词来运行正确的函数.

您可能还想创建一个ConvenienceAPI()对象,然后共享它(完全取决于该对象正在做什么以及它是如何工作的).您甚至可以将其附加到请求中.

您还应该考虑重用尽可能多的代码块(即get_user我包含的函数).

在完成上述所有操作后,以下是您的代码的样子;

config.add_route('users', '/users')
config.add_route('user', '/users/{id:\d+}')

API = ConvenienceAPI()

@view_defaults(route_name='users', renderer='json')
class UsersViews(object):

    api = API

    def __init__(self, request):
        self.request = request 

    @view_config(request_method='GET')
    def get(self):
        users = self.api.retrieve_users() 
        return users

    @view_config(request_method='POST')
    def post(self):
        username = self.request.POST.get('username')
        password = self.request.POST.get('password')
        firstname = self.request.POST.get('firstname')
        lastname = self.request.POST.get('lastname')
        email = self.request.POST.get('email')
        user = self.api.create_user(username, password, firstname, lastname, email)
        return user

@view_defaults(route_name='user', renderer='json')
class UserViews(object):

    api = API

    def __init__(self, request):
        self.request = request

    def get_user(self):
        user_id = int(self.request.matchdict['id'])
        user = self.api.retrieve_user(user_id)
        return user

    @view_config(request_method='GET')
    def get(self):
        user = self.get_user()
        if user is None:
            raise HTTPNotFound()
        return user

    @view_config(request_method='PUT')
    def put(self):
        user = self.get_user()
        if user is None:
            raise HTTPNotFound()
        new_username = self.request.POST.get('username')
        updated_user = self.api.update_user(user.username, new_username) # This is a strange way of updating the username, but your 'API' is not really relevant to this question.
        return HTTPAccepted() # Some REST services return the updated user.

    @view_config(request_method='DELETE')
    def delete(self):
        user = self.get_user()
        del_user = self.api.delete_user(user.username, user.firstname, user.lastname)
        if del_user: # If user was deleted.
            return HTTPAccepted() # Or something like this. As above, you might want to return the deleted user.
        else:
            return HTTPBadRequest()
Run Code Online (Sandbox Code Playgroud)