Search code examples
python-3.xpycharmflask-restful

Flask TypeError: argument of type 'NoneType' is not iterable


I am not sure why I am getting this TypeError:

File "C:/Users/PycharmProjects/REST/app.py", line 30, in valid_book_object if ("isbn" in book and "name" in book and "price" in book): TypeError: argument of type 'NoneType' is not iterable 127.0.0.1 - - [12/Nov/2018 14:22:29] "POST /books HTTP/1.1" 500 -

Code:

from flask import Flask, jsonify, request
from test import *
app=Flask(__name__)

books=[
    {'name': 'M',
     'price': 6.75,
    'isbn':123
    },
    {'name': 'G',
     'price': 7.75,
    'isbn':456
    },

]


#GET /store
@app.route('/books')  #first endpoint
def get_books():
    return jsonify({'books': books})

# POST /books
#{'name': 'F',
 #'price': 7.00,
 #'isbn': 789
 #},

def valid_book_object(book):
    if ("isbn" in book and "name" in book and "price" in book):
         return True
         print("true")
    else:
        return False
        print("false")


@app.route('/books', methods=['POST'])
def add_book():
    #return jsonify(request.get_json())
     request_data=request.get_json()
     if(valid_book_object(request_data)):
        books.insert(0, request_data)
        return "True"
     else:
        return "False"


#GET /books/456
@app.route('/books/<int:isbn>')  #second endpoint
def get_book_by_isbn(isbn):
    return_value={}
    for book in books:
        if book["isbn"]==isbn:
            return_value={
                'name': book["name"],
                'price':book["price"]
            }
    return jsonify(return_value)



app.run(port=5000)

Solution

  • You are not sending JSON data to /books route using POST method.

    I tried your solution with postman and it worked. Also, if you want to use some route for GET and POST, don't split them. Use methods=['GET', 'POST']. Here is your code reformatted with PEP 8 standard:

    from flask import Flask, jsonify, request
    
    app = Flask(__name__)
    
    books = [
        {'name': 'M',
         'price': 6.75,
         'isbn': 123
         },
        {'name': 'G',
         'price': 7.75,
         'isbn': 456
         }
    ]
    
    # POST /books
    # {
    #     "name": "F",
    #     "price": 7.00,
    #     "isbn": 789
    # }
    
    
    def valid_book_object(book):
        if "isbn" in book and "name" in book and "price" in book:
            return True
        else:
            return False
    
    
    @app.route('/books', methods=['GET', 'POST'])
    def add_book():
        # If request is GET, just return JSON data of books.
        if request.method == 'GET':
            return jsonify({'books': books})
        else:
            # This is part if it is POST request
            request_data = request.get_json()
            if valid_book_object(request_data):
                books.insert(0, request_data)
                return "True"
            else:
                return "False"
    
    
    # GET /books/456
    @app.route('/books/<int:isbn>')  # second endpoint
    def get_book_by_isbn(isbn):
        return_value = {}
        for book in books:
            if book["isbn"] == isbn:
                return_value = {
                    'name': book["name"],
                    'price': book["price"]
                }
                return jsonify(return_value)
        return 'No book with {} isbn value'.format(isbn)
    
    
    if __name__ == '__main__':
        app.run(port=5000)
    

    And here is the output from postman (you can see True at the bottom, that is what you return if POST was successful):

    postman

    If you use postman, be sure to select application/json content-type.

    If you are using JQuery ajax method, please read this answer. But anyway, here is using JQuery (tested):

    data = JSON.stringify({
        name: "F",
        price: 7.00,
        isbn: 789
    });
    $.ajax({
      url: '/books',
      type: "POST",
      data: data,
      contentType: "application/json",
      dataType: "json",
      success: function(){
        console.log('Post executed successfully');
      }
    })