W3cubDocs

/Falcon 2.0

FAQ

Design Philosophy

Why doesn’t Falcon come with batteries included?

Falcon is designed for applications that require a high level of customization or performance tuning. The framework’s minimalist design frees the developer to select the best strategies and 3rd-party packages for the task at hand.

The Python ecosystem offers a number of great packages that you can use from within your responders, hooks, and middleware components. As a starting point, the community maintains a list of Falcon add-ons and complementary packages.

Why doesn’t Falcon create a new Resource instance for every request?

Falcon generally tries to minimize the number of objects that it instantiates. It does this for two reasons: first, to avoid the expense of creating the object, and second to reduce memory usage by reducing the total number of objects required under highly concurrent workloads. Therefore, when adding a route, Falcon requires an instance of your resource class, rather than the class type. That same instance will be used to serve all requests coming in on that route.

Why does raising an error inside a resource crash my app?

Generally speaking, Falcon assumes that resource responders (such as on_get(), on_post(), etc.) will, for the most part, do the right thing. In other words, Falcon doesn’t try very hard to protect responder code from itself.

This approach reduces the number of checks that Falcon would otherwise have to perform, making the framework more efficient. With that in mind, writing a high-quality API based on Falcon requires that:

  1. Resource responders set response variables to sane values.
  2. Your code is well-tested, with high code coverage.
  3. Errors are anticipated, detected, and handled appropriately within each responder and with the aid of custom error handlers.

Tip

Falcon will re-raise errors that do not inherit from HTTPError unless you have registered a custom error handler for that type (see also: falcon.API).

How do I generate API documentation for my Falcon API?

When it comes to API documentation, some developers prefer to use the API implementation as the user contract or source of truth (taking an implementation-first approach), while other developers prefer to use the API spec itself as the contract, implementing and testing the API against that spec (taking a design-first approach).

At the risk of erring on the side of flexibility, Falcon does not provide API spec support out of the box. However, there are several community projects available in this vein. Our Add on Catalog lists a couple of these projects, but you may also wish to search PyPI for additional packages.

If you are interested in the design-first approach mentioned above, you may also want to check out API design and gateway services such as Tyk, Apiary, Amazon API Gateway, or Google Cloud Endpoints.

Performance

Does Falcon work with HTTP/2?

Falcon is a WSGI framework and as such does not serve HTTP requests directly. However, you can get most of the benefits of HTTP/2 by simply deploying any HTTP/2-compliant web server or load balancer in front of your app to translate between HTTP/2 and HTTP/1.1. Eventually we expect that Python web servers (such as uWSGI) will support HTTP/2 natively, eliminating the need for a translation layer.

Is Falcon thread-safe?

The Falcon framework is, itself, thread-safe. For example, new Request and Response objects are created for each incoming HTTP request. However, a single instance of each resource class attached to a route is shared among all requests. Middleware objects and other types of hooks, such as custom error handlers, are likewise shared. Therefore, as long as you implement these classes and callables in a thread-safe manner, and ensure that any third-party libraries used by your app are also thread-safe, your WSGI app as a whole will be thread-safe.

That being said, IO-bound Falcon APIs are usually scaled via multiple processes and green threads (courtesy of the gevent library or similar) which aren’t truly running concurrently, so there may be some edge cases where Falcon is not thread-safe that we aren’t aware of. If you run into any issues, please let us know.

Does Falcon support asyncio?

Due to the limitations of WSGI, Falcon is unable to support asyncio at this time. However, we are exploring alternatives to WSGI (such as ASGI) that will allow us to support asyncio natively in the future.

In the meantime, we recommend using the battle-tested gevent library via Gunicorn or uWSGI to scale IO-bound services. meinheld has also been used successfully by the community to power high-throughput, low-latency services. Note that if you use Gunicorn, you can combine gevent and PyPy to achieve an impressive level of performance. (Unfortunately, uWSGI does not yet support using gevent and PyPy together.)

Does Falcon support WebSocket?

Due to the limitations of WSGI, Falcon is unable to support the WebSocket protocol as stated above.

In the meantime, you might try leveraging uWSGI’s native WebSocket support, or implementing a standalone service via Aymeric Augustin’s handy websockets library.

Routing

How do I implement CORS with Falcon?

In order for a website or SPA to access an API hosted under a different domain name, that API must implement Cross-Origin Resource Sharing (CORS). For a public API, implementing CORS in Falcon can be as simple as implementing a middleware component similar to the following:

class CORSComponent(object):
    def process_response(self, req, resp, resource, req_succeeded):
        resp.set_header('Access-Control-Allow-Origin', '*')

        if (req_succeeded
            and req.method == 'OPTIONS'
            and req.get_header('Access-Control-Request-Method')
        ):
            # NOTE(kgriffs): This is a CORS preflight request. Patch the
            #   response accordingly.

            allow = resp.get_header('Allow')
            resp.delete_header('Allow')

            allow_headers = req.get_header(
                'Access-Control-Request-Headers',
                default='*'
            )

            resp.set_headers((
                ('Access-Control-Allow-Methods', allow),
                ('Access-Control-Allow-Headers', allow_headers),
                ('Access-Control-Max-Age', '86400'),  # 24 hours
            ))

When using the above approach, OPTIONS requests must also be special-cased in any other middleware or hooks you use for auth, content-negotiation, etc. For example, you will typically skip auth for preflight requests because it is simply unnecessary; note that such request do not include the Authorization header in any case.

For more sophisticated use cases, have a look at Falcon add-ons from the community, such as falcon-cors, or try one of the generic WSGI CORS libraries available on PyPI. If you use an API gateway, you might also look into what CORS functionality it provides at that level.

How do I implement redirects within Falcon?

Falcon provides a number of exception classes that can be raised to redirect the client to a different location (see also Redirection).

Note, however, that it is more efficient to handle permanent redirects directly with your web server, if possible, rather than placing additional load on your app for such requests.

How do I split requests between my original app and the part I migrated to Falcon?

It is common to carve out a portion of an app and reimplement it in Falcon to boost performance where it is most needed.

If you have access to your load balancer or reverse proxy configuration, we recommend setting up path or subdomain-based rules to split requests between your original implementation and the parts that have been migrated to Falcon (e.g., by adding an additional location directive to your NGINX config).

If the above approach isn’t an option for your deployment, you can implement a simple WSGI wrapper that does the same thing:

def application(environ, start_response):
    try:
        # NOTE(kgriffs): Prefer the host header; the web server
        # isn't supposed to mess with it, so it should be what
        # the client actually sent.
        host = environ['HTTP_HOST']
    except KeyError:
        # NOTE(kgriffs): According to PEP-3333, this header
        # will always be present.
        host = environ['SERVER_NAME']

    if host.startswith('api.'):
        return falcon_app(environ, start_response)
    elif:
        return webapp2_app(environ, start_response)

See also PEP 3333 for a complete list of the variables that are provided via environ.

How do I implement both POSTing and GETing items for the same resource?

Suppose you have the following routes:

# Resource Collection
GET /resources{?marker, limit}
POST /resources

# Resource Item
GET /resources/{id}
PATCH /resources/{id}
DELETE /resources/{id}

You can implement this sort of API by simply using two Python classes, one to represent a single resource, and another to represent the collection of said resources. It is common to place both classes in the same module (see also this section of the tutorial.)

Alternatively, you can use suffixed responders to map both routes to the same resource class:

class MyResource(object):
    def on_get(self, req, resp, id):
        pass

    def on_patch(self, req, resp, id):
        pass

    def on_delete(self, req, resp, id):
        pass

    def on_get_collection(self, req, resp):
        pass

    def on_post_collection(self, req, resp):
        pass


# ...


resource = MyResource()
api.add_route('/resources/{id}', resource)
api.add_route('/resources', resource, suffix='collection')

Let’s say we have the following URL schema:

GET  /game/ping
GET  /game/{game_id}
POST /game/{game_id}
GET  /game/{game_id}/state
POST /game/{game_id}/state

We can break this down into three resources:

Ping:

    GET  /game/ping

Game:

    GET  /game/{game_id}
    POST /game/{game_id}

GameState:

    GET  /game/{game_id}/state
    POST /game/{game_id}/state

GameState may be thought of as a sub-resource of Game. It is a distinct logical entity encapsulated within a more general Game concept.

In Falcon, these resources would be implemented with standard classes:

class Ping(object):

    def on_get(self, req, resp):
        resp.body = '{"message": "pong"}'


class Game(object):

    def __init__(self, dao):
        self._dao = dao

    def on_get(self, req, resp, game_id):
        pass

    def on_post(self, req, resp, game_id):
        pass


class GameState(object):

    def __init__(self, dao):
        self._dao = dao

    def on_get(self, req, resp, game_id):
        pass

    def on_post(self, req, resp, game_id):
        pass


api = falcon.API()

# Game and GameState are closely related, and so it
# probably makes sense for them to share an object
# in the Data Access Layer. This could just as
# easily use a DB object or ORM layer.
#
# Note how the resources classes provide a layer
# of abstraction or indirection which makes your
# app more flexible since the data layer can
# evolve somewhat independently from the presentation
# layer.
game_dao = myapp.DAL.Game(myconfig)

api.add_route('/game/ping', Ping())
api.add_route('/game/{game_id}', Game(game_dao))
api.add_route('/game/{game_id}/state', GameState(game_dao))

Alternatively, a single resource class could implement suffixed responders in order to handle all three routes:

class Game(object):

    def __init__(self, dao):
        self._dao = dao

    def on_get(self, req, resp, game_id):
        pass

    def on_post(self, req, resp, game_id):
        pass

    def on_get_state(self, req, resp, game_id):
        pass

    def on_post_state(self, req, resp, game_id):
        pass

    def on_get_ping(self, req, resp):
        resp.data = b'{"message": "pong"}'


# ...


api = falcon.API()

game = Game(myapp.DAL.Game(myconfig))

api.add_route('/game/{game_id}', game)
api.add_route('/game/{game_id}/state', game, suffix='state')
api.add_route('/game/ping', game, suffix='ping')

Extensibility

How do I use WSGI middleware with Falcon?

Instances of falcon.API are first-class WSGI apps, so you can use the standard pattern outlined in PEP-3333. In your main “app” file, you would simply wrap your api instance with a middleware app. For example:

import my_restful_service
import some_middleware

app = some_middleware.DoSomethingFancy(my_restful_service.api)

See also the WSGI middleware example given in PEP-3333.

How can I pass data from a hook to a responder, and between hooks?

You can inject extra responder kwargs from a hook by adding them to the params dict passed into the hook. You can also set custom attributes on the req.context object, as a way of passing contextual information around:

def authorize(req, resp, resource, params):
    # Check authentication/authorization
    # ...

    req.context.role = 'root'
    req.context.scopes = ('storage', 'things')
    req.context.uid = 0

# ...

@falcon.before(authorize)
def on_post(self, req, resp):
    pass

How can I write a custom handler for 404 and 500 pages in falcon?

When a route can not be found for an incoming request, Falcon uses a default responder that simply raises an instance of falcon.HTTPNotFound. You can use falcon.API.add_error_handler() to register a custom error handler for this exception type. Alternatively, you may be able to configure your web server to transform the response for you (e.g., using Nginx’s error_page directive).

500 errors are typically the result of an unhandled exception making its way up to the web server. To handle these errors more gracefully, you can add a custom error handler for Python’s base Exception type.

Request Handling

How do I authenticate requests?

Hooks and middleware components can be used together to authenticate and authorize requests. For example, a middleware component could be used to parse incoming credentials and place the results in req.context. Downstream components or hooks could then use this information to authorize the request, taking into account the user’s role and the requested resource.

Why does req.stream.read() hang for certain requests?

This behavior is an unfortunate artifact of the request body mechanics not being fully defined by the WSGI spec (PEP-3333). This is discussed in the reference documentation for stream, and a workaround is provided in the form of bounded_stream.

How does Falcon handle a trailing slash in the request path?

If your app sets strip_url_path_trailing_slash to True, Falcon will normalize incoming URI paths to simplify later processing and improve the predictability of application logic. This can be helpful when implementing a REST API schema that does not interpret a trailing slash character as referring to the name of an implicit sub-resource, as traditionally used by websites to reference index pages.

For example, with this option enabled, adding a route for '/foo/bar' implicitly adds a route for '/foo/bar/'. In other words, requests coming in for either path will be sent to the same resource.

Note

Starting with version 2.0, the default for the strip_url_path_trailing_slash request option changed from True to False.

Why is my query parameter missing from the req object?

If a query param does not have a value, Falcon will by default ignore that parameter. For example, passing 'foo' or 'foo=' will result in the parameter being ignored.

If you would like to recognize such parameters, you must set the keep_blank_qs_values request option to True. Request options are set globally for each instance of falcon.API via the req_options property. For example:

api.req_options.keep_blank_qs_values = True

Why are ‘+’ characters in my params being converted to spaces?

The + character is often used instead of %20 to represent spaces in query string params, due to the historical conflation of form parameter encoding (application/x-www-form-urlencoded) and URI percent-encoding. Therefore, Falcon, converts + to a space when decoding strings.

To work around this, RFC 3986 specifies + as a reserved character, and recommends percent-encoding any such characters when their literal value is desired (%2B in the case of +).

How can I access POSTed form params?

By default, Falcon does not consume request bodies. However, setting the auto_parse_form_urlencoded to True on an instance of falcon.API will cause the framework to consume the request body when the content type is application/x-www-form-urlencoded, making the form parameters accessible via params, get_param(), etc.

api.req_options.auto_parse_form_urlencoded = True

Alternatively, POSTed form parameters may be read directly from stream and parsed via falcon.uri.parse_query_string() or urllib.parse.parse_qs().

How can I access POSTed files?

Falcon does not currently support parsing files submitted by an HTTP form (multipart/form-data), although we do plan to add this feature in a future version. In the meantime, you can use the standard cgi.FieldStorage class to parse the request:

# TODO: Either validate that content type is multipart/form-data
# here, or in another hook before allowing execution to proceed.

# This must be done to avoid a bug in cgi.FieldStorage
env = req.env
env.setdefault('QUERY_STRING', '')

# TODO: Add error handling, when the request is not formatted
# correctly or does not contain the desired field...

# TODO: Consider overriding make_file, so that you can
# stream directly to the destination rather than
# buffering using TemporaryFile (see http://goo.gl/Yo8h3P)
form = cgi.FieldStorage(fp=req.stream, environ=env)

file_item = form[name]
if file_item.file:
    # TODO: It's an uploaded file... read it in
else:
    # TODO: Raise an error

You might also try this streaming_form_data package by Siddhant Goel, or searching PyPI for additional options from the community.

How do I consume a query string that has a JSON value?

Falcon defaults to treating commas in a query string as literal characters delimiting a comma separated list. For example, given the query string ?c=1,2,3, Falcon defaults to adding this to your request.params dictionary as {'c': ['1', '2', '3']}. If you attempt to use JSON in the value of the query string, for example ?c={'a':1,'b':2}, the value will get added to your request.params in a way that you probably don’t expect: {'c': ["{'a':1", "'b':2}"]}.

Commas are a reserved character that can be escaped according to RFC 3986 - 2.2. Reserved Characters, so one possible solution is to percent encode any commas that appear in your JSON query string. The other option is to switch the way Falcon handles commas in a query string by setting the auto_parse_qs_csv to False on an instance of falcon.API:

api.req_options.auto_parse_qs_csv = False

When auto_parse_qs_csv is set to False, the value of the query string ?c={'a':1,'b':2} will be added to the req.params dictionary as {'c': "{'a':1,'b':2}"}. This lets you consume JSON whether or not the client chooses to escape commas in the request.

How can I handle forward slashes within a route template field?

In Falcon 1.3 we shipped initial support for field converters. We’ve discussed building on this feature to support consuming multiple path segments ala Flask. This work is currently planned for 2.0.

In the meantime, the workaround is to percent-encode the forward slash. If you don’t control the clients and can’t enforce this, you can implement a Falcon middleware component to rewrite the path before it is routed.

How do I adapt my code to default context type changes in Falcon 2.0?

The default request/response context type has been changed from dict to a bare class in Falcon 2.0. Instead of setting dictionary items, you can now simply set attributes on the object:

# Before Falcon 2.0
req.context['cache_backend'] = MyUltraFastCache.connect()

# Falcon 2.0
req.context.cache_backend = MyUltraFastCache.connect()

The new default context type emulates a dict-like mapping interface in a way that context attributes are linked to dict items, i.e. setting an object attribute also sets the corresponding dict item, and vice versa. As a result, existing code will largely work unmodified with Falcon 2.0. Nevertheless, it is recommended to migrate to the new interface as outlined above since the dict-like mapping interface may be removed from the context type in a future release.

Warning

If you need to mix-and-match both approaches under migration, beware that setting attributes such as items or values would obviously shadow the corresponding mapping interface functions.

If an existing project is making extensive use of dictionary contexts, the type can be explicitly overridden back to dict by employing custom request/response types:

class RequestWithDictContext(falcon.Request):
    context_type = dict

class ResponseWithDictContext(falcon.Response):
    context_type = dict

# ...

api = falcon.API(request_type=RequestWithDictContext,
                 response_type=ResponseWithDictContext)

Response Handling

How can I use resp.media with types like datetime?

The default JSON handler for resp.media only supports the objects and types listed in the table documented under json.JSONEncoder. To handle additional types, you can either serialize them beforehand, or create a custom JSON media handler that sets the default param for json.dumps(). When deserializing an incoming request body, you may also wish to implement object_hook for json.loads(). Note, however, that setting the default or object_hook params can negatively impact the performance of (de)serialization.

Does Falcon set Content-Length or do I need to do that explicitly?

Falcon will try to do this for you, based on the value of resp.body, resp.data, or resp.stream_len (whichever is set in the response, checked in that order.)

For dynamically-generated content, you can choose to not set stream_len, in which case Falcon will then leave off the Content-Length header, and hopefully your WSGI server will do the Right Thing™ (assuming you’ve told it to enable keep-alive).

Note

PEP-3333 prohibits apps from setting hop-by-hop headers itself, such as Transfer-Encoding.

Why is an empty response body returned when I raise an instance of HTTPError?

Falcon attempts to serialize the HTTPError instance using its to_json() or to_xml() methods, according to the Accept header in the request. If neither JSON nor XML is acceptable, no response body will be generated. You can override this behavior if needed via set_error_serializer().

I’m setting a response body, but it isn’t getting returned. What’s going on?

Falcon skips processing the response body when, according to the HTTP spec, no body should be returned. If the client sends a HEAD request, the framework will always return an empty body. Falcon will also return an empty body whenever the response status is any of the following:

falcon.HTTP_100
falcon.HTTP_204
falcon.HTTP_416
falcon.HTTP_304

If you have another case where the body isn’t being returned, it’s probably a bug! Let us know so we can help.

By default, Falcon enables the secure cookie attribute. Therefore, if you are testing your app over HTTP (instead of HTTPS), the client will not send the cookie in subsequent requests.

(See also the cookie documentation.)

How can I serve a downloadable file with falcon?

In the on_get() responder method for the resource, you can tell the user agent to download the file by setting the Content-Disposition header. Falcon includes the downloadable_as property to make this easy:

resp.downloadable_as = 'report.pdf'

Can Falcon serve static files?

Falcon makes it easy to efficiently serve static files by simply assigning an open file to resp.stream as demonstrated in the tutorial. You can also serve an entire directory of files via falcon.API.add_static_route(). However, if possible, it is best to serve static files directly from a web server like Nginx, or from a CDN.

Misc.

How do I manage my database connections?

Assuming your database library manages its own connection pool, all you need to do is initialize the client and pass an instance of it into your resource classes. For example, using SQLAlchemy Core:

engine = create_engine('sqlite:///:memory:')
resource = SomeResource(engine)

Then, within SomeResource:

# Read from the DB
result = self._engine.execute(some_table.select())
for row in result:
    # ....
result.close()

# ...

# Write to the DB within a transaction
with self._engine.begin() as connection:
    r1 = connection.execute(some_table.select())
    # ...
    connection.execute(
        some_table.insert(),
        col1=7,
        col2='this is some data'
    )

When using a data access layer, simply pass the engine into your data access objects instead. See also this sample Falcon project that demonstrates using an ORM with Falcon.

You can also create a middleware component to automatically check out database connections for each request, but this can make it harder to track down errors, or to tune for the needs of individual requests.

If you need to transparently handle reconnecting after an error, or for other use cases that may not be supported by your client library, simply encapsulate the client library within a management class that handles all the tricky bits, and pass that around instead.

People usually fall into two camps when it comes to this question. The first camp likes to instantiate a config object and pass that around to the initializers of the resource classes so the data sharing is explicit. The second camp likes to create a config module and import that wherever it’s needed.

With the latter approach, to control when the config is actually loaded, it’s best not to instantiate it at the top level of the config module’s namespace. This avoids any problematic side-effects that may be caused by loading the config whenever Python happens to process the first import of the config module. Instead, consider implementing a function in the module that returns a new or cached config object on demand.

Other than that, it’s pretty much up to you if you want to use the standard library config library or something like aumbry as demonstrated by this falcon example app

(See also the Configuration section of our Complementary Packages wiki page. You may also wish to search PyPI for other options).

How do I test my Falcon app? Can I use pytest?

Falcon’s testing framework supports both unittest and pytest. In fact, the tutorial in the docs provides an excellent introduction to testing Falcon apps with pytest.

(See also: Testing)

© 2019 by Falcon contributors
Licensed under the Apache License, Version 2.0.
https://falcon.readthedocs.io/en/2.0.0/user/faq.html