Giter Site home page Giter Site logo

miguelgrinberg / rest-tutorial Goto Github PK

View Code? Open in Web Editor NEW
659.0 53.0 266.0 74 KB

Files for my REST API tutorials featuring a server written in Python and a web client written in Javascript.

Home Page: http://blog.miguelgrinberg.com/post/writing-a-javascript-rest-client

License: MIT License

Python 35.79% Shell 0.31% Batchfile 0.35% HTML 63.55%

rest-tutorial's Introduction

REST-tutorial

Files for my REST API tutorials featuring a server written in Python and a web client written in Javascript. Here are the articles:

Setup

  • Install Python 3 and git.
  • Run setup.sh (Linux, OS X, Cygwin) or setup.bat (Windows)
  • Run ./rest-server.py to start the server (on Windows use flask\Scripts\python rest-server.py instead)
  • Alternatively, run ./rest-server-v2.py to start the Flask-RESTful version of the server.
  • Open http://localhost:5000/index.html on your web browser to run the client

rest-tutorial's People

Contributors

cushychicken avatar danielparton avatar dependabot[bot] avatar miguelgrinberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rest-tutorial's Issues

I can't run setup.bat on Window

Traceback (most recent call last):
File "virtualenv.py", line 2577, in
main()
File "virtualenv.py", line 979, in main
no_pip=options.no_pip)
File "virtualenv.py", line 1091, in create_environment
search_dirs=search_dirs, never_download=never_download)
File "virtualenv.py", line 611, in install_setuptools
search_dirs=search_dirs, never_download=never_download)
File "virtualenv.py", line 583, in _install_req
cwd=cwd)
File "virtualenv.py", line 1057, in call_subprocess
% (cmd_desc, proc.returncode))
OSError: Command E:\Project\MYS\REST-...k\Scripts\python.exe -c "#!python
"""Bootstra...sys.argv[1:])

" --always-copy -U setuptools failed with error code 1

E:\Project\MYS\REST-tutorial-master>flask\Scripts\pip install -r requirements.txt
'flask\Scripts\pip' is not recognized as an internal or external command,
operable program or batch file

Missing License

Dear Miguel,

I would like to use this repo as base for more sophisticated app,
so I do not want to run into a LICENSE issues.

Could you please add a LICENSE?
I would prefer Apache 2.0, license, but of course it is up to you.

Yours sincerely,

Ondrej Platek

ModuleNotFoundError

Following the installation instructions and installing (using Python 3.9.0) I get the same error as referenced in a previous bug. I saw no response to that comment and open a new issue for this.

I am using Windows PowerShell and Python 3.9.0 (64 bit).
/Fredrik

E:\Project\MYS\REST-tutorial-master>flask\Scripts\python rest-server.py
Traceback (most recent call last):
File "E:\Project\MYS\REST-tutorial-master\flask\lib\site-packages\werkzeug\serving.py", line 53, in
from SocketServer import ThreadingMixIn, ForkingMixIn
ModuleNotFoundError: No module named 'SocketServer'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "rest-server.py", line 125, in
app.run(debug=True)
File "E:\Project\MYS\REST-tutorial-master\flask\lib\site-packages\flask\app.py", line 758, in run
from werkzeug.serving import run_simple
File "E:\Project\MYS\REST-tutorial-master\flask\lib\site-packages\werkzeug\serving.py", line 56, in
from socketserver import ThreadingMixIn, ForkingMixIn
ImportError: cannot import name 'ForkingMixIn'

E:\Project\MYS\REST-tutorial-master>python --version
Python 3.6.4

Originally posted by @truongvantoan in #13 (comment)

Server Answers with Error 405

Hello Sir

I'm Glad you made this tutorial, it helped me a real big time to understand a bit better Flask; However i seem to find a problem and I can't find why, each time I click on a button that sends a POST or PUT once I try to do some action that Requires PUT server answers with Error 405 but strangely I can Keep Adding items but after adding the first item I can't modify, Mark as Done.
I don't really know where is this happening, because i can POST and PUT using CURL but the webpage isn't working as i would expect.

here's a sample of the PUT request with CURL

todo-api scyth$ curl  -u Tuna:Admin123 -i -H "Content-Type: pplication/json" -X PUT -d '{"hecho":true}' http://localhost:5000/notas/api/v1.0/tareas/4
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 100
Server: Werkzeug/0.10.4 Python/2.7.10
Date: Thu, 18 Jun 2015 23:21:31 GMT

{
  "tarea": {
    "descripcion": "123", 
    "hecho": true, 
    "id": 4, 
    "titulo": "AD"
  }
}Angels-MacBook-Pro:todo-api scyth$ curl  -u Tuna:Admin123 -i -H "Content-Type: pplication/json" -X PUT -d '{"hecho":false}' http://localhost:5000/notas/api/v1.0/tareas/4
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 101
Server: Werkzeug/0.10.4 Python/2.7.10
Date: Thu, 18 Jun 2015 23:21:40 GMT

{
  "tarea": {
    "descripcion": "123", 
    "hecho": false, 
    "id": 4, 
    "titulo": "AD"
  }

here's the part of the code that actually do this.

function AddTaskViewModel(){
    var self = this;
    self.titulo = ko.observable();
    self.descripcion = ko.observable();
    self.agregarTarea = function () {
        $('#add').modal('hide');
        tasksViewModel.add({
            titulo: self.titulo(),
            descripcion: self.descripcion()
            });
            self.titulo("");
            self.descripcion("");
    }
}

function EditTaskViewModel(){
     var self = this;
    self.titulo = ko.observable();
    self.descripcion = ko.observable();
    self.hecho = ko.observable();

    self.establecerTarea = function(tarea){
        self.tarea = tarea;
        self.titulo(tarea.titulo());
        self.descripcion(tarea.descripcion());
        self.hecho(tarea.hecho());
        $('#edit').modal('show'); 
    }
    self.editarTarea = function(){
        $('#edit').modal('hide');
        tasksViewModel.edit(self.tarea, {
           titulo: self.titulo(),
           descripcion: self.descripcion(),
           hecho: self.hecho()
        });
    }
}

here's the server side

@app.route('/notas/api/v1.0/tareas', methods=['POST'])
@auth.login_required
def crear_tarea():
    ''' En este caso el metodo POST se utilizara para crear una nueva nota. la nota debera ser un request tipo application/json y debera contener un titulo.
    En caso de no contar con alguno de los anteriores abortamos con un codigo 400 '''
    if not request.json or not 'titulo' in request.json:
        abort(400)
    tarea = {
        'id':tareas[-1]['id'] + 1,
        'titulo': request.json['titulo'],
        'descripcion':request.json.get('descripcion', ""),
        'hecho':False
    }
    tareas.append(tarea) #en caso de ser exitoso hasta el momento, agregamos la tarea a el arreglo de tareas.
    return jsonify({'tarea':tarea}), 201

@app.route('/notas/api/v1.0/tareas/<int:id_tarea>', methods=['PUT'])
@auth.login_required
def actualizar_tarea(id_tarea):
    ''' El metodo PUT se utiliza para actualizar un objeto dentro de nuestra lista de objetos.
    se revisa que cada uno de los campos actualizados este en formato unicode por compatibilidad.
    en caso de que el request no sea application/json o que no se cumpla con el formato o que el request
    llegue vacio, se utilizara un codigo de error 400, 400, 400, 404 '''
    tarea = [tarea for tarea in tareas if tarea['id'] == id_tarea]
    if len(tarea) == 0:
        abort(404)
    if not request.json:
        abort(400)
    if 'titulo' in request.json and type(request.json['titulo']) != unicode:
        abort(400)
    if 'descripcion' in request.json and type(request.json['descripcion']) != unicode:
        abort(400)
    if 'hecho' in request.json and type(request.json['hecho']) != bool:
        abort(400)
    tarea[0]['titulo'] = request.json.get('titulo', tarea[0]['titulo'])
    tarea[0]['descripcion'] = request.json.get('descripcion', tarea[0]['descripcion'])
    tarea[0]['hecho'] = request.json.get('hecho', tarea[0]['hecho'])
    #hacemos las modificaciones adecuadas en el arreglo de objetos.
    return jsonify({'tarea': tarea[0]})

@app.route('/notas/api/v1.0/tareas/<int:id_tarea>', methods=['DELETE'])
@auth.login_required
def borrar_tarea(id_tarea):
    ''' El metodo DELETE se utilizara para borrar un objeto dentro de nuestra lista usando como identificador el id del objeto.
    en caso de que el request venga vacio regresaremos un error 404. '''
    tarea = [tarea for tarea in tareas if tarea['id'] == id_tarea]
    if len(tarea) == 0:
        abort(404)
    tareas.remove(tarea[0]) #en caso de exito removemos el objeto de la lista
    return jsonify({'resultado': True})

You might be wondering why in spanish some stuff, well my team and I want to learn and use flask and like I said above i found your tutorials to be concise and useful but they don't speak english that's why haha.

How to run this on python 3?

Hello Miguel.

I know you stated in the readme to run this on python 2. But is there any way I can modify the program to run on python 3?

Currently, it produces this error when I run it using python 3 (after entering the credentials in the dialog box) :

Traceback (most recent call last):
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask_restful/__init__.py", line 263, in error_router
    return original_handler(e)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/_compat.py", line 32, in reraise
    raise value.with_traceback(tb)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask_restful/__init__.py", line 263, in error_router
    return original_handler(e)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/_compat.py", line 32, in reraise
    raise value.with_traceback(tb)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask_restful/__init__.py", line 435, in wrapper
    return self.make_response(data, code, headers=headers)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask_restful/__init__.py", line 452, in make_response
    resp = self.representations[mediatype](data, *args, **kwargs)
  File "/home/shawn/.virtualenvs/flaskp3/lib/python3.4/site-packages/flask_restful/representations/json.py", line 24, in output_json
    dumped = dumps(data, **local_settings)
  File "/usr/lib/python3.4/json/__init__.py", line 237, in dumps
    **kw).encode(obj)
  File "/usr/lib/python3.4/json/encoder.py", line 194, in encode
    chunks = list(chunks)
  File "/usr/lib/python3.4/json/encoder.py", line 422, in _iterencode
    yield from _iterencode_dict(o, _current_indent_level)
  File "/usr/lib/python3.4/json/encoder.py", line 396, in _iterencode_dict
    yield from chunks
  File "/usr/lib/python3.4/json/encoder.py", line 429, in _iterencode
    o = _default(o)
  File "/usr/lib/python3.4/json/encoder.py", line 173, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <map object at 0x7f81d1c50e10> is not JSON serializable

And the response I get in the browser in the web console is ajax error 500.

setup.sh should follow PEP 394

Problem it that not everything is using python2 by default. For example Arch Linux uses Python 3 by default.

diff --git a/setup.sh b/setup.sh
index 5b50183..7209315 100755
--- a/setup.sh
+++ b/setup.sh
@@ -1,2 +1,2 @@
-python virtualenv.py flask
+python2 virtualenv.py flask
flask/bin/pip install -r requirements.txt

Two minor mistakes from tags v0.1 to v0.7

While working through Writing a Javascript REST Client, I noticed two minor mistakes in all tags from v0.1 to v0.7.

The first one is the following import statement, which is the old way of importing Flask-HTTPAuth.

from flask.ext.httpauth import HTTPBasicAuth

For the latest version, it should be

from flask_httpauth import HTTPBasicAuth

The second one is that there are two not_found functions. Actually the first one should be named bad_request.

@app.errorhandler(400)
def bad_request(error):
    return make_response(jsonify( { 'error': 'Bad request' } ), 400)
 
@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify( { 'error': 'Not found' } ), 404)

Cross-Origin Request Blocked

Following the setup steps for Windows I open http://localhost:5000/index.html on my web browser to run the client. The table headings are displayed (Task, Options, etc.) as well as the "Add Task" button. No data is displayed. This is consistent on Firefox, Edge and Internet Explorer.

Using the Firefox browser console I see the following errors:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/todo/api/v1.0/tasks?_=1641069699513. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

It also says "ajax error 0" which I think is output from the error handler.

This or a similar issue was raised in a previous issue and attributed to the server and client being run on the same host. I'm new to front end development but after reading about CORS today I think it is rather due to that the endpoints require authentication. As I understand it, "Access-Control-Allow-Origin" needs to be specified on the response (and not as "*") or standard browsers will not accept the response. Non browser clients may not have this issue.

Not sure how to accomplish this in the simplest way though...

TaskAPI inflexible on single argument changes.

Some form of the following issue occurs when you try to change a single attribute of a single task (e.g. changing 'done' from False to True) when running the rest-server-v2.py script:

File "/Users/nreilly/Desktop/projects/factsure/lib/python2.7/site-packages/flask_restful/init.py", line 268, in handle_error
raise exc
TypeError: init() takes exactly 4 arguments (2 given)

Shouldn't a curl request be able to selectively edit single parameters of the URI? FYI, I think this was brought up by a commenter on your second

Sorry if my terminology isn't correct, I'm very new to web development.

doesn't run as stated

Setup

  • Install Python 2.7 and git.
  • Run setup.sh (Linux, OS X, Cygwin) or setup.bat (Windows)
  • Run python rest-server.py to start the server

python installed
macMini:REST-tutorial-0.1 yves$ python --version
Python 2.7.2

macMini:REST-tutorial-0.1 yves$ ./setup.sh
New python executable in flask/bin/python
Installing setuptools................done.
Installing pip.............done.
Downloading/unpacking git+git://github.com/miguelgrinberg/[email protected] (from -r requirements.txt (line 2))
Cloning git://github.com/miguelgrinberg/flask-httpauth.git (to v0.6) to /var/folders/qv/jbvzshbs76n4tqm3w4mfcx680000gn/T/pip-Azvlgi-build
fatal: remote error:
Repository not found.
Complete output from command /usr/local/bin/git clone -q git://github.com/miguelgrinberg/flask-httpauth.git /var/folders/qv/jbvzshbs76n4tqm3w4mfcx680000gn/T/pip-Azvlgi-build:


Cleaning up...
Command /usr/local/bin/git clone -q git://github.com/miguelgrinberg/flask-httpauth.git /var/folders/qv/jbvzshbs76n4tqm3w4mfcx680000gn/T/pip-Azvlgi-build failed with error code 128 in None
Storing complete log in /Users/yves/.pip/pip.log

SHOULD MODIFY requirments.txt to read

git+git://github.com/miguelgrinberg/Flask-HTTPAuth.git

it's cloning..

then :

python rest-server.py
Traceback (most recent call last):
File "rest-server.py", line 2, in
from flask import Flask, jsonify, abort, request, make_response, url_for
ImportError: No module named flask

Access-Control-Allow-Origin

Running the server on localhost:5000 and the client on localhost is raising obviously the error :
Origin http://localhost is not allowed by Access-Control-Allow-Origin.

Is there any Access-Control-Allow-Origin: *
added to the response in the python server ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.