Creating a RESTful API With Flask

Flask http://flask.pocoo.org/ is a python microframework that allows create simple web application quickly and simply. It has some advantages over django, one of these if the RESTFUL support out of the box. This post shows a very simple API implementation using flask.

The first step is created a base class will extend the MethodView . More info about flask class based views here http://flask.pocoo.org/docs/views/#method-based-dispatching

The code

    from flask import abort, jsonify
    from flask.views import MethodView


    class APIView(MethodView):
        """ Generic API, all the API views will inherit for this base class
            every dispatch method will return an invalid request message, every
            child class must implements this methods properly
            More info about flask class based views here
            http://flask.pocoo.org/docs/views/#method-based-dispatching.
        """

        ENDPOINT = '/mymusic/api/v1.0'

        def get(self):
            abort(400)

        def post(self):
            abort(400)

        def put(self):
            abort(400)

        def delete(self):
            abort(400)

        def json_response(self, data={}):
            return jsonify(data)

The param that define the endpoint for the api url is defined at APIView.ENDPONT constant, you can change for whatever you want. After that you create a very simple Resource called UserResource:

    class UserResource(object):
    def __init__(self, data={}, model=None, **kwargs):
        self._dict_data = data
        self._is_valid = True

    def is_valid(self):
        return self._is_valid

    def to_serializable_dict(self):
        return self._dict_data

    def add(self):
        for key, value in self._dict_data.items():
            setattr(self, key, value)

    def update(self):
        for key, value in self._dict_data.items():
            setattr(self, key, value)

    def delete(self):
        self._dict_data = {}

    @classmethod
    def get(cls, user_id):
        dict_data = {'id': user_id, 'name': 'user {0}'.format(user_id)}
        return UserResource(data=dict_data)

    @classmethod
    def get_list(cls, *args, **kwargs):
        user_list = []
        for x in range(4):
            dict_data = {'id': x, 'name': 'user {0}'.format(x)}
            resource = UserResource(data=dict_data)
            user_list.append(resource.to_serializable_dict())

        return user_list

The next step is create a concrete implementation from APIView we will call it Userview:

    class UserAPIView(APIView):
        def get(self, user_id):
            """
            If GET request have the id: attribute, this view will search and return
            an user with this id, If id: atrribute is no setted will return list of
            users
            """
            if user_id:
                user_resource = UserResource.get(user_id)
                data_dict = {'user': user_resource.to_serializable_dict()}
            else:
                data_dict = {'users': UserResource.get_list()}
            return self.json_response(data=data_dict)


        def post(self):
            """
            user Creation is performed by POST METHOD
            """
            response = {}
            user_resource = UserResource(request.json)
            if user_resource.is_valid():
                try:
                    user_resource.add()
                    response['user'] = user_resource.to_serializable_dict()
                except Exception as error:
                    pass
            return self.json_response(data=response)

        def put(self, user_id):
            """
            User modification using PUT method
            """
            response = {}
            user_resource = UserResource(request.json)
            if user_resource.is_valid():
                try:
                    user_resource.update()
                    response['user'] = user_resource.to_serializable_dict()
                except Exception as error:
                    pass
            return self.json_response(data=response)

        def delete(self, user_id):
            response = {}
            user_resource = UserResource(request.json)
            try:
                user_resource.delete()
                response['ok'] = 'record deleted'
            except Exception as error:
                pass
            return self.json_response(data=response)

Configuring the Routes

    app = Flask(__name__)
    user_view = UserAPIView.as_view('user_api')
    app.add_url_rule('{0}/users/'.format(UserAPIView.ENDPOINT), defaults={'user_id': None},
                      view_func=user_view, methods=['GET',])

    app.add_url_rule('{0}/users/'.format(UserAPIView.ENDPOINT), view_func=user_view, methods=['POST',])

    app.add_url_rule('{0}/users/'.format(UserAPIView.ENDPOINT), view_func=user_view,
                     methods=['GET', 'PUT', 'DELETE'])

    def run_app():
        app.run()

    if __name__ == "__main__":
        run_app()

Testing the API

First we start the app:
    python flaskapi.py

Getting user list

curl localhost:5000/mymusic/api/v1.0/users/ will return:

    {
      "users": [
        {
          "id": 0, 
          "name": "user 0"
        }, 
        {
          "id": 1, 
          "name": "user 1"
        }, 
        {
          "id": 2, 
          "name": "user 2"
        }, 
        {
          "id": 3, 
          "name": "user 3"
        }
      ]
    }

Getting an user

curl localhost:5000/mymusic/api/v1.0/users/1 will return:

    {
      "user": {
        "id": 1,
        "name": "user 1"
      }
    }

Creating an user

 curl -X POST localhost:5000/mymusic/api/v1.0/users/ -H "Content-Type: application/json" \
     -d '{"id": 500, "name": "maigfrga"}'

will return:

    {
      "user": {
        "id": 500,
        "name": "maigfrga"
      }
    }

Updating an user

 curl -X PUT localhost:5000/mymusic/api/v1.0/users/500 -H "Content-Type: application/json" \
     -d '{"id": 500, "name": "maigfrga modified"}'

will return:

    {
      "user": {
        "id": 500,
        "name": "maigfrga modified"
      }
    }

Deleting an user

 curl -X DELETE localhost:5000/mymusic/api/v1.0/users/500 -H "Content-Type: application/json" -d '{}'

will return:

    {
      "ok": "record deleted"
    }