File: faq.rst

package info (click to toggle)
python-falcon 4.0.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,172 kB
  • sloc: python: 33,608; javascript: 92; sh: 50; makefile: 50
file content (1391 lines) | stat: -rw-r--r-- 53,346 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
.. _faq:

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 <https://github.com/falconry/falcon/wiki>`_.

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.

What happens if my responder raises an error?
---------------------------------------------
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.

.. note::
    As of version 3.0, the framework will no longer propagate uncaught
    exceptions to the application server.
    Instead, the default ``Exception`` handler will return an HTTP 500 response
    and log details of the exception to ``wsgi.errors``.

Although providing basic error handlers, Falcon optimizes for the most common
case where resource responders do not raise any errors for valid requests.
With that in mind, writing a high-quality API based on Falcon requires that:

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

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 <https://github.com/falconry/falcon/wiki/Add-on-Catalog>`_ lists
a couple of these projects, but you may also wish to search
`PyPI <https://pypi.python.org/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.

.. _faq_thread_safety:

Is Falcon thread-safe?
----------------------

The Falcon framework is, itself, thread-safe. For example, new
:class:`~falcon.Request` and :class:`~falcon.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.

.. _faq_free_threading:

Can I run Falcon on free-threaded CPython?
------------------------------------------

At the time of this writing, Falcon has not been extensively evaluated without
the GIL yet.

We load-tested the WSGI flavor of the framework via
:class:`~wsgiref.simple_server.WSGIServer` +
:class:`~socketserver.ThreadingMixIn` on
`free-threaded CPython 3.13.0
<https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython>`__
(under ``PYTHON_GIL=0``), and observed no issues that would point toward
Falcon's reliance on the GIL. Thus, we would like to think that Falcon is still
:ref:`thread-safe <faq_thread_safety>` even in free-threaded execution,
but it is too early to provide a definite answer.

If you experimented with free-threading of Falcon or other Python web services,
please :ref:`share your experience <chat>`!

Does Falcon support asyncio?
------------------------------

Starting with version 3.0, the `ASGI <https://asgi.readthedocs.io/en/latest/>`_
flavor of Falcon now proudly supports :any:`asyncio`!
Use the :class:`falcon.asgi.App` class to create an async application, and
serve it via an :ref:`ASGI application server <install_asgi_server>` such as
Uvicorn.

Alternatively, IO-bound WSGI applications can be scaled using the battle-tested
`gevent <http://www.gevent.org/>`_ library via Gunicorn or uWSGI.
`meinheld <https://pypi.org/project/meinheld/>`_ has also been used
successfully by the community to power high-throughput, low-latency WSGI
services.

.. tip::
    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?
------------------------------

The async flavor of Falcon supports the
`ASGI <https://asgi.readthedocs.io/en/latest/>`_ WebSocket protocol.
See also: :ref:`ws`.

WSGI applications might try leveraging
`uWSGI's native WebSocket support <http://uwsgi.readthedocs.io/en/latest/WebSockets.html>`_
or `gevent-websocket's <https://pypi.org/project/gevent-websocket>`_
``GeventWebSocketWorker`` for Gunicorn.

As an option, it may make sense to design WebSocket support as a separate
service due to very different performance characteristics and interaction
patterns, compared to a regular RESTful API. In addition to (obviously!)
Falcon's native ASGI support, a standalone WebSocket service could also be
implemented via Aymeric Augustin's handy
`websockets <https://pypi.python.org/pypi/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) <https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS>`_.
For a public API, implementing CORS in Falcon can be as simple as passing the
``cors_enable`` flag (set to ``True``) when instantiating
:ref:`your application <app>`.

Further CORS customization is possible via :class:`~falcon.CORSMiddleware`
(for more information on managing CORS in Falcon, see also :ref:`cors`).

For even more sophisticated use cases, have a look at Falcon add-ons from the
community, such as `falcon-cors <https://github.com/lwcolton/falcon-cors>`_, or
try one of the generic
`WSGI CORS libraries available on PyPI <https://pypi.python.org/pypi?%3Aaction=search&term=cors&submit=search>`_.
If you use an API gateway, you might also look into what CORS functionality
it provides at that level.

Why is my request with authorization blocked despite ``cors_enable``?
---------------------------------------------------------------------

When you are making a cross-origin request from the browser (or another HTTP
client verifying CORS policy), and the request is authenticated using the
Authorization header, the browser adds ``authorization`` to
Access-Control-Request-Headers in the preflight (``OPTIONS``) request,
however, the actual authorization credentials are omitted at this stage.

If your request authentication/authorization is performed in a
:ref:`middleware <middleware>` component which rejects requests lacking
authorization credentials by raising an instance of :class:`~.HTTPUnauthorized`
(or rendering a 4XX response in another way), a common pitfall is that even an
``OPTIONS`` request (which is lacking authorization as per the above
explanation) yields an error in this manner. As a result of the failed
preflight, the browser chooses not proceed with the main request.

If you have implemented the authorization middleware yourself, you can simply
let ``OPTIONS`` pass through:

.. code:: python

    class MyAuthMiddleware:
        def process_request(self, req, resp):
            # NOTE: Do not authenticate OPTIONS requests.
            if req.method == 'OPTIONS':
                return

            # -- snip --

            # My authorization logic...

Alternatively, if the middleware comes from a third-party library,
it may be more practical to subclass it:

.. code:: python

    class CORSAwareMiddleware(SomeAuthMiddleware):
        def process_request(self, req, resp):
            # NOTE: Do not authenticate OPTIONS requests.
            if req.method != 'OPTIONS':
                super().process_request(req, resp)

In the case middleware in question instead hooks into ``process_resource()``,
you can use a similar treatment.

If you tried the above, and you still suspect the problem lies within Falcon's
:ref:`CORS middleware <cors>`, it might be a bug! :ref:`Let us know <help>` so
we can help.

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 :ref:`Redirection <redirects>`).

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:

.. code:: python

    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 <https://www.python.org/dev/peps/pep-3333/#environ-variables>`_
for a complete list of the variables that are provided via ``environ``.

.. _collection-vs-item-routing:

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 :ref:`this section of the tutorial <tutorial-serving-images>`.)

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

.. code:: python

    class MyResource:
        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


    # -- snip --


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

.. _recommended-route-layout:

What is the recommended way to map related routes to resource classes?
----------------------------------------------------------------------

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:

.. code:: python

    class Ping:

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


    class Game:

        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:

        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


    app = falcon.App()

    # 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)

    app.add_route('/game/ping', Ping())
    app.add_route('/game/{game_id}', Game(game_dao))
    app.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:

.. code:: python

    class Game:

        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"}'


    # -- snip --


    app = falcon.App()

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

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

.. _routing_encoded_slashes:

Why is my URL with percent-encoded forward slashes (``%2F``) routed incorrectly?
--------------------------------------------------------------------------------
This is an unfortunate artifact of the WSGI specification, which offers no
standard means of accessing the "raw" request URL. According to PEP 3333,
`the recommended way to reconstruct a request's URL path
<https://www.python.org/dev/peps/pep-3333/#url-reconstruction>`_ is using the
``PATH_INFO`` CGI variable, which is already presented percent-decoded,
effectively making originally percent-encoded forward slashes (``%2F``)
indistinguishable from others passed verbatim (and intended to separate URI
fields).

Although not standardized, some WSGI servers provide the raw URL as a
non-standard extension; for instance, Gunicorn exposes it as ``RAW_URI``,
uWSGI calls it ``REQUEST_URI``, etc. You can implement a WSGI (or ASGI, see the
discussion below) middleware component to overwrite the request path with the
path component of the raw URL, see more in the following recipe:
:ref:`raw_url_path_recipe`.

In contrast to WSGI, the ASGI specification does define a standard connection
HTTP scope variable name (``raw_path``) for the unmodified HTTP path. However,
it is not mandatory, and some applications servers may be unable to provide
it. Nevertheless, we are exploring the possibility of adding an optional
feature to use this raw path for routing in the ASGI flavor of the framework.

Extensibility
~~~~~~~~~~~~~

How do I use WSGI middleware with Falcon?
-----------------------------------------
Instances of :class:`falcon.App` 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:

.. code:: python

    import my_restful_service
    import some_middleware

    app = some_middleware.DoSomethingFancy(my_restful_service.app)

See also the `WSGI middleware example <https://www.python.org/dev/peps/pep-3333/#middleware-components-that-play-both-sides>`_ 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 :attr:`req.context <falcon.Request.context>` object, as a way of passing
contextual information around:

.. code:: python

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

        # -- snip --

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

    # -- snip --

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

.. _faq_override_404_500_handlers:

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 :class:`~.HTTPRouteNotFound`, which
the framework will in turn render as a 404 response. You can use
:meth:`falcon.App.add_error_handler` to override the default handler for this
exception type (or for its parent type, :class:`~.HTTPNotFound`).
Alternatively, you may be able to configure your web server to transform the
response for you (e.g., using nginx's ``error_page`` directive).

By default, non-system-exiting exceptions that do not inherit from
:class:`~.HTTPError` or :class:`~.HTTPStatus` are handled by Falcon with a
plain HTTP 500 error. To provide your own 500 logic, you can add a custom error
handler for Python's base :class:`Exception` type. This will not affect the
default handlers for :class:`~.HTTPError` and :class:`~.HTTPStatus`.

See :ref:`errors` and the :meth:`falcon.App.add_error_handler` docs for more
details.

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
:attr:`req.context <falcon.Request.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 :attr:`~falcon.Request.stream`, and a workaround
is provided in the form of :attr:`~falcon.Request.bounded_stream`.

.. _trailing_slash_in_path:

How does Falcon handle a trailing slash in the request path?
------------------------------------------------------------
If your app sets :attr:`~falcon.RequestOptions.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.

.. warning::

    If :attr:`~falcon.RequestOptions.strip_url_path_trailing_slash` is enabled,
    adding a route with a trailing slash will effectively make it unreachable
    from normal routing (theoretically, it may still be matched by rewriting
    the request path in middleware).

    In this case, routes should be added without a trailing slash (obviously
    except the root path ``'/'``), such as ``'/foo/bar'`` in the example above.

.. note::

    Starting with version 2.0, the default for the
    :attr:`~falcon.RequestOptions.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 and the
:attr:`~falcon.RequestOptions.keep_blank_qs_values` request option is set to
``False`` (the default as of Falcon 2.0+ is ``True``), Falcon will ignore that
parameter.
For example, passing ``'foo'`` or ``'foo='`` will result in the parameter being
ignored.

If you would like to recognize such parameters, the
:attr:`~falcon.RequestOptions.keep_blank_qs_values` request option should be
set to ``True`` (or simply kept at its default value in Falcon 2.0+). Request
options are set globally for each instance of :class:`falcon.App` via the
:attr:`~falcon.App.req_options` property. For example:

.. code:: python

    app.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 ``+``).

.. _access_urlencoded_form:

How can I access POSTed form params?
------------------------------------
By default, Falcon does not consume request bodies. However, a :ref:`media
handler <media>` for the ``application/x-www-form-urlencoded`` content type is
installed by default, thus making the POSTed form available as
:attr:`Request.media <falcon.Request.media>` with zero configuration:

.. code:: python

    import falcon


    class MyResource:
        def on_post(self, req, resp):
            # TODO: Handle the submitted URL-encoded form
            form = req.media

            # NOTE: Falcon chooses the right media handler automatically, but
            #   if we wanted to differentiate from, for instance, JSON, we
            #   could check whether req.content_type == falcon.MEDIA_URLENCODED
            #   or use mimeparse to implement more sophisticated logic.

.. note::
   In prior versions of Falcon, a POSTed URL-encoded form could be automatically
   consumed and merged into :attr:`~falcon.Request.params` by setting the
   :attr:`~falcon.RequestOptions.auto_parse_form_urlencoded` option to ``True``. This
   behavior is still supported in the Falcon 3.x series. However, it has been
   deprecated in favor of :class:`~.media.URLEncodedFormHandler`, and the
   option to merge URL-encoded form data into
   :attr:`~falcon.Request.params` may be removed in a future release.

POSTed form parameters may also be read directly from
:attr:`~falcon.Request.stream` and parsed via
:meth:`falcon.uri.parse_query_string` or :func:`urllib.parse.parse_qs`.

.. _access_multipart_files:

How can I access POSTed files?
------------------------------

If files are ``POST``\ed as part of a :ref:`multipart form <multipart>`, the
default :class:`MultipartFormHandler <falcon.media.MultipartFormHandler>` can
be used to efficiently parse the submitted ``multipart/form-data``
:ref:`request media <media>` by iterating over the multipart
:class:`body parts <falcon.media.multipart.BodyPart>`:

.. code:: python

    for part in req.media:
        # TODO: Do something with the body part
        pass

.. _multipart_cloud_upload:

How can I save POSTed files (from a multipart form) directly to AWS S3?
-----------------------------------------------------------------------

As highlighted in the previous answer dealing with
:ref:`files posted as multipart form <access_multipart_files>`,
:class:`falcon.media.MultipartFormHandler` may be used to iterate over the
uploaded multipart body parts.

The `stream` of a body part is a file-like object implementing the ``read()``
method, making it compatible with ``boto3``\'s
`upload_fileobj <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.upload_fileobj>`_:

.. tab-set::

    .. tab-item:: WSGI
        :sync: wsgi

        .. code:: python

            import boto3

            # -- snip --

            s3 = boto3.client('s3')

            for part in req.media:
                if part.name == 'myfile':
                    s3.upload_fileobj(part.stream, 'mybucket', 'mykey')

    .. tab-item:: ASGI
        :sync: asgi

        .. code:: python

            import aioboto3

            # -- snip --

            session = aioboto3.Session()

            form = await req.get_media()
            async for part in form:
                if part.name == 'myfile':
                    async with session.client('s3') as s3:
                        await s3.upload_fileobj(part.stream, 'mybucket', 'mykey')

        .. note::
            The ASGI snippet requires the
            `aioboto3 <https://pypi.org/project/aioboto3/>`__ async wrapper in
            lieu of ``boto3`` (as the latter only offers a synchronous
            interface at the time of writing).

.. note::
   Falcon is not endorsing any particular cloud service provider, and AWS S3
   and ``boto3`` are referenced here just as a popular example. The same
   pattern can be applied to any storage API that supports streaming directly
   from a file-like object.

How do I parse a nested multipart form?
---------------------------------------
Falcon does not offer official support for parsing nested multipart forms
(i.e., where multiple files for a single field are transmitted using a nested
``multipart/mixed`` part) at this time. The usage is considered deprecated
according to the `living HTML5 standard
<https://html.spec.whatwg.org/multipage/form-control-infrastructure.html>`_ and
`RFC 7578, Section 4.3 <https://tools.ietf.org/html/rfc7578#section-4.3>`_.

.. tip::
    If your app absolutely must deal with such legacy forms, the parser may
    actually be capable of the task. See more in this recipe:
    :ref:`nested-multipart-forms`.

How do I retrieve a JSON value from the query string?
-----------------------------------------------------
To retrieve a JSON-encoded value from the query string, Falcon provides the
:meth:`~falcon.Request.get_param_as_json` method, an example of which is given
below:

.. code:: python

    import falcon


    class LocationResource:

        def on_get(self, req, resp):
            places = {
                'Chandigarh, India': {
                    'lat': 30.692781,
                    'long': 76.740875
                },

                'Ontario, Canada': {
                    'lat': 43.539814,
                    'long': -80.246094
                }
            }

            coordinates = req.get_param_as_json('place')

            place = None
            for (key, value) in places.items():
                if coordinates == value:
                    place = key
                    break

            resp.media = {
                'place': place
            }


    app = falcon.App()
    app.add_route('/locations', LocationResource())

In the example above, ``LocationResource`` expects a query string containing
a JSON-encoded value named ``'place'``. This value can be fetched and
decoded from JSON in a single step with the
:meth:`~falcon.Request.get_param_as_json` method. Given a request URL
such as:

    ``/locations?place={"lat":43.539814,"long":-80.246094}``

The `coordinates` variable will be set to a :class:`dict` as expected.

By default, the :attr:`~falcon.RequestOptions.auto_parse_qs_csv` option is
set to ``False``. The example above assumes this default.

On the other hand, when :attr:`~falcon.RequestOptions.auto_parse_qs_csv` is set
to ``True``, Falcon treats commas in a query string as literal characters
delimiting a comma-separated list. For example, given the query string
``?c=1,2,3``, Falcon will add 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 be
added to ``request.params`` in an unexpected way: ``{'c': ['{"a":1', '"b":2}']}``.

Commas are a reserved character that can be escaped according to
`RFC 3986 - 2.2. Reserved Characters <https://tools.ietf.org/html/rfc3986#section-2.2>`_,
so one possible solution is to percent encode any commas that appear in your
JSON query string.

The other option is to leave
:attr:`~falcon.RequestOptions.auto_parse_qs_csv` disabled and simply use JSON
array syntax in lieu of CSV.

When :attr:`~falcon.RequestOptions.auto_parse_qs_csv` is not enabled, 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 percent-encode
commas in the request. In this case, you can retrieve the raw JSON string
via :meth:`~falcon.Request.get_param`, or use the
:meth:`~falcon.Request.get_param_as_json` convenience method as
demonstrated above.

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

Falcon 4 shipped initial support for
`field converters <http://falcon.readthedocs.io/en/stable/api/routing.html#field-converters>`_
that can match multiple segments. The ``path`` :class:`field converter <~falcon.routing.PathConverter>`
is capable of consuming multiple path segments when placed at the end of the URL template.

In previous versions, you can work around the issue by implementing a Falcon
middleware component to rewrite the path before it is routed. If you control
the clients, you can percent-encode forward slashes inside the field in
question, however, note that pre-processing is unavoidable in order to access
the raw encoded URI too. See also: :ref:`routing_encoded_slashes`

.. _bare_class_context_type:

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:

.. code:: python

   # 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:

.. code:: python

    class RequestWithDictContext(falcon.Request):
        context_type = dict

    class ResponseWithDictContext(falcon.Response):
        context_type = dict

    # -- snip --

    app = falcon.App(request_type=RequestWithDictContext,
                     response_type=ResponseWithDictContext)

Response Handling
~~~~~~~~~~~~~~~~~

When would I use media, data, text, and stream?
-----------------------------------------------

These four attributes are mutually exclusive, you should only set one when
defining your response.

:attr:`resp.media <falcon.Response.media>` is used when you want to use the
Falcon serialization mechanism. Just assign data to the attribute and Falcon
will take care of the rest.

.. code:: python

    class MyResource:
        def on_get(self, req, resp):
            resp.media = {'hello': 'World'}

:attr:`resp.text <falcon.Response.text>` and
:attr:`resp.data <falcon.Response.data>` are very similar, they both allow you
to set the body of the response. The difference being,
:attr:`~falcon.Response.text` takes a string, and :attr:`~falcon.Response.data`
takes bytes.

.. code:: python

    class MyResource:
        def on_get(self, req, resp):
            resp.text = json.dumps({'hello': 'World'})

        def on_post(self, req, resp):
            resp.data = b'{"hello": "World"}'

:attr:`resp.stream <falcon.Response.stream>` allows you to set a generator that
yields bytes, or a file-like object with a ``read()`` method that returns
bytes. In the case of a file-like object, the framework will call ``read()``
until the stream is exhausted.

.. code:: python

    class MyResource:
        def on_get(self, req, resp):
            resp.stream = open('myfile.json', mode='rb')

See also the :ref:`outputting_csv_recipe` recipe for an example of using
:attr:`resp.stream <falcon.Response.stream>` with a generator.

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

The default JSON handler for :attr:`resp.media <falcon.Response.media>` only
supports the objects and types listed in the table documented under
:any:`json.JSONEncoder`.

To handle additional types in JSON, you can either serialize them beforehand,
or create a custom JSON media handler that sets the `default` param for
:func:`json.dumps`. When deserializing an incoming request body, you may also
wish to implement `object_hook` for :func:`json.loads`. Note, however, that
setting the `default` or `object_hook` params can negatively impact the
performance of (de)serialization.

If you use an alternative JSON library, you might also look whether it provides
support for additional data types. For instance, the popular ``orjson`` opts to
automatically serialize :mod:`dataclasses`, :mod:`enums <enum>`,
:class:`~datetime.datetime` objects, etc.

Furthermore, different Internet media types such as YAML,
:class:`msgpack <falcon.media.MessagePackHandler>`, etc might support more data
types than JSON, either as part of the respective (de)serialization format, or
via custom type extensions.

.. seealso:: See :ref:`custom-media-json-encoder` for an example on how to
    use a custom json encoder.

.. note:: When testing an application employing a custom JSON encoder, bear in
    mind that :class:`~.testing.TestClient` is decoupled from the app, and it
    simulates requests as if they were performed by a third-party client (just
    sans network). Therefore, passing the **json** parameter to
    :ref:`simulate_* <testing_standalone_methods>` methods will effectively
    use the stdlib's :func:`json.dumps`. If you want to serialize custom
    objects for testing, you will need to dump them into a string yourself, and
    pass it using the **body** parameter instead (accompanied by the
    ``application/json`` content type header).

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
:attr:`resp.text <falcon.Response.text>`,
:attr:`resp.data <falcon.Response.data>` or
:attr:`resp.media <falcon.Response.media>` (whichever is set in the response,
checked in that order).

For dynamically-generated content, you can choose to not set
:attr:`~falcon.Response.content_length`, 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 the server to enable keep-alive, it may
choose to use chunked encoding).

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

Similar to WSGI, the `ASGI HTTP connection scope
<https://asgi.readthedocs.io/en/latest/specs/www.html#http-connection-scope>`_
specification states that responses without Content-Length "may be chunked as
the server sees fit".

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

Falcon attempts to serialize the :class:`~falcon.HTTPError` instance using its
:meth:`~falcon.HTTPError.to_json` or :meth:`~falcon.HTTPError.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 :meth:`~falcon.App.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! :ref:`Let us know <help>` so we can help.

I'm setting a cookie, but it isn't being returned in subsequent requests.
-------------------------------------------------------------------------
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 :ref:`cookie documentation <cookie-secure-attribute>`.)

.. _serve-downloadable-as:

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 :attr:`~falcon.Response.downloadable_as` property to make this
easy:

.. code:: python

    resp.downloadable_as = 'report.pdf'

See also the :ref:`outputting_csv_recipe` recipe for a more involved example of
dynamically generated downloadable content.

.. _faq_header_names_lowercase:

Why is Falcon changing my header names to lowercase?
----------------------------------------------------

Falcon always lowercases header names before storing them in the internal
:class:`Response <falcon.Response>` structures in order to make the response
header handling straightforward and performant, as header name lookup can be
done using a simple ``dict``. Since HTTP headers are case insensitive, this
optimization should normally not affect your API consumers.

In the unlikely case you absolutely must deal with non-conformant HTTP clients
expecting a specific header name capitalization, see this recipe how to
override header names using generic WSGI middleware:
:ref:`capitalizing_response_headers`.

Note that this question only applies to the WSGI flavor of Falcon. The
`ASGI HTTP scope specification
<https://asgi.readthedocs.io/en/latest/specs/www.html#response-start-send-event>`_
requires HTTP header names to be lowercased.

Furthermore, the HTTP2 standard also mandates that header field names MUST be
converted to lowercase (see `RFC 7540, Section 8.1.2
<https://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2>`_).

.. _faq_static_files:

Can Falcon serve static files?
------------------------------

Falcon makes it easy to efficiently serve static files by simply assigning an
open file to ``resp.stream`` :ref:`as demonstrated in the tutorial
<tutorial-serving-images>`. You can also serve an entire directory of files via
:meth:`falcon.App.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:

.. code:: python

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

Then, within ``SomeResource``:

.. code:: python

    # Read from the DB
    with self._engine.connect() as connection:
        result = connection.execute(some_table.select())
    for row in result:
        # TODO: Do something with each row

    result.close()

    # -- snip --

    # Write to the DB within a transaction
    with self._engine.begin() as connection:
        r1 = connection.execute(some_table.select())

        # -- snip --

        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 <https://github.com/jmvrbanac/falcon-example>`_
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.

If you are interested in the middleware approach, the
`falcon-sqla <https://github.com/vytas7/falcon-sqla>`__ library can be used to
automatically check out and close SQLAlchemy connections that way (although it
also supports the explicit context manager pattern).

How do I manage my database connections with ASGI?
--------------------------------------------------

This example is similar to the above one, but it uses ASGI lifecycle hooks
to set up a connection pool, and to dispose it at the end of the application.
The example uses `psycopg <https://www.psycopg.org/psycopg3/docs/api/index.html>`_
to connect to a PostgreSQL database, but a similar pattern may be adapted to
other asynchronous database libraries.

.. code:: python

    import psycopg_pool

    url = 'postgresql://scott:tiger@127.0.0.1:5432/test'

    class AsyncPoolMiddleware:
        def __init__(self):
            self._pool = None

        async def process_startup(self, scope, event):
            self._pool = psycopg_pool.AsyncConnectionPool(url)
            await self._pool.wait()  # created the pooled connections

        async def process_shutdown(self, scope, event):
            if self._pool:
                await self._pool.close()

        async def process_request(self, req, resp):
            req.context.pool = self._pool

            try:
                req.context.conn = await self._pool.getconn()
            except Exception:
                req.context.conn = None
                raise

        async def process_response(self, req, resp, resource, req_succeeded):
            if req.context.conn:
                await self._pool.putconn(req.context.conn)

Then, an example resource may use the connection or the pool:

.. code:: python

    class Numbers:
        async def on_get(self, req, resp):
            # This endpoint uses the connection created for the request by the Middleware
            async with req.context.conn.cursor() as cur:
                await cur.execute('SELECT value FROM numbers')
                rows = await cur.fetchall()

            resp.media = [row[0] for row in rows]

        async def on_get_with_pool(self, req, resp):
            # This endpoint uses the pool to acquire a connection
            async with req.context.pool.connection() as conn:
                cur = await conn.execute('SELECT value FROM numbers')
                rows = await cur.fetchall()
                await cur.close()

            resp.media = [row[0] for row in rows]

The application can then be used as

.. code:: python

    from falcon.asgi import App

    app = App(middleware=[AsyncPoolMiddleware()])
    num = Numbers()
    app.add_route('/conn', num)
    app.add_route('/pool', num, suffix='with_pool')

.. _configuration-approaches:

What is the recommended approach for app configuration?
-------------------------------------------------------

When it comes to app configuration, Falcon is not opinionated. You are free to
choose from any of the excellent general-purpose configuration libraries
maintained by the Python community. It’s pretty much up to you if you want to
use the standard library or something like ``aumbry`` as demonstrated by this
`Falcon example app <https://github.com/jmvrbanac/falcon-example/tree/master/example>`_.

(See also the **Configuration** section of our
`Complementary Packages wiki page <https://github.com/falconry/falcon/wiki/Complementary-Packages>`_.
You may also wish to search PyPI for other options).

After choosing a configuration library, the only remaining question is how to
access configuration options throughout your app.

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.

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 <http://falcon.readthedocs.io/en/stable/user/tutorial.html#testing-your-application>`_.

(See also: `Testing <http://falcon.readthedocs.io/en/stable/api/testing.html>`_)

Can I shut my server down cleanly from the app?
-----------------------------------------------

Normally, the lifetime of an app server is controlled by other means than from
inside the running app, and there is no standardized way for a WSGI or ASGI
framework to shut down the server programmatically.

However, if you need to spin up a real server for testing purposes (such as for
collecting coverage while interacting with other services over the network),
your app server of choice may offer a Python API or hooks that you can
integrate into your app.

For instance, the stdlib's :mod:`wsgiref` server inherits from
:class:`~socketserver.TCPServer`, which can be stopped by calling its
``shutdown()`` method. Just make sure to perform the call from a different
thread (otherwise it may deadlock):

.. code:: python

    import http
    import threading
    import wsgiref.simple_server

    import falcon


    class Shutdown:
        def __init__(self, httpd):
            self._httpd = httpd

        def on_post(self, req, resp):
            thread = threading.Thread(target=self._httpd.shutdown, daemon=True)
            thread.start()

            resp.content_type = falcon.MEDIA_TEXT
            resp.text = 'Shutting down...\n'
            resp.status = http.HTTPStatus.ACCEPTED


    with wsgiref.simple_server.make_server('', 8000, app := falcon.App()) as httpd:
        app.add_route('/shutdown', Shutdown(httpd))
        print('Serving on port 8000, POST to /shutdown to stop...')
        httpd.serve_forever()

.. warning::
   While ``wsgiref.simple_server`` is handy for integration testing, it builds
   upon :mod:`http.server`, which is not recommended for production. (See
   :ref:`install` on how to install a production-ready WSGI or ASGI server.)

How can I set cookies when simulating requests?
-----------------------------------------------

The easiest way is to simply pass the ``cookies`` parameter into
``simulate_request``. Here is an example:

.. code:: python

    import falcon
    import falcon.testing
    import pytest

    class TastyCookies:

        def on_get(self, req, resp):
            resp.media = {'cookies': req.cookies}


    @pytest.fixture
    def client():
        app = falcon.App()
        app.add_route('/cookies', TastyCookies())

        return falcon.testing.TestClient(app)


    def test_cookies(client):
        resp = client.simulate_get('/cookies', cookies={'cookie': 'cookie value'})

        assert resp.json == {'cookies': {'cookie': 'cookie value'}}


Alternatively, you can set the Cookie header directly as demonstrated in this version of ``test_cookies()``

.. code:: python

    def test_cookies(client):
        resp = client.simulate_get('/cookies', headers={'Cookie': 'xxx=yyy'})

        assert resp.json == {'cookies': {'xxx': 'yyy'}}

To include multiple values, simply use ``"; "`` to separate each name-value
pair. For example, if you were to pass ``{'Cookie': 'xxx=yyy; hello=world'}``,
you would get ``{'cookies': {'xxx': 'yyy', 'hello': 'world'}}``.

Why do I see no error tracebacks in my ASGI application?
--------------------------------------------------------

When using Falcon with an ASGI server like Uvicorn,
you might notice that server errors do not include any traceback by default.
This behavior differs from WSGI, where the PEP-3333 specification defines the
`wsgi.errors <https://peps.python.org/pep-3333/#environ-variables>`__ stream
(which Falcon utilizes to log unhandled
:class:`internal server errors <falcon.HTTPInternalServerError>`).

Since there is no standardized way to log errors back to the ASGI server,
the framework simply opts to log them using the ``falcon``
:class:`logger <logging.Logger>`.

The easiest way to get started is configuring the root logger via
:func:`logging.basicConfig`:

.. code:: python

    import logging

    import falcon
    import falcon.asgi

    logging.basicConfig(
        format="%(asctime)s [%(levelname)s] %(message)s", level=logging.INFO)


    class FaultyResource:
        async def on_get(self, req, resp):
            raise ValueError('foo')


    app = falcon.asgi.App()
    app.add_route('/things', FaultyResource())

By adding the above logging configuration, you should now see tracebacks logged
to :any:`stderr <sys.stderr>` when accessing ``/things``.

For additional details on this topic,
please refer to :ref:`debugging_asgi_applications`.