Falcon adalah kerangka kerja ASGI/WSGI minimalis untuk membangun REST API dan layanan mikro yang sangat penting, dengan fokus pada keandalan, kebenaran, dan kinerja dalam skala besar.
Ketika membangun API HTTP, kerangka kerja lain membebani Anda dengan banyak ketergantungan dan abstraksi yang tidak perlu. Falcon langsung mengikuti perkembangan dengan desain bersih yang mencakup gaya arsitektur HTTP dan REST.
Aplikasi Falcon berfungsi dengan server WSGI atau ASGI mana pun, dan berjalan seperti jagoan di bawah CPython 3.8+ dan PyPy 3.8+.
"Falcon sangat kokoh dan cepat."
"Kami telah menggunakan Falcon sebagai pengganti [kerangka kerja lain] dan kami sangat menyukai kinerjanya (tiga kali lebih cepat) dan ukuran basis kode (setengah dari kode [asli] kami)."
"Saya menyukai #falconframework! Sangat bersih dan sederhana, saya akhirnya memiliki kecepatan dan fleksibilitas yang saya perlukan!"
"Falcon tampak hebat sejauh ini. Saya melakukan tes cepat untuk server kecil milik saya dan ~40% lebih cepat hanya dengan 20 menit kerja."
"Saya merasa seperti akhirnya hanya berbicara tentang HTTP, tanpa ada apa pun di tengahnya. Falcon sepertinya merupakan permintaan backend."
"Kode sumber untuk Falcon sangat bagus, saya hampir lebih memilihnya daripada dokumentasi. Pada dasarnya tidak mungkin salah."
"Kerangka kerja apa lagi yang memiliki dukungan terintegrasi untuk 786 COBA SEKARANG?"
Falcon mencoba melakukan sesedikit mungkin namun tetap efektif.
asyncio
asliApakah Falcon membantu Anda membuat aplikasi keren? Tunjukkan dukungan Anda hari ini dengan donasi satu kali atau dengan menjadi patron. Pendukung mendapatkan perlengkapan keren, peluang untuk mempromosikan merek mereka ke pengembang Python, dan dukungan prioritas.
Terima kasih!
Kesempurnaan pada akhirnya dicapai bukan ketika tidak ada lagi yang dapat ditambahkan, melainkan ketika tidak ada lagi yang dapat dikurangi.
- Antoine de Saint-Exupéry
Kami merancang Falcon untuk mendukung tuntutan kebutuhan layanan mikro berskala besar dan backend aplikasi yang responsif. Falcon melengkapi kerangka web Python yang lebih umum dengan memberikan kinerja, keandalan, dan fleksibilitas sederhana di mana pun Anda membutuhkannya.
Dapat diandalkan. Kami berusaha keras untuk menghindari perubahan yang dapat menyebabkan gangguan, dan ketika kami melakukannya, perubahan tersebut didokumentasikan sepenuhnya dan hanya diperkenalkan (dalam semangat SemVer) dengan peningkatan versi utama. Kode ini diuji secara ketat dengan banyak masukan dan kami memerlukan cakupan 100% setiap saat. Falcon tidak memiliki ketergantungan di luar pustaka standar, sehingga membantu meminimalkan permukaan serangan aplikasi Anda sekaligus menghindari bug transitif dan perubahan yang dapat mengganggu.
Dapat di-debug. Falcon menghindari sihir. Sangat mudah untuk membedakan masukan mana yang menghasilkan keluaran. Pengecualian yang tidak tertangani tidak pernah dienkapsulasi atau ditutupi. Perilaku yang berpotensi mengejutkan, seperti penguraian isi permintaan otomatis, didokumentasikan dengan baik dan dinonaktifkan secara default. Terakhir, terkait kerangka kerja itu sendiri, kami menjaga jalur logika tetap sederhana dan mudah dipahami. Semua ini mempermudah pertimbangan kode dan melakukan debug kasus edge dalam penerapan skala besar.
Cepat. Perangkat keras yang sama, lebih banyak permintaan. Falcon menyelesaikan permintaan secara signifikan lebih cepat dibandingkan kerangka kerja Python populer lainnya seperti Django dan Flask. Untuk peningkatan kecepatan ekstra, Falcon mengkompilasi dirinya sendiri dengan Cython bila tersedia, dan juga bekerja dengan baik dengan PyPy. Sedang mempertimbangkan untuk pindah ke bahasa pemrograman lain? Tolok ukur dengan Falcon+PyPy terlebih dahulu!
Fleksibel. Falcon menyerahkan banyak keputusan dan detail implementasi kepada Anda, pengembang API. Ini memberi Anda banyak kebebasan untuk menyesuaikan dan menyempurnakan penerapan Anda. Hal ini juga membantu Anda memahami aplikasi Anda pada tingkat yang lebih dalam, membuatnya lebih mudah untuk disesuaikan, di-debug, dan difaktorkan ulang dalam jangka panjang. Desain minimalis Falcon memberikan ruang bagi anggota komunitas Python untuk berinovasi secara mandiri pada add-on Falcon dan paket pelengkap.
Falcon digunakan di seluruh dunia oleh semakin banyak organisasi, termasuk:
Jika Anda menggunakan kerangka Falcon untuk komunitas atau proyek komersial, harap pertimbangkan untuk menambahkan informasi Anda ke wiki kami di bawah Siapa yang Menggunakan Falcon?
Sejumlah add-on, templat, dan paket pelengkap Falcon tersedia untuk digunakan dalam proyek Anda. Kami telah mencantumkan beberapa di antaranya di wiki Falcon sebagai titik awal, tetapi Anda mungkin juga ingin mencari sumber tambahan di PyPI.
Komunitas Falconry di Gitter adalah tempat yang bagus untuk mengajukan pertanyaan dan berbagi ide Anda. Anda dapat menemukan kami di elang/pengguna. Kami juga memiliki ruang falconry/dev untuk mendiskusikan desain dan pengembangan kerangka itu sendiri.
Sesuai dengan Kode Etik kami, kami mengharapkan semua orang yang berpartisipasi dalam diskusi komunitas bertindak profesional, dan memberi contoh dalam mendorong diskusi konstruktif. Setiap individu dalam masyarakat bertanggung jawab untuk menciptakan budaya yang positif, konstruktif, dan produktif.
PyPy adalah cara tercepat untuk menjalankan aplikasi Falcon Anda. PyPy3.8+ didukung mulai PyPy v7.3.7+.
$ pip install falcon
Atau, untuk menginstal kandidat beta atau rilis terbaru, jika ada:
$ pip install --pre falcon
Falcon juga mendukung penuh CPython 3.8+.
Falcon versi stabil terbaru dapat diinstal langsung dari PyPI:
$ pip install falcon
Atau, untuk menginstal kandidat beta atau rilis terbaru, jika ada:
$ pip install --pre falcon
Untuk memberikan peningkatan kecepatan ekstra, Falcon secara otomatis mengkompilasi dirinya sendiri dengan Cython di bawah penginstal yang sesuai dengan PEP 517.
Demi kenyamanan Anda, roda yang berisi biner yang telah dikompilasi sebelumnya tersedia dari PyPI untuk sebagian besar platform umum. Meskipun build biner untuk platform pilihan Anda tidak tersedia, pip
akan memilih roda Python murni. Anda juga dapat melakukan sitonisasi Falcon untuk lingkungan Anda; lihat dokumen Instalasi kami untuk informasi lebih lanjut tentang ini dan opsi lanjutan lainnya.
Falcon tidak memerlukan instalasi paket lain apa pun.
Falcon berbicara WSGI (atau ASGI; lihat juga di bawah). Untuk melayani aplikasi Falcon, Anda memerlukan server WSGI. Gunicorn dan uWSGI adalah beberapa yang lebih populer di luar sana, tetapi apa pun yang dapat memuat aplikasi WSGI bisa digunakan.
$ pip install [gunicorn | uwsgi]
Untuk melayani aplikasi Falcon ASGI, Anda memerlukan server ASGI. Uvicorn adalah pilihan populer:
$ pip install uvicorn
Falcon ada di GitHub, membuat kodenya mudah dijelajahi, diunduh, di-fork, dll. Permintaan tarik selalu diterima! Selain itu, harap ingat untuk membintangi proyek tersebut jika itu membuat Anda bahagia. :)
Setelah Anda mengkloning repo atau mengunduh tarball dari GitHub, Anda dapat menginstal Falcon seperti ini:
$ cd falcon
$ pip install .
Atau, jika Anda ingin mengedit kodenya, pertama-tama fork repo utama, kloning fork tersebut ke desktop Anda, lalu jalankan perintah berikut untuk menginstalnya menggunakan tautan simbolis, sehingga ketika Anda mengubah kode, perubahan tersebut akan secara otomatis tersedia untuk Anda. aplikasi Anda tanpa harus menginstal ulang paket:
$ cd falcon
$ FALCON_DISABLE_CYTHON=Y pip install -e .
Anda dapat menguji perubahan pada kerangka Falcon secara manual dengan beralih ke direktori repo yang dikloning dan kemudian menjalankan pytest:
$ cd falcon
$ pip install -r requirements/tests
$ pytest tests
Atau, untuk menjalankan serangkaian pengujian default:
$ pip install tox && tox
Lihat juga file tox.ini untuk daftar lengkap lingkungan yang tersedia.
Dokumen dalam basis kode Falcon cukup luas, dan kami menyarankan agar REPL tetap berjalan sambil mempelajari kerangka kerja sehingga Anda dapat menanyakan berbagai modul dan kelas saat Anda memiliki pertanyaan.
Dokumen online tersedia di: https://falcon.readthedocs.io
Anda dapat membuat dokumen yang sama secara lokal sebagai berikut:
$ pip install tox && tox -e docs
Setelah dokumen dibuat, Anda dapat melihatnya dengan membuka halaman indeks berikut di browser Anda. Di OS X sesederhana:
$ buka dokumen/_build/html/index.html
Atau di Linux:
$ xdg-open docs/_build/html/index.html
Berikut adalah contoh sederhana yang dibuat-buat yang menunjukkan cara membuat aplikasi WSGI berbasis Falcon (versi ASGI disertakan di bagian bawah):
# examples/things.py
# Let's get this party started!
from wsgiref . simple_server import make_server
import falcon
# Falcon follows the REST architectural style, meaning (among
# other things) that you think in terms of resources and state
# transitions, which map to HTTP verbs.
class ThingsResource :
def on_get ( self , req , resp ):
"""Handles GET requests"""
resp . status = falcon . HTTP_200 # This is the default status
resp . content_type = falcon . MEDIA_TEXT # Default is JSON, so override
resp . text = ( ' n Two things awe me most, the starry sky '
'above me and the moral law within me. n '
' n '
' ~ Immanuel Kant n n ' )
# falcon.App instances are callable WSGI apps...
# in larger applications the app is created in a separate file
app = falcon . App ()
# Resources are represented by long-lived class instances
things = ThingsResource ()
# things will handle all requests to the '/things' URL path
app . add_route ( '/things' , things )
if __name__ == '__main__' :
with make_server ( '' , 8000 , app ) as httpd :
print ( 'Serving on port 8000...' )
# Serve until process is killed
httpd . serve_forever ()
Anda dapat menjalankan contoh di atas secara langsung menggunakan server wsgiref yang disertakan:
$ pip install falcon
$ python things.py
Kemudian, di terminal lain:
$ curl localhost:8000/things
Contoh versi ASGI serupa:
# examples/things_asgi.py
import falcon
import falcon . asgi
# Falcon follows the REST architectural style, meaning (among
# other things) that you think in terms of resources and state
# transitions, which map to HTTP verbs.
class ThingsResource :
async def on_get ( self , req , resp ):
"""Handles GET requests"""
resp . status = falcon . HTTP_200 # This is the default status
resp . content_type = falcon . MEDIA_TEXT # Default is JSON, so override
resp . text = ( ' n Two things awe me most, the starry sky '
'above me and the moral law within me. n '
' n '
' ~ Immanuel Kant n n ' )
# falcon.asgi.App instances are callable ASGI apps...
# in larger applications the app is created in a separate file
app = falcon . asgi . App ()
# Resources are represented by long-lived class instances
things = ThingsResource ()
# things will handle all requests to the '/things' URL path
app . add_route ( '/things' , things )
Anda dapat menjalankan versi ASGI dengan uvicorn atau server ASGI lainnya:
$ pip install falcon uvicorn
$ uvicorn things_asgi:app
Berikut adalah contoh yang lebih mendalam yang menunjukkan pembacaan header dan parameter kueri, penanganan kesalahan, dan bekerja dengan badan permintaan dan respons. Perhatikan bahwa contoh ini mengasumsikan bahwa paket permintaan telah diinstal.
(Untuk aplikasi ASGI yang setara, lihat: Contoh yang Lebih Kompleks (ASGI)).
# examples/things_advanced.py
import json
import logging
import uuid
from wsgiref import simple_server
import falcon
import requests
class StorageEngine :
def get_things ( self , marker , limit ):
return [{ 'id' : str ( uuid . uuid4 ()), 'color' : 'green' }]
def add_thing ( self , thing ):
thing [ 'id' ] = str ( uuid . uuid4 ())
return thing
class StorageError ( Exception ):
@ staticmethod
def handle ( ex , req , resp , params ):
# TODO: Log the error, clean up, etc. before raising
raise falcon . HTTPInternalServerError ()
class SinkAdapter :
engines = {
'ddg' : 'https://duckduckgo.com' ,
'y' : 'https://search.yahoo.com/search' ,
}
def __call__ ( self , req , resp , engine ):
url = self . engines [ engine ]
params = { 'q' : req . get_param ( 'q' , True )}
result = requests . get ( url , params = params )
resp . status = str ( result . status_code ) + ' ' + result . reason
resp . content_type = result . headers [ 'content-type' ]
resp . text = result . text
class AuthMiddleware :
def process_request ( self , req , resp ):
token = req . get_header ( 'Authorization' )
account_id = req . get_header ( 'Account-ID' )
challenges = [ 'Token type="Fernet"' ]
if token is None :
description = ( 'Please provide an auth token '
'as part of the request.' )
raise falcon . HTTPUnauthorized ( title = 'Auth token required' ,
description = description ,
challenges = challenges ,
href = 'http://docs.example.com/auth' )
if not self . _token_is_valid ( token , account_id ):
description = ( 'The provided auth token is not valid. '
'Please request a new token and try again.' )
raise falcon . HTTPUnauthorized ( title = 'Authentication required' ,
description = description ,
challenges = challenges ,
href = 'http://docs.example.com/auth' )
def _token_is_valid ( self , token , account_id ):
return True # Suuuuuure it's valid...
class RequireJSON :
def process_request ( self , req , resp ):
if not req . client_accepts_json :
raise falcon . HTTPNotAcceptable (
description = 'This API only supports responses encoded as JSON.' ,
href = 'http://docs.examples.com/api/json' )
if req . method in ( 'POST' , 'PUT' ):
if 'application/json' not in req . content_type :
raise falcon . HTTPUnsupportedMediaType (
title = 'This API only supports requests encoded as JSON.' ,
href = 'http://docs.examples.com/api/json' )
class JSONTranslator :
# NOTE: Normally you would simply use req.media and resp.media for
# this particular use case; this example serves only to illustrate
# what is possible.
def process_request ( self , req , resp ):
# req.stream corresponds to the WSGI wsgi.input environ variable,
# and allows you to read bytes from the request body.
#
# See also: PEP 3333
if req . content_length in ( None , 0 ):
# Nothing to do
return
body = req . stream . read ()
if not body :
raise falcon . HTTPBadRequest ( title = 'Empty request body' ,
description = 'A valid JSON document is required.' )
try :
req . context . doc = json . loads ( body . decode ( 'utf-8' ))
except ( ValueError , UnicodeDecodeError ):
description = ( 'Could not decode the request body. The '
'JSON was incorrect or not encoded as '
'UTF-8.' )
raise falcon . HTTPBadRequest ( title = 'Malformed JSON' ,
description = description )
def process_response ( self , req , resp , resource , req_succeeded ):
if not hasattr ( resp . context , 'result' ):
return
resp . text = json . dumps ( resp . context . result )
def max_body ( limit ):
def hook ( req , resp , resource , params ):
length = req . content_length
if length is not None and length > limit :
msg = ( 'The size of the request is too large. The body must not '
'exceed ' + str ( limit ) + ' bytes in length.' )
raise falcon . HTTPContentTooLarge (
title = 'Request body is too large' , description = msg )
return hook
class ThingsResource :
def __init__ ( self , db ):
self . db = db
self . logger = logging . getLogger ( 'thingsapp.' + __name__ )
def on_get ( self , req , resp , user_id ):
marker = req . get_param ( 'marker' ) or ''
limit = req . get_param_as_int ( 'limit' ) or 50
try :
result = self . db . get_things ( marker , limit )
except Exception as ex :
self . logger . error ( ex )
description = ( 'Aliens have attacked our base! We will '
'be back as soon as we fight them off. '
'We appreciate your patience.' )
raise falcon . HTTPServiceUnavailable (
title = 'Service Outage' ,
description = description ,
retry_after = 30 )
# NOTE: Normally you would use resp.media for this sort of thing;
# this example serves only to demonstrate how the context can be
# used to pass arbitrary values between middleware components,
# hooks, and resources.
resp . context . result = result
resp . set_header ( 'Powered-By' , 'Falcon' )
resp . status = falcon . HTTP_200
@ falcon . before ( max_body ( 64 * 1024 ))
def on_post ( self , req , resp , user_id ):
try :
doc = req . context . doc
except AttributeError :
raise falcon . HTTPBadRequest (
title = 'Missing thing' ,
description = 'A thing must be submitted in the request body.' )
proper_thing = self . db . add_thing ( doc )
resp . status = falcon . HTTP_201
resp . location = '/%s/things/%s' % ( user_id , proper_thing [ 'id' ])
# Configure your WSGI server to load "things.app" (app is a WSGI callable)
app = falcon . App ( middleware = [
AuthMiddleware (),
RequireJSON (),
JSONTranslator (),
])
db = StorageEngine ()
things = ThingsResource ( db )
app . add_route ( '/{user_id}/things' , things )
# If a responder ever raises an instance of StorageError, pass control to
# the given handler.
app . add_error_handler ( StorageError , StorageError . handle )
# Proxy some things to another service; this example shows how you might
# send parts of an API off to a legacy system that hasn't been upgraded
# yet, or perhaps is a single cluster that all data centers have to share.
sink = SinkAdapter ()
app . add_sink ( sink , r'/search/(?P<engine>ddg|y)Z' )
# Useful for debugging problems in your API; works with pdb.set_trace(). You
# can also use Gunicorn to host your app. Gunicorn can be configured to
# auto-restart workers when it detects a code change, and it also works
# with pdb.
if __name__ == '__main__' :
httpd = simple_server . make_server ( '127.0.0.1' , 8000 , app )
httpd . serve_forever ()
Sekali lagi kode ini menggunakan wsgiref, tetapi Anda juga dapat menjalankan contoh di atas menggunakan server WSGI apa pun, seperti uWSGI atau Gunicorn. Misalnya:
$ pip install requests gunicorn
$ gunicorn things:app
Di Windows Anda dapat menjalankan Gunicorn dan uWSGI melalui WSL, atau Anda dapat mencoba Waitress:
$ pip install requests waitress
$ waitress-serve --port=8000 things:app
Untuk menguji contoh ini, buka terminal lain dan jalankan:
$ http localhost:8000/1/things authorization:custom-token
Anda juga dapat melihat konfigurasi aplikasi dari CLI melalui skrip falcon-inspect-app
yang disertakan dengan kerangka kerja:
falcon-inspect-app things_advanced:app
Berikut versi aplikasi ASGI dari atas. Perhatikan bahwa ia menggunakan paket httpx sebagai pengganti permintaan.
# examples/things_advanced_asgi.py
import json
import logging
import uuid
import falcon
import falcon . asgi
import httpx
class StorageEngine :
async def get_things ( self , marker , limit ):
return [{ 'id' : str ( uuid . uuid4 ()), 'color' : 'green' }]
async def add_thing ( self , thing ):
thing [ 'id' ] = str ( uuid . uuid4 ())
return thing
class StorageError ( Exception ):
@ staticmethod
async def handle ( ex , req , resp , params ):
# TODO: Log the error, clean up, etc. before raising
raise falcon . HTTPInternalServerError ()
class SinkAdapter :
engines = {
'ddg' : 'https://duckduckgo.com' ,
'y' : 'https://search.yahoo.com/search' ,
}
async def __call__ ( self , req , resp , engine ):
url = self . engines [ engine ]
params = { 'q' : req . get_param ( 'q' , True )}
async with httpx . AsyncClient () as client :
result = await client . get ( url , params = params )
resp . status = result . status_code
resp . content_type = result . headers [ 'content-type' ]
resp . text = result . text
class AuthMiddleware :
async def process_request ( self , req , resp ):
token = req . get_header ( 'Authorization' )
account_id = req . get_header ( 'Account-ID' )
challenges = [ 'Token type="Fernet"' ]
if token is None :
description = ( 'Please provide an auth token '
'as part of the request.' )
raise falcon . HTTPUnauthorized ( title = 'Auth token required' ,
description = description ,
challenges = challenges ,
href = 'http://docs.example.com/auth' )
if not self . _token_is_valid ( token , account_id ):
description = ( 'The provided auth token is not valid. '
'Please request a new token and try again.' )
raise falcon . HTTPUnauthorized ( title = 'Authentication required' ,
description = description ,
challenges = challenges ,
href = 'http://docs.example.com/auth' )
def _token_is_valid ( self , token , account_id ):
return True # Suuuuuure it's valid...
class RequireJSON :
async def process_request ( self , req , resp ):
if not req . client_accepts_json :
raise falcon . HTTPNotAcceptable (
description = 'This API only supports responses encoded as JSON.' ,
href = 'http://docs.examples.com/api/json' )
if req . method in ( 'POST' , 'PUT' ):
if 'application/json' not in req . content_type :
raise falcon . HTTPUnsupportedMediaType (
description = 'This API only supports requests encoded as JSON.' ,
href = 'http://docs.examples.com/api/json' )
class JSONTranslator :
# NOTE: Normally you would simply use req.get_media() and resp.media for
# this particular use case; this example serves only to illustrate
# what is possible.
async def process_request ( self , req , resp ):
# NOTE: Test explicitly for 0, since this property could be None in
# the case that the Content-Length header is missing (in which case we
# can't know if there is a body without actually attempting to read
# it from the request stream.)
if req . content_length == 0 :
# Nothing to do
return
body = await req . stream . read ()
if not body :
raise falcon . HTTPBadRequest ( title = 'Empty request body' ,
description = 'A valid JSON document is required.' )
try :
req . context . doc = json . loads ( body . decode ( 'utf-8' ))
except ( ValueError , UnicodeDecodeError ):
description = ( 'Could not decode the request body. The '
'JSON was incorrect or not encoded as '
'UTF-8.' )
raise falcon . HTTPBadRequest ( title = 'Malformed JSON' ,
description = description )
async def process_response ( self , req , resp , resource , req_succeeded ):
if not hasattr ( resp . context , 'result' ):
return
resp . text = json . dumps ( resp . context . result )
def max_body ( limit ):
async def hook ( req , resp , resource , params ):
length = req . content_length
if length is not None and length > limit :
msg = ( 'The size of the request is too large. The body must not '
'exceed ' + str ( limit ) + ' bytes in length.' )
raise falcon . HTTPContentTooLarge (
title = 'Request body is too large' , description = msg )
return hook
class ThingsResource :
def __init__ ( self , db ):
self . db = db
self . logger = logging . getLogger ( 'thingsapp.' + __name__ )
async def on_get ( self , req , resp , user_id ):
marker = req . get_param ( 'marker' ) or ''
limit = req . get_param_as_int ( 'limit' ) or 50
try :
result = await self . db . get_things ( marker , limit )
except Exception as ex :
self . logger . error ( ex )
description = ( 'Aliens have attacked our base! We will '
'be back as soon as we fight them off. '
'We appreciate your patience.' )
raise falcon . HTTPServiceUnavailable (
title = 'Service Outage' ,
description = description ,
retry_after = 30 )
# NOTE: Normally you would use resp.media for this sort of thing;
# this example serves only to demonstrate how the context can be
# used to pass arbitrary values between middleware components,
# hooks, and resources.
resp . context . result = result
resp . set_header ( 'Powered-By' , 'Falcon' )
resp . status = falcon . HTTP_200
@ falcon . before ( max_body ( 64 * 1024 ))
async def on_post ( self , req , resp , user_id ):
try :
doc = req . context . doc
except AttributeError :
raise falcon . HTTPBadRequest (
title = 'Missing thing' ,
description = 'A thing must be submitted in the request body.' )
proper_thing = await self . db . add_thing ( doc )
resp . status = falcon . HTTP_201
resp . location = '/%s/things/%s' % ( user_id , proper_thing [ 'id' ])
# The app instance is an ASGI callable
app = falcon . asgi . App ( middleware = [
# AuthMiddleware(),
RequireJSON (),
JSONTranslator (),
])
db = StorageEngine ()
things = ThingsResource ( db )
app . add_route ( '/{user_id}/things' , things )
# If a responder ever raises an instance of StorageError, pass control to
# the given handler.
app . add_error_handler ( StorageError , StorageError . handle )
# Proxy some things to another service; this example shows how you might
# send parts of an API off to a legacy system that hasn't been upgraded
# yet, or perhaps is a single cluster that all data centers have to share.
sink = SinkAdapter ()
app . add_sink ( sink , r'/search/(?P<engine>ddg|y)Z' )
Anda dapat menjalankan versi ASGI dengan server ASGI apa pun, seperti uvicorn:
$ pip install falcon httpx uvicorn
$ uvicorn things_advanced_asgi:app
Terima kasih atas minat Anda pada proyek ini! Kami menerima permintaan penarikan dari pengembang dari semua tingkat keahlian. Untuk memulai, cukup fork cabang master di GitHub ke akun pribadi Anda, lalu klon fork tersebut ke lingkungan pengembangan Anda.
Jika Anda ingin berkontribusi namun belum memikirkan apa pun, kami mengundang Anda untuk melihat isu-isu yang tercantum dalam pencapaian kami berikutnya. Jika Anda melihat salah satu yang ingin Anda kerjakan, silakan tinggalkan komentar singkat agar kami tidak berakhir dengan upaya duplikat. Terima kasih sebelumnya!
Harap dicatat bahwa semua kontributor dan pengelola proyek ini tunduk pada Kode Etik kami.
Sebelum mengirimkan permintaan penarikan, pastikan Anda telah menambahkan/memperbarui pengujian yang sesuai (dan semua pengujian yang ada masih lolos dengan perubahan Anda), dan gaya pengkodean Anda mengikuti PEP 8 dan tidak menyebabkan pyflakes mengeluh.
Pesan komit harus diformat menggunakan konvensi AngularJS.
Komentar mengikuti panduan gaya Google, dengan persyaratan tambahan berupa awalan komentar sebaris menggunakan nama panggilan GitHub Anda dan awalan yang sesuai:
Pemelihara inti proyek Falcon adalah:
Jangan ragu untuk menghubungi kami jika Anda memiliki pertanyaan, atau hanya memerlukan sedikit bantuan untuk memulai. Anda dapat menemukan kami di falconry/dev di Gitter.
Lihat juga: KONTRIBUSI.md
Hak Cipta 2013-2024 oleh kontributor individu dan perusahaan sebagaimana tercantum dalam file sumber individual.
Berlisensi di bawah Lisensi Apache, Versi 2.0 ("Lisensi"); Anda tidak boleh menggunakan bagian apa pun dari kerangka Falcon kecuali sesuai dengan Lisensi. Kontributor setuju untuk melisensikan karyanya di bawah Lisensi yang sama. Anda dapat memperoleh salinan Lisensi di http://www.apache.org/licenses/LICENSE-2.0
Kecuali diwajibkan oleh undang-undang yang berlaku atau disetujui secara tertulis, perangkat lunak yang didistribusikan berdasarkan Lisensi didistribusikan berdasarkan DASAR "APA ADANYA", TANPA JAMINAN ATAU KETENTUAN DALAM BENTUK APAPUN, baik tersurat maupun tersirat. Lihat Lisensi untuk bahasa tertentu yang mengatur izin dan batasan berdasarkan Lisensi.