librelist archives

« back to archive

Flask-Restless Routing Exceptions

Flask-Restless Routing Exceptions

From:
Russell Holloway
Date:
2013-12-02 @ 23:12
Hey all,

I'm trying to add an API using Flask-Restless and have come across an
issue that completely stumps me, and I'm not sure if it's starting in
the initial Flask app or Flask-Restless. Short story, I'm getting 301
Moved Permanently on my Flask-Restless routes and have no idea where
they come from.

Longer Story:
I'm using Flask 0.8, Flask-Restless 0.12.1, and SQLAlchemy 0.8.2. I'm
using the pure SQLAlchemy method rather than Flask-Alchemy given other
requirements we have.

I attempted to create a standard setup for a basic class defined in
SQLAlchemy.

# Flask-Restless Setup
manager = APIManager(app, session = sqlalchemy_scoped_session)
manager.create_api(TheClass, collection_name="the_class", methods=["GET"])

The code above should set up a blueprint with routes. In fact, if I
iterate over the rules, I can see the routes are created as expected.
For example, "/api/the_class/<instid> (HEAD, OPTIONS, GET)" is one of
the basic ones I try to access.

Here is where it gets weird. I make a request for

GET /wsgi_base/api/the_class/1

and get a "301 Moved Permanently" back, redirecting to
"/wsgi_base/api/the_class/None". This ends up leading to an attribute
error because u"None" is not an attribute...

Does anyone know where this 301 may be coming from? I've searched and
searched but haven't figured it out. Simple grepping for 301 in both
flask and flask_restless come up with nothing. Some rough,
unprofessional debugging techniques shows it tosses a routing_exception
within app.py in Flask fairly early on somewhere..In fact, it seems to
already have "301 Moved Permanently" as the
_request_ctx_stack.top.request.routing_exception in the earliest code I
see in a traceback - right in the start of the wsgi_app function. I'm
not sure what code executes before that as it's the earliest code I have
in traceback and seems to be the start of wsgi running the app.

This only seems to happen for these flask_restless API requests as
well...If I put in a bogus route, there is no 301 exception. If I put in
any hard coded routes, it works fine as well. But what doesn't make
sense is I can print the rules/endpoints after calling create_api() and
everything looks ok there..

Re: [flask] Flask-Restless Routing Exceptions

From:
gioi
Date:
2013-12-03 @ 13:55
So weird... Would you gimme some code to reproduce this?

Re: [flask] Flask-Restless Routing Exceptions

From:
Russell Holloway
Date:
2013-12-03 @ 22:21
On 12/3/13, 8:55 AM, gioi wrote:
> So weird... Would you gimme some code to reproduce this?
>
Sure. Here is some slightly adjusted code straight from Flask-Restless
tutorial. Just adjusted it to work with pure SQLAlchemy. This was tested
using Flask 0.8 and Flask-Restless 0.12. I'm still working on testing
running newer versions of Flask, but it truly is a pain to jump through
some of these hoops to do so.

Hitting <ip>:5000/api/person/1 redirects to <ip>:5000/api/person/1/None

---

from flask import Flask
from sqlalchemy import Column, Date, DateTime, Float, Integer, Unicode
from sqlalchemy import ForeignKey
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import backref, relationship
from sqlalchemy.orm import scoped_session, sessionmaker
from flask.ext.restless import APIManager


app = Flask(__name__)
engine = create_engine('sqlite:////tmp/testdb.sqlite', convert_unicode=True)
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
mysession = scoped_session(Session)

Base = declarative_base()
Base.metadata.bind = engine

class Computer(Base):
    __tablename__ = 'computer'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode, unique=True)
    vendor = Column(Unicode)
    buy_date = Column(DateTime)
    owner_id = Column(Integer, ForeignKey('person.id'))

class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode, unique=True)
    age = Column(Float)
    other = Column(Float)
    birth_date = Column(Date)
    computers = relationship('Computer',
                             backref=backref('owner', lazy='dynamic'))

Base.metadata.create_all()

# Create the Flask-Restless API manager.
manager = APIManager(app, session=mysession)

# Create API endpoints, which will be available at /api/<tablename> by
# default. Allowed HTTP methods can be specified as well.
manager.create_api(Person, methods=['GET', 'POST', 'DELETE'])
manager.create_api(Computer, methods=['GET'])

# start the flask loop
app.run(host='0.0.0.0')