Skip to content
Snippets Groups Projects
Select Git revision
1 result Searching

python_web_flask

  • Clone with SSH
  • Clone with HTTPS
  • Forked from Ronnie Paskin / python_web_flask
    3 commits behind the upstream repository.
    user avatar
    Ronnie Paskin authored
    af25916d
    History
    Name Last commit Last update
    .api.py
    .gitignore
    README.md
    api.py
    app.py
    movies.csv

    Tutorial de Servidor Web e APIs com python

    https://poseidon.les.inf.puc-rio.br/rpaskin/python_web_flask

    Você pode clonar diretamente, ou melhor ainda, crie seu próprio Fork!

    Forking

    git clone git@poseidon.les.inf.puc-rio.br:rpaskin/python_web_flask.git (ou o seu fork)

    O objetivo desse tutorial é mostrar como podemos criar um servidor web para integrar com qualquer código Python.

    Instalação Python, Virtualenv e Flask

    Ambiente

    Você deve ter o python3 instalado. Caso não tenha:

    Por exemplo:

    brew update
    brew upgrade python
    # OU caso não esteja instalado
    brew install python

    Ambiente Virtual

    Um ambiente virtual cria uma configuração local ao seu diretório sem afetar o resto do sistema. Veja https://virtualenv.pypa.io/en/latest/

    Para instalar caso não tenha:

    pip3 install virtualenv

    Crie uma pasta para seu teste e crie o ambiente virtual

    mkdir flask # cria a pasta
    cd flask
    virtualenv flask
    flask/bin/python3 -m pip install flask

    Permissões

    Para poder executar (rodar) um programa, ele deve ter permissões de execução, para isso use o comando chmod:

    chmod a+x app.py
    chmod a+x api.py

    Edite o programa do servidor simples app.py

    #!flask/bin/python
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return "Olá mundo!"
    
    if __name__ == '__main__':
        app.run(debug=True)

    Execute o servidor simples

    Para executar use ./ (indicando o diretório atual) seguido do nome do programa:

    ./app.py

    Acesse a URL mostrada. Qual o resultado?

    Indo além

    Vamos criar um outro servidor mais complexo com uma API REST.

    O que é REST?

    REpresentational State Transfer

    REST é um estilo de arquitetura para recursos em rede, que deve obedecer a algumas diretivas:

    • Interface uniforme
    • Não guarda estado
    • Cacheável
    • Cliente-servidor
    • Sistema em camadas

    REST

    Verbos

    Os verbos definem qual o tipo de pedido (request):

    HTTP Verb CRUD Entire Collection (e.g. /customers) Specific Item (e.g. /customers/{id})
    POST Create 201 (Created), 'Location' header with link to /customers/{id} containing new ID. 404 (Not Found), 409 (Conflict) if resource already exists..
    GET Read 200 (OK), list of customers. Use pagination, sorting and filtering to navigate big lists. 200 (OK), single customer. 404 (Not Found), if ID not found or invalid.
    PUT Update/Replace 405 (Method Not Allowed), unless you want to update/replace every resource in the entire collection. 200 (OK) or 204 (No Content). 404 (Not Found), if ID not found or invalid.
    PATCH Update/Modify 405 (Method Not Allowed), unless you want to modify the collection itself. 200 (OK) or 204 (No Content). 404 (Not Found), if ID not found or invalid.
    DELETE Delete 405 (Method Not Allowed), unless you want to delete the whole collection—not often desirable. 200 (OK). 404 (Not Found), if ID not found or invalid.

    Note que são diretivas e nem sempre são obedecidas ao pé da letra. Ou seja, você poderia implementar um Delete usando um verbo GET. Poderia mas não deveria!

    Referências

    Exemplo: servidor com API Rest (GET)

    #!flask/bin/python
    from flask import Flask, jsonify, abort
    
    app = Flask(__name__)
    
    tasks = [
        {
            'id': 1,
            'title': u'Buy groceries',
            'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
            'done': False
        },
        {
            'id': 2,
            'title': u'Learn Python',
            'description': u'Need to find a good Python tutorial on the web',
            'done': False
        }
    ]
    
    @app.route('/todo/api/v1.0/tasks', methods=['GET'])
    def get_tasks():
        return jsonify({'tasks': tasks})
    
    if __name__ == '__main__':
        app.run(debug=True)

    Testando o GET

    Via linha de comando (usando o curl)

    Caso necessário:

    $ brew install curl

    Rode o comando para acessar o servidor:

    $ curl -i http://localhost:5000/todo/api/v1.0/tasks

    Acesse a URL mostrada. Qual o resultado? Por que? Como resolver?

    Adicionando uma nova rota (GET)

    @app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['GET'])
    def get_task(task_id):
        task = [task for task in tasks if task['id'] == task_id]
        if len(task) == 0:
            abort(404)
        return jsonify({'task': task[0]})

    Como acessar a URL dessa nova rota?

    Desafios

    • Juntar as três versões no mesmo servidor (Olá mundo, /tasks e /tasks/int:task_id )

    Adicionando erros mais amigáveis

    from flask import make_response
    
    @app.errorhandler(404)
    def not_found(error):
        return make_response(jsonify({'error': 'Not found'}), 404)

    Adicionando rota de POST

    from flask import request
    
    @app.route('/todo/api/v1.0/tasks', methods=['POST'])
    def create_task():
        if not request.json or not 'title' in request.json:
            abort(400)
        task = {
            'id': tasks[-1]['id'] + 1,
            'title': request.json['title'],
            'description': request.json.get('description', ""),
            'done': False
        }
        tasks.append(task)
        return jsonify({'task': task}), 201

    Testando o POST via shell

    $ curl -i -H "Content-Type: application/json" -X POST -d '{"title":"Ler um livro"}' http://localhost:5000/todo/api/v1.0/tasks
    
    HTTP/1.0 201 CREATED
    Content-Type: application/json
    Content-Length: 106
    Server: Werkzeug/0.14.1 Python/3.6.1
    Date: Tue, 11 Dec 2018 13:36:23 GMT
    
    {
      "task": {
        "description": "",
        "done": false,
        "id": 3,
        "title": "Ler um livro"
      }
    }
    
    $ curl -i http://localhost:5000/todo/api/v1.0/tasks

    Desafio

    • Usar dados que você mesmo pode prover, a partir de outras fontes.

    Exemplo

    Mostrar dados de filmes do kaggle: https://www.kaggle.com/jrobischon/wikipedia-movie-plots

    Pandas

    Instalar pandas se necessário:

    $ flask/bin/python3 -m pip install pandas

    Nova rota

    import pandas as pd
    
    @app.route('/movies/api/v0.1/movies', methods=['GET'])
    def get_movies():
        csv_file = pd.DataFrame(pd.read_csv("movies.csv", sep = ",", header = 0, index_col = False))
        json_file = csv_file.to_json(orient = "records", date_format = "epoch", double_precision = 10, force_ascii = True, date_unit = "ms", default_handler = None)
        response = app.response_class(
            response=json_file,
            status=200,
            mimetype='application/json'
        )
        return response

    Próximos passos

    Django

    Se você quiser algo mais complexo, porém mais robusto usando Model-View-Controller, por exemplo, aprenda a usar o Django, por exemplo pelo tutorial do Vitor Freitas

    Créditos

    Tutorial de Michael Grinberg:

    https://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask