diff --git a/src/.vuepress/locales/abstract/locale_abstract_ja.js b/src/.vuepress/locales/abstract/locale_abstract_ja.js index 0416c60b48..f35b482412 100644 --- a/src/.vuepress/locales/abstract/locale_abstract_ja.js +++ b/src/.vuepress/locales/abstract/locale_abstract_ja.js @@ -1,7 +1,7 @@ module.exports = { - lang: "ja-JA", - title: "Sanic フレームワーク", - current: "現在のバージョン:21.12", - description: - "SanicはPython3.7以上で書かれており、処理速度が速いWebサーバーとウェブフレームワークです。Python 3.5で追加された非同期/待機構文の使用が可能になり、コードがノンブロッキングでスピーディーになります。", + lang: "ja-JA", + title: "Sanic フレームワーク", + current: "現在のバージョン:22.12", + description: + "SanicはPython3.7以上で書かれており、処理速度が速いWebサーバーとウェブフレームワークです。Python 3.5で追加された非同期/待機構文の使用が可能になり、コードがノンブロッキングでスピーディーになります。", }; diff --git a/src/.vuepress/locales/details/locale_detail_ja.js b/src/.vuepress/locales/details/locale_detail_ja.js index eaa9bf56e4..678b65195e 100644 --- a/src/.vuepress/locales/details/locale_detail_ja.js +++ b/src/.vuepress/locales/details/locale_detail_ja.js @@ -1,13 +1,11 @@ const sidebar_ja = require("./sidebar/sidebar_ja"); const nav_ja = require("./nav/nav_ja"); - module.exports = { - selectText: "Languages", - label: "日本語", - editLinkText: "Edit this page on GitHub", - helpText: "Help", - algolia: {}, - current: "現在のバージョン21.12", - nav: nav_ja, - sidebar: sidebar_ja, + selectText: "言語", + label: "日本語", + editLinkText: "このページをGitHubで編集", + helpText: "Help", + algolia: {}, + nav: nav_ja, + sidebar: sidebar_ja, }; diff --git a/src/.vuepress/locales/details/nav/nav_ja.js b/src/.vuepress/locales/details/nav/nav_ja.js index 1f3b0cef68..953dabccab 100644 --- a/src/.vuepress/locales/details/nav/nav_ja.js +++ b/src/.vuepress/locales/details/nav/nav_ja.js @@ -1,97 +1,105 @@ module.exports = [ - { - text: "Home", - link: "/ja/", - }, - // { text: "Announcements", link: "/announcements" }, - { - text: "Docs", - items: [ - { - text: "ユーザーガイド", - items: [ - { - text: "ジェネラル", - link: "/ja/guide/getting-started.md", - }, - { - text: "ベーシック", - link: "/ja/guide/basics/app.md", - }, - { - text: "アドバンス", - link: "/ja/guide/advanced/class-based-views.md", - }, - { - text: "ベストプラクティス", - link: "/ja/guide/best-practices/blueprints.md", - }, - { - text: "実行とデプロイ", - link: "/ja/guide/deployment/configuration.md", - }, - { - text: "どうやって。。。", - link: "/ja/guide/how-to/toc.md", - }, - ], - }, - { - text: "公式プラグイン", - items: [ - { - text: "sanic拡張", - link: "/ja/plugins/sanic-ext/getting-started.md", - }, - { - text: "Sanic テスト", - link: "/ja/plugins/sanic-testing/testing.md", - }, - ], - }, - { - text: "APIドキュメント", - items: [ - { - text: "APIドキュメントを見る", - link: "https://sanic.readthedocs.io", - }, - ], - }, - { - text: "非政府組織ドキュメント", - items: [ - { - text: "ポリシー", - link: "/ja/org/policies.md", - }, - { - text: "S.C.O.P.E.", - link: "/ja/org/scope.md", - }, - ], - }, - ], - }, - { - text: "コミュニティー", - items: [ - { - text: "Forums", - link: "https://community.sanicframework.org/", - }, - { - text: "Discord", - link: "https://discord.gg/FARQzAEMAA", - }, - { - text: "Twitter", - link: "https://twitter.com/sanicframework", - }, - { - text: "Sponsorship", - link: "https://opencollective.com/sanic-org/", - }, - ], - }, + { + text: "Home", + link: "/ja/", + }, + // { text: "Announcements", link: "/announcements" }, + { + text: "ドキュメント", + items: [ + { + text: "ユーザーガイド", + items: [ + { + text: "全般", + link: "/ja/guide/getting-started.md", + }, + { + text: "ベーシック", + link: "/ja/guide/basics/app.md", + }, + { + text: "アドバンス", + link: "/ja/guide/advanced/class-based-views.md", + }, + { + text: "ベストプラクティス", + link: "/ja/guide/best-practices/blueprints.md", + }, + { + text: "実行とデプロイ", + link: "/ja/guide/deployment/configuration.md", + }, + { + text: "ハウツー集", + link: "/ja/guide/how-to/toc.md", + }, + { + text: "最新のリリースノート", + link: "/ja/guide/release-notes/v22.12.md", + }, + ], + }, + { + text: "公式プラグイン", + items: [ + { + text: "Sanic Extensions", + link: "/ja/plugins/sanic-ext/getting-started.md", + }, + { + text: "Sanic Testing", + link: "/ja/plugins/sanic-testing/getting-started.md", + }, + ], + }, + { + text: "APIドキュメント", + items: [ + { + text: "APIドキュメントを見る", + link: "https://sanic.readthedocs.io", + }, + ], + }, + { + text: "組織ドキュメント", + items: [ + { + text: "機能リクエスト", + link: "/en/org/feature_requests.md", + }, + { + text: "ポリシー", + link: "/ja/org/policies.md", + }, + { + text: "S.C.O.P.E.", + link: "/ja/org/scope.md", + }, + ], + }, + ], + }, + { + text: "コミュニティー", + items: [ + { + text: "フォーラム", + link: "https://community.sanicframework.org/", + }, + { + text: "Discord", + link: "https://discord.gg/FARQzAEMAA", + }, + { + text: "Twitter", + link: "https://twitter.com/sanicframework", + }, + { + text: "スポンサー", + link: "https://opencollective.com/sanic-org/", + }, + ], + }, ]; diff --git a/src/.vuepress/locales/details/sidebar/sidebar_ja.js b/src/.vuepress/locales/details/sidebar/sidebar_ja.js index 81e2a02521..1904126111 100644 --- a/src/.vuepress/locales/details/sidebar/sidebar_ja.js +++ b/src/.vuepress/locales/details/sidebar/sidebar_ja.js @@ -1,7 +1,6 @@ -module.exports = { - "/ja/guide/": [ - { - title: "ジェネラル", +const userGuideFull = [ + { + title: "全般", sidebarDepth: 1, children: ["/ja/guide/", "/ja/guide/getting-started.md"], }, @@ -34,7 +33,7 @@ module.exports = { ], }, { - title: "いい練習", + title: "ベストプラクティス", sidebarDepth: 1, children: [ "/ja/guide/best-practices/blueprints.md", @@ -51,14 +50,17 @@ module.exports = { "/ja/guide/deployment/configuration.md", "/ja/guide/deployment/development.md", "/ja/guide/deployment/running.md", + "/ja/guide/deployment/manager.md", + "/ja/guide/deployment/app-loader.md", + "/ja/guide/deployment/inspector.md", // "/guide/deployment/server-choice.md", "/ja/guide/deployment/nginx.md", - // "/guide/deployment/docker.md", + "/ja/guide/deployment/docker.md", // "/guide/deployment/kubernetes.md", ], }, { - title: "どうやって。。。", + title: "ハウツー集", sidebarDepth: 1, children: [ "/ja/guide/how-to/toc.md", @@ -68,7 +70,7 @@ module.exports = { "/ja/guide/how-to/cors.md", // "/guide/how-to/db.md", // "/guide/how-to/decorators.md", - // "/guide/how-to/validtion.md", + // "/guide/how-to/validation.md", // "/guide/how-to/csrf.md", // "/guide/how-to/serialization.md", // "/ja/guide/how-to/sqlalchemy.md", @@ -79,58 +81,29 @@ module.exports = { // "/guide/how-to/websocket-feed.md", // "/guide/how-to/server-sent-events.md", ], - }, - { - title: "リリースノート", - sidebarDepth: 1, - children: [ - "/ja/guide/release-notes/v21.9.md", - "/ja/guide/release-notes/v21.6.md", - "/ja/guide/release-notes/v21.3.md", - ], - }, - { - title: "プラグイン", - sidebarDepth: 1, - children: [ - ["/ja/plugins/sanic-ext/getting-started.md", "Sanic Extensions"], - ["/ja/plugins/sanic-testing/getting-started.md", "Sanic Testing"], - ], - }, - { - title: "組織", - sidebarDepth: 1, - children: ["/ja/org/policies.md", "/ja/org/scope.md"], - }, - ], - - "/ja/plugins/": [ - { - title: "ユーザーガイド", - sidebarDepth: 1, - children: [ - ["/ja/guide/", "General"], - ["/ja/guide/basics/app.md", "Basics"], - ["/ja/guide/advanced/class-based-views.md", "Advanced"], - ["/ja/guide/best-practices/blueprints.md", "Best Practices"], - ["/ja/guide/deployment/configuration.md", "Running & Deploying"], - ["/ja/guide/how-to/toc.md", "How to..."], - ], - }, - { - title: "Sanic拡張", + } +] +const userGuideShort = [ + ["/ja/guide/", "全般"], + ["/ja/guide/basics/app.md", "ベーシック"], + ["/ja/guide/advanced/class-based-views.md", "アドバンス"], + ["/ja/guide/best-practices/blueprints.md", "ベストプラクティス"], + ["/ja/guide/deployment/configuration.md", "実行とデプロイ"], + ["/ja/guide/how-to/toc.md", "ハウツー集"], + ] +const pluginsFull = [ + { + title: "Sanic Extensions", sidebarDepth: 1, children: [ "/ja/plugins/sanic-ext/getting-started.md", { - title: "HTTP グッズ", + title: "HTTP goodies", children: [ "/ja/plugins/sanic-ext/http/methods.md", "/ja/plugins/sanic-ext/http/cors.md", ], }, - "/ja/plugins/sanic-ext/convenience.md", - "/ja/plugins/sanic-ext/injection.md", { title: "OpenAPI", sidebarDepth: 2, @@ -143,51 +116,84 @@ module.exports = { "/ja/plugins/sanic-ext/openapi/security.md", ], }, + "/ja/plugins/sanic-ext/convenience.md", + "/ja/plugins/sanic-ext/templating.md", + "/ja/plugins/sanic-ext/injection.md", "/ja/plugins/sanic-ext/validation.md", + "/ja/plugins/sanic-ext/health-monitor.md", + "/ja/plugins/sanic-ext/logger.md", "/ja/plugins/sanic-ext/configuration.md", + "/ja/plugins/sanic-ext/custom.md", ], - }, - { - title: "Sanic テスト", - sidebarDepth: 1, - children: [ + }, + { + title: "Sanic Testing", + sidebarDepth: 1, + children: [ "/ja/plugins/sanic-testing/getting-started.md", "/ja/plugins/sanic-testing/clients.md", ], - }, - { - title: "組織", - sidebarDepth: 1, - children: ["/ja/org/policies.md", "/ja/org/scope.md"], - }, - ], + } +] +const pluginsShort = [ + ["/ja/plugins/sanic-testing/getting-started.md", "Sanic Testing"], + ["/ja/plugins/sanic-ext/getting-started.md", "Sanic Extensions"], +] +const org = [ + "/ja/org/feature_requests.md", + "/ja/org/policies.md", + "/ja/org/scope.md" + ] +const releaseNotes = [ + { + title: "2022", + sidebarDepth: 2, + children: [ + "/ja/guide/release-notes/v22.12.md", + "/ja/guide/release-notes/v22.9.md", + "/ja/guide/release-notes/v22.6.md", + "/ja/guide/release-notes/v22.3.md", + ] + }, + + { + title: "2021", + sidebarDepth: 2, + children: [ + "/ja/guide/release-notes/v21.12.md", + "/ja/guide/release-notes/v21.9.md", + "/ja/guide/release-notes/v21.6.md", + "/ja/guide/release-notes/v21.3.md", + ] + }, + ] + +module.exports = { + "/ja/guide/": [ + {"title": "ユーザーガイド", children: userGuideFull, collapsable: false}, + {"title": "プラグイン", children: pluginsFull, collapsable: false}, + {"title": "リリースノート", children: releaseNotes}, + {"title": "組織", children: org}, + ], - "/ja/org/": [ - { - title: "ユーザーガイド", - sidebarDepth: 1, - children: [ - ["/ja/guide/", "General"], - ["/ja/guide/basics/app.md", "Basics"], - ["/ja/guide/advanced/class-based-views.md", "Advanced"], - ["/ja/guide/best-practices/blueprints.md", "Best Practices"], - ["/ja/guide/deployment/configuration.md", "Running & Deploying"], - ["/ja/guide/how-to/toc.md", "How to..."], - ], - }, - { - title: "プラグイン", - sidebarDepth: 1, - children: [ - ["/ja/plugins/sanic-ext/getting-started.md", "Sanic Extensions"], - ["/ja/plugins/sanic-testing/getting-started.md", "Sanic Testing"], - ], - }, - { - title: "組織", - sidebarDepth: 1, - collapsable: false, - children: ["/ja/org/policies.md", "/ja/org/scope.md"], - }, - ], + "/ja/guide/release-notes/": [ + {"title": "ユーザーガイド", children: userGuideShort, initialOpenGroupIndex: -1}, + {"title": "プラグイン", children: pluginsShort, initialOpenGroupIndex: -1}, + {"title": "リリースノート", children: releaseNotes, collapsable: false}, + {"title": "組織", children: org}, + ], + + "/ja/plugins/": [ + {"title": "ユーザーガイド", children: userGuideFull, collapsable: false, initialOpenGroupIndex: -1}, + {"title": "プラグイン", children: pluginsFull, collapsable: false}, + {"title": "リリースノート", children: releaseNotes}, + {"title": "組織", children: org}, + ], + + "/ja/org/": [ + {"title": "ユーザーガイド", children: userGuideShort}, + {"title": "プラグイン", children: pluginsShort}, + {"title": "リリースノート", children: releaseNotes}, + {"title": "組織", children: org, collapsable: false}, + ], }; diff --git a/src/ja/README.md b/src/ja/README.md index 3349560424..e17473e517 100644 --- a/src/ja/README.md +++ b/src/ja/README.md @@ -1,13 +1,13 @@ --- home: true -heroImage: https://raw.githubusercontent.com/sanic-org/sanic-assets/master/png/sanic-framework-logo-400x97.png +heroImage: /images/logo.svg heroText: 速く構築。速く動作。 -tagline: 次世代Python webサーバー/フレームワーク -actionText: さあ始めよう → -actionLink: /ja/guide/ +tagline: Webアプリケーションの開発を加速させる +actionText: 始めよう → +actionLink: /ja/guide/getting-started.html features: - title: シンプルで軽量 - details: スマートデフォルトと肥大化のない直感的なAPIを使用し、アプリの構築に直接取り掛かることができます。 + details: 賢いデフォルトと肥大化のない直感的なAPIを使用し、アプリの構築に直接取り掛かることができます。 - title: 自由な発想と柔軟な対応 details: ツールに制限をかけずに構築する方法を構築します。 - title: パフォーマンスとスケーラブル @@ -21,3 +21,262 @@ features: pageClass: landing-page logo: false --- + +## The lightning-fast asynchronous Python web framework + +**With the features and tools you'd expect.
And some you wouldn't believe.** + +:::: tabs +::: tab "Production-grade" + +After installing, Sanic has all the tools you need for a scalable, production-grade server—out of the box! + +Including [full TLS support](#tls-server). + +```python +from sanic import Sanic +from sanic.response import text + +app = Sanic("MyHelloWorldApp") + +@app.get("/") +async def hello_world(request): + return text("Hello, world.") +``` +```sh +sanic path.to.server:app +[2023-01-31 12:34:56 +0000] [999996] [INFO] Sanic v22.12.0 +[2023-01-31 12:34:56 +0000] [999996] [INFO] Goin' Fast @ http://127.0.0.1:8000 +[2023-01-31 12:34:56 +0000] [999996] [INFO] mode: production, single worker +[2023-01-31 12:34:56 +0000] [999996] [INFO] server: sanic, HTTP/1.1 +[2023-01-31 12:34:56 +0000] [999996] [INFO] python: 3.10.9 +[2023-01-31 12:34:56 +0000] [999996] [INFO] platform: SomeOS-9.8.7 +[2023-01-31 12:34:56 +0000] [999996] [INFO] packages: sanic-routing==22.8.0, sanic-testing==22.12.0, sanic-ext==22.12.0 +[2023-01-31 12:34:56 +0000] [999997] [INFO] Sanic Extensions: +[2023-01-31 12:34:56 +0000] [999997] [INFO] > injection [12 dependencies; 7 constants] +[2023-01-31 12:34:56 +0000] [999997] [INFO] > openapi [http://127.0.0.1:8000/docs] +[2023-01-31 12:34:56 +0000] [999997] [INFO] > http +[2023-01-31 12:34:56 +0000] [999997] [INFO] > templating [jinja2==3.1.2] +[2023-01-31 12:34:56 +0000] [999997] [INFO] Starting worker [999997] +``` +::: + +::: tab "TLS server" + +Running Sanic with TLS enabled is as simple as passing it the file paths... +```sh +sanic path.to.server:app --cert=/path/to/bundle.crt --key=/path/to/privkey.pem +``` + +... or the a directory containing `fullchain.pem` and `privkey.pem` + +```sh +sanic path.to.server:app --tls=/path/to/certs +``` + +**Even better**, while you are developing, let Sanic handle setting up local TLS certificates so you can access your site over TLS at [https://localhost:8443](https://localhost:8443) + +```sh +sanic path.to.server:app --dev --auto-tls +``` +::: + +::: tab Websockets + +Up and running with websockets in no time using the [websockets](https://websockets.readthedocs.io) package. +```python +from sanic import Request, Websocket + +@app.websocket("/feed") +async def feed(request: Request, ws: Websocket): + async for msg in ws: + await ws.send(msg) +``` +::: + +::: tab "Static files" + +Serving static files is of course intuitive and easy. Just name an endpoint and either a file or directory that should be served. + +```python +app.static("/", "/path/to/index.html") +app.static("/uploads/", "/path/to/uploads/") +``` + +Moreover, serving a directory has two additional features: automatically serving an index, and automatically serving a file browser. + +---:1 +Sanic can automatically serve `index.html` (or any other named file) as an index page in a directory or its subdirectories. +:--: +```python +app.static( + "/uploads/", + "/path/to/uploads/", + index="index.html" +) +``` +:--- + +And/or, setup Sanic to display a file browser. + +---:1 +![image](../assets/images/directory-view.png) +:--: +```python +app.static( + "/uploads/", + "/path/to/uploads/", + directory_view=True +) +``` +:--- + +::: + +::: tab Lifecycle + +Beginning or ending a route with functionality is as simple as adding a decorator. + +```python +@app.on_request +async def add_key(request): + request.ctx.foo = "bar" + +@app.on_response +async def custom_banner(request, response): + response.headers["X-Foo"] = request.ctx.foo +``` + +Same with server events. + +```python +@app.before_server_start +async def setup_db(app): + app.ctx.db_pool = await db_setup() + +@app.after_server_stop +async def setup_db(app): + await app.ctx.db_pool.shutdown() +``` + +But, Sanic also allows you to tie into a bunch of built-in events (called signals), or create and dispatch your own. + +```python +@app.signal("http.lifecycle.complete") # built-in +async def my_signal_handler(conn_info): + print("Connection has been closed") + +@app.signal("something.happened.ohmy") # custom +async def my_signal_handler(): + print("something happened") + +await app.dispatch("something.happened.ohmy") +``` +::: + +::: tab "Smart error handling" + +Raising errors will intuitively result in proper HTTP errors: + +```python +raise sanic.exceptions.NotFound # Automatically responds with HTTP 404 +``` + +Or, make your own: + +```python +from sanic.exceptions import SanicException + +class TeapotError(SanicException): + status_code = 418 + message = "Sorry, I cannot brew coffee" + +raise TeapotError +``` + +And, when an error does happen, Sanic's beautiful DEV mode error page will help you drill down to the bug quickly. + +![image](../assets/images/error-div-by-zero.png) + +Regardless, Sanic comes with an algorithm that attempts to respond with HTML, JSON, or text-based errors as appropriate. Don't worry, it is super easy to setup and customize your error handling to your exact needs. + +::: + +::: tab "App Inspector" + +Check in on your live, running applications (whether local or remote). +```sh +sanic inspect + + ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ Sanic │ + │ Inspecting @ http://localhost:6457 │ + ├───────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────┤ + │ │ mode: production, single worker │ + │ ▄███ █████ ██ │ server: unknown │ + │ ██ │ python: 3.10.9 │ + │ ▀███████ ███▄ │ platform: SomeOS-9.8.7 + │ ██ │ packages: sanic==22.12.0, sanic-routing==22.8.0, sanic-testing==22.12.0, sanic-ext==22.12.0 │ + │ ████ ████████▀ │ │ + │ │ │ + │ Build Fast. Run Fast. │ │ + └───────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────┘ + + Sanic-Main + pid: 999996 + + Sanic-Server-0-0 + server: True + state: ACKED + pid: 999997 + start_at: 2023-01-31T12:34:56.00000+00:00 + starts: 1 + + Sanic-Inspector-0 + server: False + state: STARTED + pid: 999998 + start_at: 2023-01-31T12:34:56.00000+00:00 + starts: 1 +``` + +And, issue commands like `reload`, `shutdown`, `scale`... + +```sh +sanic inspect scale 4 +``` + +... or even create your own! + +```sh +sanic inspect migrations +``` +::: + +::: tab Extensible +In addition to the tools that Sanic comes with, the officially supported [Sanic Extensions](./plugins/sanic-ext/getting-started.md) provides lots of extra goodies to make development easier. + +- **CORS** protection +- Template rendering with **Jinja** +- **Dependency injection** into route handlers +- OpenAPI documentation with **Redoc** and/or **Swagger** +- Predefined, endpoint-specific response **serializers** +- Request query arguments and body input **validation** +- **Auto create** HEAD, OPTIONS, and TRACE endpoints +- Live **health monitor** +::: + +::: tab "Developer Experience" +Sanic is **built for building**. + +From the moment it is installed, Sanic includes helpful tools to help the developer get their job done. + +- **One server** - Develop locally in DEV mode on the same server that will run your PRODUCTION application +- **Auto reload** - Reload running applications every time you save a Python fil, but also auto-reload **on any arbitrary directory** like HTML template directories +- **Debuggin tools** - Super helpful (and beautiful) [error pages](#smart-error-handling) that help you traverse the trace stack easily +- **Auto TLS** - Running a localhost website with `https` can be difficult, [Sanic makes it easy](#tls-server) +- **Streamlined testing** - Built-in testing capabilities, making it easier for developers to create and run tests, ensuring the quality and reliability of their services +- **Modern Python** - Thoughtful use of type hints to help the developer IDE experience +::: + +:::: diff --git a/src/ja/guide/README.md b/src/ja/guide/README.md index 7d0cb35511..5b6d1293fb 100644 --- a/src/ja/guide/README.md +++ b/src/ja/guide/README.md @@ -6,13 +6,13 @@ pageClass: intro Sanicは、Python 3.7以上のWebサーバーとWebフレームワークで、高速に機能するように書かれています。Python 3.5で追加された非同期/待機構文の使用が可能になり、コードがノンブロッキングでスピーディーになります。 -| | | -|---------|-------------------------------------------------------------------------------------------------------------------------| -| 構築 | [![Build Status][]][1] [![AppVeyor Build Status][]][2] [![Codecov]][3]   | -| ドキュメント | [![Documentation]][4] | -| パッケージ | [![PyPI][]][5] [![PyPI version][]][5] [![PyPI Wheel][]][6] [![Supported implementations][]][6] [![Code style black]][7] | -| サポート | [![Forums][]][8] [![Discord][]][9] [![Awesome Sanic List]][10] | -| ステータス | [![Downloads][]][11] [![Downloads][12]][11] | +| | | +| ------ | ------------------------------------------------------------------------------------------------------------ | +| 構築 | [![Build Status][1]][1] [![AppVeyor Build Status][3]][2] [![Codecov]][3] | +| ドキュメント | [![Documentation]][4] | +| パッケージ | [![PyPI][7]][5] [![PyPI バージョン][9]][5] [![PyPI ホイール][11]][6] [![サポートされている実装][13]][6] [![Code style black]][7] | +| サポート | [![フォーラム][16]][8] [![Discord][18]][9] [![Awesome Sanic List]][10] | +| ステータス | [![ダウンロード][21]][11] [![ダウンロード][23]][11] | ## これは何? @@ -22,14 +22,16 @@ Sanicは、Python 3.7以上のWebサーバーとWebフレームワークで、 しかし、箱から出してすぐにSanicには、本番グレードのWebアプリケーションの作成、展開、拡張に必要なものがすべて付属していることを忘れないでください。:rocket: -## 目的 +## 目標 > 構築、拡張、最終的に拡張が簡単な高性能HTTPサーバーを起動して実行する簡単な方法を提供する。 ## 機能 ---:1 -- 速いウェブサーバーを構築する +### コア + +- **_速い_**ウェブサーバーを構築する - 生産準備完了 - 非常にスケーラブル - ASGI準拠 @@ -37,123 +39,60 @@ Sanicは、Python 3.7以上のWebサーバーとWebフレームワークで、 - コミュニティによって、コミュニティのために :--:1 +### Sanic Extensions [[詳細](../plugins/sanic-ext/getting-started.md)] + +- CORSの保護 +- Jinjaによるテンプレートのレンダリング +- ルートハンドラへの依存性インジェクション +- Redocや Swagger を使用した OpenAPI ドキュメント +- 定義済み、エンドポイント固有のレスポンスシリアライザー +- リクエストのクエリ引数とボディ入力の検証 +- `HEAD`、`OPTIONS`、`TRACE` のエンドポイントの自動作成 + :--- ## スポンサー -確認 [open collective](https://opencollective.com/sanic-org) to learn more about helping to fund Sanic. +Sanicへの資金援助の詳細については、 [open collective](https://opencollective.com/sanic-org) を参照してください。 ## コミュニティーに参加 議論のメインチャンネルは[コミュニティフォーラム](https://community.sanicframework.org/)にあります。ライブディスカッションとチャット用の[Discord Server](https://discord.gg/FARQzAEMAA)もあります。 -Stackoverflow `[sanic]`タグは、プロジェクトのメンテナによって[積極的に監視](https://stackoverflow.com/questions/tagged/sanic)です。 +Stackoverflowの`[sanic]` タグは [積極的に](https://stackoverflow.com/questions/tagged/sanic) プロジェクト管理者によって監視されています。 -## リビューション +## コントリビューション 私たちは常に新しい貢献を喜んでいます。私たちは[始めるために探している人のために良いマークされた問題](https://github.com/sanic-org/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner)、ようこそ[フォーラムの質問/回答/ディスカッション](https://community.sanicframework.org/)。[貢献ガイドライン](https://github.com/sanic-org/sanic/blob/master/CONTRIBUTING.rst)をご覧ください。 -## 私たちは誰 +## 我々について - + -[構築ステータス]: https://travis-ci.com/sanic-org/sanic.svg?branch=master +[1]: https://travis-ci.com/sanic-org/sanic.svg?branch=master [1]: https://travis-ci.com/sanic-org/sanic -[AppVeyorビルドステータス]: https://ci.appveyor.com/api/projects/status/d8pt3ids0ynexi8c/branch/master?svg=true +[3]: https://ci.appveyor.com/api/projects/status/d8pt3ids0ynexi8c/branch/master?svg=true [2]: https://ci.appveyor.com/project/sanic-org/sanic -[Codecov]: https://codecov.io/gh/sanic-org/sanic/branch/master/graph/badge.svg [3]: https://codecov.io/gh/sanic-org/sanic -[ドキュメンテーション]: https://readthedocs.org/projects/sanic/badge/?version=latest [4]: http://sanic.readthedocs.io/en/latest/?badge=latest -[PyPI]: https://img.shields.io/pypi/v/sanic.svg +[7]: https://img.shields.io/pypi/v/sanic.svg [5]: https://pypi.python.org/pypi/sanic/ -[PyPI version]: https://img.shields.io/pypi/pyversions/sanic.svg -[PyPI Wheel]: https://img.shields.io/pypi/wheel/sanic.svg -[6]: https://pypi.python.org/pypi/sanic -[Supported implementations]: https://img.shields.io/pypi/implementation/sanic.svg -[Code style black]: https://img.shields.io/badge/code%20style-black-000000.svg -[7]: https://github.com/ambv/black -[Forums]: https://img.shields.io/badge/forums-community-ff0068.svg -[8]: https://community.sanicframework.org/ -[Discord]: https://img.shields.io/discord/812221182594121728?logo=discord -[9]: https://discord.gg/FARQzAEMAA -[Awesome Sanic List]: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg -[10]: https://github.com/mekicha/awesome-sanic -[Downloads]: https://pepy.tech/badge/sanic/month -[11]: https://pepy.tech/project/sanic -[12]: https://pepy.tech/badge/sanic/week | -| ドキュメント | [![Documentation]][4] | -| パッケージ | [![PyPI][]][5] [![PyPI version][]][5] [![PyPI Wheel][]][6] [![Supported implementations][]][6] [![Code style black]][7] | -| サポート | [![Forums][]][8] [![Discord][]][9] [![Awesome Sanic List]][10] | -| ステータス | [![Downloads][]][11] [![Downloads][12]][11] | - -## これは何? - -まず第一に、水に飛び込む前に、サニックは他のフレームワークとは異なることを知っておく必要があります。 - -その最初の文では、Sanicは**フレームワーク**と**ウェブサーバー**の両方であるため、大きな間違いがあります。展開セクションでは、これについてもう少し話します。 - -しかし、箱から出してすぐにSanicには、本番グレードのWebアプリケーションの作成、展開、拡張に必要なものがすべて付属していることを忘れないでください。:rocket: - -## Goal - -> 構築、拡張、最終的に拡張が簡単な高性能HTTPサーバーを起動して実行する簡単な方法を提供する。 -## Features - ----:1 - -- 速いウェブサーバーを構築する -- 生産準備完了 -- 非常にスケーラブル -- ASGI準拠 -- シンプルで直感的なAPIデザイン -- コミュニティによって、コミュニティのために -:--:1 - -:--- - - - -## スポンサー - -確認 [open collective](https://opencollective.com/sanic-org) to learn more about helping to fund Sanic. - - -## コミュニティーに参加 - -議論のメインチャンネルは[コミュニティフォーラム](https://community.sanicframework.org/)にあります。ライブディスカッションとチャット用の[Discord Server](https://discord.gg/FARQzAEMAA)もあります。 - -Stackoverflow `[sanic]`タグは、プロジェクトのメンテナによって[積極的に監視](https://stackoverflow.com/questions/tagged/sanic)です。 - -## Contribution - -私たちは常に新しい貢献を喜んでいます。私たちは[始めるために探している人のために良いマークされた問題](https://github.com/sanic-org/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner)、ようこそ[フォーラムの質問/回答/ディスカッション](https://community.sanicframework.org/)。[貢献ガイドライン](https://github.com/sanic-org/sanic/blob/master/CONTRIBUTING.rst)をご覧ください。 - -[構築ステータス]: https://travis-ci.com/sanic-org/sanic.svg?branch=master -[1]: https://travis-ci.com/sanic-org/sanic -[AppVeyorビルドステータス]: https://ci.appveyor.com/api/projects/status/d8pt3ids0ynexi8c/branch/master?svg=true -[2]: https://ci.appveyor.com/project/sanic-org/sanic -[Codecov]: https://codecov.io/gh/sanic-org/sanic/branch/master/graph/badge.svg -[3]: https://codecov.io/gh/sanic-org/sanic -[ドキュメンテーション]: https://readthedocs.org/projects/sanic/badge/?version=latest -[4]: http://sanic.readthedocs.io/en/latest/?badge=latest -[PyPI]: https://img.shields.io/pypi/v/sanic.svg +[9]: https://img.shields.io/pypi/pyversions/sanic.svg [5]: https://pypi.python.org/pypi/sanic/ -[PyPI version]: https://img.shields.io/pypi/pyversions/sanic.svg -[PyPI Wheel]: https://img.shields.io/pypi/wheel/sanic.svg +[11]: https://img.shields.io/pypi/wheel/sanic.svg +[6]: https://pypi.python.org/pypi/sanic +[13]: https://img.shields.io/pypi/implementation/sanic.svg [6]: https://pypi.python.org/pypi/sanic -[Supported implementations]: https://img.shields.io/pypi/implementation/sanic.svg -[Code style black]: https://img.shields.io/badge/code%20style-black-000000.svg [7]: https://github.com/ambv/black -[Forums]: https://img.shields.io/badge/forums-community-ff0068.svg +[16]: https://img.shields.io/badge/forums-community-ff0068.svg [8]: https://community.sanicframework.org/ -[Discord]: https://img.shields.io/discord/812221182594121728?logo=discord +[18]: https://img.shields.io/discord/812221182594121728?logo=discord [9]: https://discord.gg/FARQzAEMAA -[Awesome Sanic List]: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg [10]: https://github.com/mekicha/awesome-sanic -[Downloads]: https://pepy.tech/badge/sanic/month +[21]: https://pepy.tech/badge/sanic/month +[11]: https://pepy.tech/project/sanic +[23]: https://pepy.tech/badge/sanic/week [11]: https://pepy.tech/project/sanic -[12]: https://pepy.tech/badge/sanic/week diff --git a/src/ja/guide/advanced/class-based-views.md b/src/ja/guide/advanced/class-based-views.md index 773a6652cf..6b17ca3f39 100644 --- a/src/ja/guide/advanced/class-based-views.md +++ b/src/ja/guide/advanced/class-based-views.md @@ -59,13 +59,13 @@ app.add_route(FooBar.as_view(), "/foobar") ## ビューの定義 -クラスベースのビューは、`HTTPMethodView` をサブクラス化する必要があります。その後、対応するHTTPメソッドの名前でクラスメソッドを実装できます。定義されたメソッドを持たない要求を受信すると、`405: Method not allowed` 応答が生成されます。 +クラスベースのビューは、`HTTPMethodView`のサブクラスである必要があります。その後、対応するHTTPメソッドの名前でクラスメソッドを実装できます。定義されたメソッドを持たない要求を受信すると、`405: Method not allowed`応答が生成されます。 ---:1 -エンドポイントにクラスベースのビューを登録するには、`app.add_route`メソッドが使用されます。最初の引数は、メソッド `as_view` が呼び出された定義されたクラスで、2 番目の引数は URL エンドポイントである必要があります。 +エンドポイントにクラスベースのビューを登録するために、`app.add_route`メソッドが使用できます。最初の引数は、メソッド`as_view`が呼び出された定義済みクラスで、2番目の引数はURLエンドポイントである必要があります。 -利用可能な方法は: +利用可能なメソッドは: - get - post @@ -84,7 +84,7 @@ class SimpleView(HTTPMethodView): def get(self, request): return text("I am get method") - # You can also use async syntax + # 非同期構文も利用可能 async def post(self, request): return text("I am post method") @@ -119,7 +119,7 @@ app.add_route(NameView.as_view(), "/") ## デコレーター -[デコレータセクション](/guide/best-practices/decorators.md)で説明したように、デコレータを使用してエンドポイントに機能を追加する必要があります。 あなたはCBVと二つ選択肢があります。 +[デコレータセクション](/guide/best-practices/decorators.md)で説明したように、デコレータを使用してエンドポイントに機能を追加する必要がある場合があります。 CBVによる二つの選択肢があります: 1. ビュー内の _全ての_ HTTPメソッドに適用する 2. ビュー内のHTTPメソッドに個別に適用する @@ -128,19 +128,19 @@ app.add_route(NameView.as_view(), "/") ---:1 -### すべての方法に適用する +### すべてのメソッドに適用する -クラスにデコレータを追加する場合は、`デコレータ`クラス変数を設定できます。これらは、`as_view`が呼び出されるとクラスに適用されます。 +クラスにデコレータを追加する場合は、`decorators`クラス変数を設定できます。 これらは、`as_view`が呼び出されるとクラスに適用されます。 :--:1 ```python class ViewWithDecorator(HTTPMethodView): decorators = [some_decorator_here] def get(self, request, name): - return text("Hello I have a decorator") + return text("やあ、僕はデコレータを持ってるよ") def post(self, request, name): - return text("Hello I also have a decorator") + return text("やあ、僕もデコレータを持ってるよ") app.add_route(ViewWithDecorator.as_view(), "/url") ``` @@ -158,18 +158,18 @@ class ViewWithSomeDecorator(HTTPMethodView): @staticmethod @some_decorator_here def get(request, name): - return text("Hello I have a decorator") + return text("やあ、僕はデコレータを持ってるよ") def post(self, request, name): - return text("Hello I don"t have any decorators") + return text("やあ、僕はデコレータを持っていないよ") @some_decorator_here def patch(self, request, name): - return text("Hello I have a decorator") + return text("やあ、僕もデコレータを持っているよ") ``` :--- -## URLを作成 +## URLの生成 ---:1 これは、クラス名がエンドポイントの一部であることを除いて、[他のURLの生成](/guide/basics/routing.md#generating-a-url)と同じように機能します。 @@ -183,7 +183,7 @@ def index(request): class SpecialClassView(HTTPMethodView): def get(self, request): - return text("Hello from the Special Class View!") + return text("Special Class Viewからこんにちは!") app.add_route(SpecialClassView.as_view(), "/special_class_view") diff --git a/src/ja/guide/advanced/proxy-headers.md b/src/ja/guide/advanced/proxy-headers.md index 9848992f01..309731616b 100644 --- a/src/ja/guide/advanced/proxy-headers.md +++ b/src/ja/guide/advanced/proxy-headers.md @@ -1,8 +1,8 @@ -# プロキシ構成 +# プロキシ設定 -リバースプロキシサーバー(nginxなど)を使用する場合、`request.ip`の値にはプロキシのIP(通常は`127.0.0.1`が含まれます。ほとんどの場合、これはあなたが望むものではありません。 +リバースプロキシサーバー(nginxなど)を使用する場合、`request.ip`の値にはプロキシのIP(通常は`127.0.0.1`が含まれます。ほとんどの場合、これはあなたが望むもの**ではありません**。 -Sanicは、`request.remote_addr`として利用可能な真のクライアントIPを決定するためにプロキシヘッダーを使用するように構成できます。完全な外部URLは、ヘッダーフィールド_if available_からも構築されます。 +Sanicは、`request.remote_addr`として利用可能な本当のクライアントIPを決定するためにプロキシヘッダーを使用するように構成できます。完全な外部URLは、_使用できれば_ヘッダーフィールドからも構築されます。 ::: ヒント 注意 適切な予防措置がなければ、悪意のあるクライアントはプロキシヘッダーを使用して独自のIPを偽装することができます。このような問題を回避するために、Sanicは明示的に有効になっていない限り、プロキシヘッダーを使用しません。 @@ -17,39 +17,35 @@ Sanicは、`request.remote_addr`として利用可能な真のクライアント - `PROXIES_COUNT` :--:1 ```python -app.config.FORWARDED_SECRET = "super-duper-secret" -app.config.REAL_IP_HEADER = "CF-Connecting-IP" +app.config.FORWARDED_SECRET = "metya-kutya-siikuretto" +app.config.REAL_IP_HEADER = "CF-Setuzoku-IP" app.config.PROXIES_COUNT = 2 ``` :--- -## 転送されたヘッダー +## Forwarded ヘッダー -`Forwarded`ヘッダーを使用するには、信頼できるプロキシサーバーに知られている値に`app.config.FORWARDED_SECRET`を設定する必要があります。この秘密は、特定のプロキシサーバーを安全に識別するために使用されます。 +`Forwarded`ヘッダーを使用するには、信信頼できるプロキシサーバーに設定されている値を`app.config.FORWARDED_SECRET`に設定する必要があります。このシークレットは、特定のプロキシサーバーを安全に識別するために使用されます。 -29 +Sanicはシークレットキーのない要素を無視し、シークレットが設定されていない場合はヘッダーを解析することもありません。 -30 +信頼された転送要素が見つかると、他のすべてのプロキシヘッダは無視されます。クライアントに関する完全な情報をすでに運んでいるからです。 -Sanicは秘密鍵のない要素を無視し、秘密が設定されていない場合、ヘッダーを解析することさえしません。 - -他のすべてのプロキシヘッダーは、クライアントに関する完全な情報をすでに持っているため、信頼できる転送された要素が見つかると無視されます。 - -`Forwarded`ヘッダーの詳細については、関連する[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded)および[Nginx](https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/)の記事をお読みください。 +`Forwarded`ヘッダーの詳細については、関連する[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded)および[Nginx](https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/)の記事を参照してください。 ## 従来のプロキシヘッダー -### IP-Header +### IPヘッダー -プロキシが既知のヘッダーのIPアドレスを転送すると、「REAL_IP_HEADER」設定値でそれが何であるかをSanicに伝えることができます。 +プロキシが既知のヘッダーにIPアドレスを転送するとき`REAL_IP_HEADER`の値を指定すると、Sanicにそれが何かを教えることができます。 ### X-Forwarded-For -このヘッダーには、通常、プロキシの各レイヤーを介したIPアドレスのチェーンが含まれています。`PROXIES_COUNT`を設定すると、クライアントの実際のIPアドレスを取得する深さがSanicに指示されます。この値は、チェーン内のIPアドレスの_expected_数に等しいはずです。 +このヘッダーには、通常、プロキシの各レイヤーを介したIPアドレスのチェーンが含まれています。`PROXIES_COUNT`を設定すると、クライアントの実際のIPアドレスを取得する深さがSanicに指示されます。この値は、チェーン内のIPアドレスの _期待される_ 数に等しいはずです。 -### Other X-headers +### その他のXヘッダー -クライアントIPが次のいずれかの方法で見つかった場合、SanicはURL部分に次のヘッダーを使用します。 +クライアントIPがこれらのメソッドのいずれかで見つかった場合、Sanicは以下のURLパーツのヘッダを使用します: - x-forwarded-proto - x-forwarded-host @@ -57,9 +53,9 @@ Sanicは秘密鍵のない要素を無視し、秘密が設定されていない - x-forwarded-path - x-scheme -## 例えば +## 例 -次の例では、すべての要求はエンドポイントが次のようになります。 +以下の例では、すべてのリクエストはエンドポイントが次のようになると仮定します。 ```python @app.route("/fwd") async def forwarded(request): @@ -76,8 +72,8 @@ async def forwarded(request): ---:1 --- -##### 例えば 1 -FORWARDED_SECRETが設定されていない場合、xヘッダーは尊重されるべきです +##### 例1 +FORWARDED_SECRETが設定されていない場合、Xヘッダは尊重されます。 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -92,7 +88,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "127.0.0.2", "scheme": "ws", @@ -108,8 +104,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### 例えば 2 -FORWARDED_SECRETが設定されました +##### 例2 +FORWARDED_SECRETが設定された場合: ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -125,7 +121,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "[::2]", "scheme": "https", @@ -144,7 +140,7 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### 例えば 3 +##### 例3 空の転送ヘッダー - > Xヘッダーを使用する ```python app.config.PROXIES_COUNT = 1 @@ -160,7 +156,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "127.0.0.2", "scheme": "ws", @@ -176,8 +172,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 4 -Header present but not matching anything +##### 例4 +ヘッダーは存在するのに何も一致しない場合。 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -189,7 +185,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "", "scheme": "http", @@ -203,8 +199,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 5 -Forwarded header present but no matching secret -> use X-headers +##### 例5 +Forwarded ヘッダーは存在するが、一致するシークレットはない場合 -> Xヘッダを使用 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -217,7 +213,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "127.0.0.2", "scheme": "http", @@ -232,8 +228,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 6 -Different formatting and hitting both ends of the header +##### 例6 +フォーマットが異なり、ヘッダーの両端がヒットする場合 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -245,7 +241,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "127.0.0.4", "scheme": "http", @@ -262,8 +258,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 7 -Test escapes (modify this if you see anyone implementing quoted-pairs) +##### 例7 +エスケープをテストする場合(quoted-pairsを実装しているのを見かけたら修正してあげてください)。 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -275,7 +271,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "test", "scheme": "http", @@ -292,8 +288,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 8 -Secret insulated by malformed field #1 +##### 例8 +不正なフィールドによってシークレットが隔離される例 #1 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -305,7 +301,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "test", "scheme": "http", @@ -321,8 +317,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 9 -Secret insulated by malformed field #2 +##### 例9 +不正なフィールドによってシークレットが隔離される例 #2 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -334,7 +330,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "", "scheme": "wss", @@ -350,8 +346,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 10 -Unexpected termination should not lose existing acceptable values +##### 例10 +予期しない終了で、既存の許容可能な値を失うことはありません。 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -363,7 +359,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "", "scheme": "wss", @@ -379,8 +375,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 11 -Field normalization +##### 例11 +フィールドの正規化 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -392,7 +388,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "", "scheme": "wss", @@ -411,8 +407,8 @@ $ curl localhost:8000/fwd \ --- ---:1 -##### Example 12 -Using "by" field as secret +##### 例12 +`by`フィールドをシークレットとして使用する場合。 ```python app.config.PROXIES_COUNT = 1 app.config.REAL_IP_HEADER = "x-real-ip" @@ -424,7 +420,7 @@ $ curl localhost:8000/fwd \ ``` :--:1 ```bash -# curl response +# curlの応答 { "remote_addr": "1.2.3.4", "scheme": "http", diff --git a/src/ja/guide/advanced/signals.md b/src/ja/guide/advanced/signals.md index 359f64a5a4..d8102f3e1d 100644 --- a/src/ja/guide/advanced/signals.md +++ b/src/ja/guide/advanced/signals.md @@ -1,4 +1,4 @@ -# Signals +# シグナル シグナルは、アプリケーションのある部分が別の部分に何かが起こったことを伝える方法を提供します。 @@ -13,17 +13,17 @@ async def handle_registration(request): await request.app.dispatch( "user.registration.created", context={"email": request.json.email} - }) + ) ``` -## signalを追加する +## シグナルを追加する ---:1 信号を追加するためのAPIは、ルートの追加と非常によく似ています。 :--:1 ```python async def my_signal_handler(): - print("something happened") + print("何かが起こった") app.add_signal(my_signal_handler, "something.happened.ohmy") ``` @@ -35,31 +35,48 @@ app.add_signal(my_signal_handler, "something.happened.ohmy") ```python @app.signal("something.happened.ohmy") async def my_signal_handler(): - print("something happened") + print("何かが起こった") ``` :--- ---:1 -信号は設計図で宣言することもできます +シグナルに条件(conditions)が必要な場合は、ハンドラを追加する際に必ず追加してください。 +:--:1 +```python +async def my_signal_handler1(): + print("何かが起こった") +app.add_signal( + my_signal_handler, + "something.happened.ohmy1", + conditions={"some_condition": "value"} +) +@app.signal("something.happened.ohmy2", conditions={"some_condition": "value"}) +async def my_signal_handler2(): + print("何かが起こった") +``` +:--- + +---:1 +シグナルはblueprintsで宣言することもできます。 :--:1 ```python bp = Blueprint("foo") @bp.signal("something.happened.ohmy") async def my_signal_handler(): - print("something happened") + print("何かが起こった") ``` :--- -## signalsを設計する +## ビルトインシグナル -新しい信号を作成することに加えて、Sanic自体からディスパッチされる組み込み信号がいくつかあります。これらの信号は、開発者に要求とサーバーのライフサイクルに機能を追加する機会を増やすために存在します。 - ----:1 -新しいシグナルを作成することに加えて、Sanic自体からディスパッチされる多くの組み込みシグナルがあります。これらのシグナルは、開発者がリクエストとサーバーのライフサイクルに機能を追加する機会を増やすために存在します。 +新しいシグナルを作成することに加えて、Sanic自体からディスパッチされる組み込みシグナルがいくつかあります。 これらのシグナルは、開発者に要求とサーバーのライフサイクルに機能を追加する機会を増やすために存在します。 他のシグナルと同じように、アプリケーションまたはブループリントインスタンスにアタッチできます。 +*Added in v21.9* +---:1 +You can attach them just like any other signal to an application or blueprint instance. :--:1 ```python @@ -72,43 +89,53 @@ async def my_signal_handler(conn_info): これらの信号は、ハンドラーが取る引数、およびアタッチする条件(存在する場合)とともに、利用可能な信号です。 -| イベント名 | 変数 | 条件 | -| -------------------------- | ------------------------------- | --------------------------------------------------------- | -| `http.routing.before` | request | | -| `http.routing.after` | request, route, kwargs, handler | | -| `http.lifecycle.begin` | conn_info | | -| `http.lifecycle.read_head` | head | | -| `http.lifecycle.request` | request | | -| `http.lifecycle.handle` | request | | -| `http.lifecycle.read_body` | body | | -| `http.lifecycle.exception` | request, exception | | -| `http.lifecycle.response` | request, response | | -| `http.lifecycle.send` | data | | -| `http.lifecycle.complete` | conn_info | | -| `http.middleware.before` | request, response | `{"attach_to": "request"}` or `{"attach_to": "response"}` | -| `http.middleware.after` | request, response | `{"attach_to": "request"}` or `{"attach_to": "response"}` | -| `server.init.before` | app, loop | | -| `server.init.after` | app, loop | | -| `server.shutdown.before` | app, loop | | -| `server.shutdown.after` | app, loop | | +| イベント名 | 変数 | 条件 | +| ------------------------ | ------------------------------- | ---------------------------------------------------------- | +| `http.routing.before` | request | | +| `http.routing.after` | request, route, kwargs, handler | | +| `http.handler.before` | request | | +| `http.handler.after` | request | | +| `http.lifycle.begin` | conn_info | | +| `http.lifycle.read_head` | head | | +| `http.lifycle.request` | request | | +| `http.lifycle.handle` | request | | +| `http.lifycle.read_body` | body | | +| `http.lifycle.exception` | request, exception | | +| `http.lifycle.response` | request, response | | +| `http.lifycle.send` | data | | +| `http.lifycle.complete` | conn_info | | +| `http.middleware.before` | request, response | `{"attach_to": "request"}` または `{"attach_to": "response"}` | +| `http.middleware.after` | request, response | `{"attach_to": "request"}` または `{"attach_to": "response"}` | +| `server.exception.report` | app, exception | | +| `server.init.before` | app, loop | | +| `server.init.after` | app, loop | | +| `server.shutdown.before` | app, loop | | +| `server.shutdown.after` | app, loop | | + +Version 22.9 added `http.handler.before` and `http.handler.after`. + +Version 23.6 added `server.exception.report`. ::: new NEW in v21.12 ---:1 -ビルトインシグナルを使いやすくするために、許可されたビルトインをすべて含む `Enum` オブジェクトが用意されています。最近の IDE では、イベント名の完全なリストを文字列として覚えておく必要がないので、これは便利です。 +ビルトインシグナルを使いやすくするために、許可されたビルトインをすべて含む `Enum` オブジェクトが用意されています。 最近の IDE では、イベント名の完全なリストを文字列として覚えておく必要がないので、これは便利です。 +:--:1 + +*Added in v21.12* :--:1 ```python from sanic.signals import Event @app.signal(Event.HTTP_LIFECYCLE_COMPLETE) async def my_signal_handler(conn_info): - print("Connection has been closed") + print("接続は閉じています") ``` :--- ## イベント ---:1 -信号は_event_に基づいています。イベントは、単に次のパターンの文字列です。 +信号は _event_ に基づいています。イベントは、単に次のパターンの文字列です。 :--:1 ``` namespace.reference.action @@ -135,11 +162,13 @@ async def signal_handler(thing): @app.get("/") async def trigger(request): await app.dispatch("foo.bar.baz") - return response.text("Done.") + return response.text("完了。") ``` :--- -許可された型定義の詳細については、[pathパラメータ](../basics/routing.md#path-parameters)をチェックしてください。 +---:1 +シグナルハンドラの実行に加えて、アプリケーションはイベントがトリガーされるのを待つことができます。 +:--:1 ::: 注意 イベントの3番目の部分(「アクション」)のみが動的です。 @@ -151,7 +180,7 @@ async def trigger(request): ### 待つ ---:1 -シグナルハンドラの実行に加えて、アプリケーションはイベントがトリガーされるのを待つことができます。 +アプリケーションは、シグナルハンドラを実行するだけでなく、イベントがトリガーされるのを待つこともできます。 :--:1 ```python await app.event("foo.bar.baz") @@ -159,14 +188,14 @@ await app.event("foo.bar.baz") :--- ---:1 -**大事**: 待つことはブロッキング機能です。したがって、これを[バックグラウンドタスク](../basics/tasks.md)で実行する必要があります。 +**重要**: 待つことはブロッキング機能です。したがって、これを[バックグラウンドタスク](../basics/tasks.md)で実行する必要があります。 :--:1 ```python async def wait_for_event(app): while True: - print("> waiting") + print("> 待機中") await app.event("foo.bar.baz") - print("> event found\n") + print("> イベント発見\n") @app.after_server_start async def after_server_start(app, loop): @@ -186,12 +215,12 @@ await app.event("foo.bar.*") ``` :--- -## Dispatching +## ディスパッチ *将来的には、Sanicは開発者がライフサイクルイベントに参加するのを支援するために、いくつかのイベントを自動的にディスパッチします。* ---:1 -イベントをDispatchすると、2つのことを行います。 +イベントをディスパッチすると、2つのことを行います。 1. イベントで定義されたシグナルハンドラを実行し、 2. イベントが完了するまで「待っている」ことをすべて解決します。 @@ -208,10 +237,10 @@ thing=baz ``` :--- -### Context +### コンテキスト ---:1 -場合によっては、信号ハンドラに余分な情報を渡す必要があるかもしれません。上記の最初の例では、電子メール登録プロセスにユーザーの電子メールアドレスを指定してほしかった。 +場合によっては、信号ハンドラに余分な情報を渡す必要があるかもしれません。例として最初に挙げられるのは、電子メール登録プロセスにユーザーの電子メールアドレスを指定してほしい場合です。 :--:1 ```python @app.signal("user.registration.created") @@ -229,15 +258,15 @@ await app.dispatch( :--- ::: tip FYI -信号はバックグラウンドタスクでディスパッチされます。 +シグナルはバックグラウンドタスクでディスパッチされます。 ::: ### Blueprints -青写真信号のdispatchは、[middleware](../basics/middleware.md)と同様に機能します。アプリレベルから行われるものは、青写真まで流れ落ちます。ただし、青写真でディスパッチすると、その青写真で定義されている信号のみが実行されます。 +Blueprintシグナルのディスパッチは、[middleware](../basics/middleware.md)と同様に機能します。アプリレベルから行われるものは、blueprintまで流れ落ちます。 ただし、blueprintでディスパッチすると、そのblueprintで定義されているシグナルのみが実行されます。 ---:1 -おそらく、例は説明しやすいです: +おそらく、例は説明しやすいでしょう: :--:1 ```python bp = Blueprint("bp") @@ -258,7 +287,7 @@ def bp_signal(): :--- ---:1 -`app.dispatch("foo.bar.baz")`を実行すると、両方の信号が実行されます。 +`app.dispatch("foo.bar.baz")`を実行すると、両方のシグナルが実行されます。 :--:1 ```python await app.dispatch("foo.bar.baz") @@ -268,7 +297,7 @@ assert bp_counter == 1 :--- ---:1 -`bp.dispatch("foo.bar.baz")`を実行すると、ブループリント信号のみが実行されます。 +`bp.dispatch("foo.bar.baz")`を実行すると、Blueprintシグナルのみが実行されます。 :--:1 ```python await bp.dispatch("foo.bar.baz") diff --git a/src/ja/guide/advanced/streaming.md b/src/ja/guide/advanced/streaming.md index 96cc648296..6b59200fd3 100644 --- a/src/ja/guide/advanced/streaming.md +++ b/src/ja/guide/advanced/streaming.md @@ -1,6 +1,6 @@ # Streaming -## Request streaming +## ストリーミングのリクエスト Sanicを使用すると、クライアントから送信されたデータをストリーミングして、バイトが到着するとデータの処理を開始できます。 @@ -8,7 +8,7 @@ Sanicを使用すると、クライアントから送信されたデータをス エンドポイントで有効にすると、`await request.stream.read()`を使用してリクエストボディをストリーミングできます。 -そのメソッドは、本文が完了すると「なし」を返します。 +そのメソッドは、ボディが完了すると `None` を返します。 :--:1 ```python from sanic.views import stream @@ -41,7 +41,7 @@ async def handler(request): ---:1 -... or the `add_route()` method. +...または `add_route()` メソッドを使う。 :--:1 ```python bp.add_route( @@ -54,16 +54,13 @@ bp.add_route( :--- ::: tip FYI -Post、put、patchデコレータのみがストリーム引数を持っています。 +post、put、patchデコレータのみがストリーム引数を持っています。 ::: -## Response streaming +## ストリーミングの応答 ---:1 - -Sanicを使用すると、「StreamingHTTPResponse」のインスタンスを使用してクライアントにコンテンツをストリーミングできます。`sanic.response.stream`コンビニエンスメソッドもあります。 - -このメソッドは、クライアントへの書き込みを制御できるオブジェクトを渡されるコルーチンコールバックを受け入れます。 +Sanicではクライアントにコンテンツをストリーミングできます。 :--:1 ```python from sanic.response import stream @@ -92,36 +89,18 @@ async def index(request): return stream(stream_from_db) ``` -::: tip FYI -クライアントが HTTP/1.1 をサポートしている場合、Sanic は [チャンク転送エンコーディング](https://en.wikipedia.org/wiki/Chunked_transfer_encoding) を使用します。ストリーム関数のチャンクオプションを使用して明示的に有効または無効にできます。 -::: - ----:1 - -`stream`を使用したコルーチンコールバックパターンは必要ありません。これはストリーミングの*古いスタイル*であり、新しいインラインストリーミングに置き換える必要があります。これで、ハンドラーで応答を直接ストリーミングできるようになりました。 - -:--:1 -```python -@app.route("/") -async def test(request): - response = await request.respond(content_type="text/csv") - await response.send("foo,") - await response.send("bar") - await response.eof() - return response -``` -:--- -上記の例では、`await response.eof()` は `await response.send("", True)` を置き換える便利なメソッドとして呼び出されます。ハンドラがクライアントに送り返すものが何も残っていないと判断した場合、** 1回** *after*を呼び出す必要があります。 +`await response.eof()` を呼び出すことで、ストリームを明示的に終了させることができます。 上記の例では、`await response.eof()` は `await response.send("", True)` を置き換える便利なメソッドとして呼び出されます。 ハンドラがクライアントに送り返すものが何も残っていないと判断した場合、**1回** *after* を呼び出す必要があります。 Sanicサーバで使用するのは*任意*ですが、SanicをASGIモードで動作させている場合は、**必ず**明示的にストリームを終了させなければなりません。 +*Calling `eof` became optional in v21.6* -## File streaming +## ファイルストリーミング ---:1 Sanicは、大きなファイルを送信する場合に便利な `sanic.response.file_stream` 関数を提供します。`StreamingHTTPResponse`オブジェクトを返し、デフォルトでチャンク転送エンコーディングを使用します。このため、Sanicは応答に`Content-Length` HTTPヘッダーを追加しません。 -典型的なユースケースは、ビデオファイルをストリーミングしている可能性があります。 +典型的なユースケースは、ビデオファイルをストリーミングしている場合です。 :--:1 ```python @app.route("/mp4") diff --git a/src/ja/guide/advanced/versioning.md b/src/ja/guide/advanced/versioning.md index ab78986576..4b5b00a70a 100644 --- a/src/ja/guide/advanced/versioning.md +++ b/src/ja/guide/advanced/versioning.md @@ -1,4 +1,4 @@ -# Versioning +# バージョン進行 API構築では、エンドポイントにバージョンを追加するのが標準プラクティスです。これにより、APIを断りなく変更しようとすると、互換性のないエンドポイントを簡単に区別できます。 @@ -10,7 +10,7 @@ API構築では、エンドポイントにバージョンを追加するのが - `1.1`, `2.25`, `3.0` - `"1"`, `"v1"`, `"v1.1"` -## Per route +## ルートごとのバージョン ---:1 @@ -20,20 +20,20 @@ API構築では、エンドポイントにバージョンを追加するのが # /v1/text @app.route("/text", version=1) def handle_request(request): - return response.text("Hello world! Version 1") + return response.text("Hello world! バージョン1") # /v2/text @app.route("/text", version=2) def handle_request(request): - return response.text("Hello world! Version 2") + return response.text("Hello world! バージョン2") ``` :--- -## Per Blueprint +## Blueprintごとのバージョン ---:1 -ブループリントにバージョン番号を渡すこともできます。これは、そのブループリント内のすべてのルートに適用されます。 +lueprintにバージョン番号を渡すこともできます。これは、そのBlueprint内のすべてのルートに適用されます。 :--:1 ```python bp = Blueprint("test", url_prefix="/foo", version=1) @@ -45,20 +45,18 @@ def handle_request(request): ``` :--- -## Per Blueprint Group +## Blueprintグループごとのバージョン ---:1 -バージョン管理を簡素化するために、ブループリントにバージョン番号を提供できます -グループ。青写真がまだ上書きされていない場合、その下にグループ化されたすべての青写真にも同じことが継承されます -ブループリントインスタンスの作成中に指定された値と同じ情報。 +バージョン化されたBlueprintの管理を簡素化するために、グループにバージョン番号を提供できます。Blueprintインスタンスを作成する際に指定された値で同じ情報を上書きしない場合、 その下方でグループ化されたすべてのBlueprintにも同じ情報が継承されます。 -バージョンの管理にブループリントグループを使用する場合は、バージョンプレフィックスを登録されているルート。 +バージョン管理にblueprintグループを使用する場合、登録中の経路にVersionプレフィックスを適用するには、以下の順序で行います。 1. ルートレベルの設定 -2. ブループリントレベルの構成 -3. ブループリントグループレベルの構成 +2. Blueprintレベルの構成 +3. Blueprintグループレベルの構成 -より尖ったバージョニング仕様を見つけたら、より一般的なバージョニング仕様よりもそれを選びますブループリントまたはブループリントグループの下で提供 +もし、より尖ったバージョン管理仕様が見つかれば、BlueprintやBlueprintグループの下で提供される一般的なバージョン管理仕様よりも、そちらを選ぶことになります。 :--:1 ```python @@ -98,24 +96,24 @@ async def handle_endpoint_2_bp2(request): ``` :--- -## Version prefix +## バージョンプレフィックス -上記のように、ルートに適用される `version` は、生成された URI パスの最初のセグメントを **常に** です。したがって、バージョンの前にパスセグメントを追加できるように、`version`引数が渡されるすべての場所で、`version_prefix`を渡すこともできます。 +上で見たように、ルートに適用される`バージョン`は、**常に**生成されたURIパスの最初のセグメントになります。 したがって、バージョンの前にパスセグメントを追加できるように、`version`引数が渡されるすべての場所で、`version_prefix`を渡すこともできます。 `version_prefix`引数は次のように定義できます。 -- `app.route` and `bp.route` decorators (and all the convenience decorators also) -- `Blueprint` instantiation -- `Blueprint.group` constructor -- `BlueprintGroup` instantiation -- `app.blueprint` registration +- `app.route` と `bp.route` デコレータ (そして、すべての便利なデコレータ) +- `Blueprint`のインスタンス化 +- `Blueprint.group`コンストラクタ +- `BlueprintGroup`のインスタンス化 +- `app.blueprint`の登録 複数の場所に定義がある場合、より具体的な定義はより一般的な定義を上書きします。このリストはその階層を提供します。 `version_prefix`のデフォルト値は`/v`です。 ---:1 -頻繁に要求される機能は、バージョン管理されたルートを `/api` にマウントできるようにすることです。これは「version_prefix」で簡単に実現できます。 +頻繁に要求される機能は、バージョン管理されたルートを `/api` にマウントできるようにすることです。これは`version_prefix`で簡単に実現できます。 :--:1 ```python # /v1/my/path @@ -124,7 +122,7 @@ app.route("/my/path", version=1, version_prefix="/api/v") :--- ---:1 -おそらく、より説得力のある使用法は、すべての「/api」ルートを単一の「BlueprintGroup」にロードすることです。 +おそらく、より説得力のある使用法は、すべての`/api`ルートを単一の`BlueprintGroup`にロードすることです。 :--:1 ```python # /v1/my/path @@ -144,13 +142,15 @@ app.blueprint(api) したがって、ルートのURIは次のとおりです。 ``` -version_prefix + version + url_prefix + URI definition +version_prefix + version + url_prefix + URI定義 ``` ::: tip -`url_prefix`と同様に、`version_prefix`内にパスパラメータを定義することができます。これを行うことは完全に合法です。すべてのルートには、そのパラメータがハンドラーに注入されることを覚えておいてください。 +`url_prefix`と同様に、`version_prefix`内にパスパラメータを定義することができます。 これを行うのは完全に正当なことです。 すべてのルートには、そのパラメータがハンドラーに注入されることを覚えておいてください。 ```python version_prefix="//v" ``` ::: + +*Added in v21.6* \ No newline at end of file diff --git a/src/ja/guide/advanced/websockets.md b/src/ja/guide/advanced/websockets.md index 607a7265b7..50a36d0c2e 100644 --- a/src/ja/guide/advanced/websockets.md +++ b/src/ja/guide/advanced/websockets.md @@ -3,40 +3,45 @@ Sanicは、[websockets](https://websockets.readthedocs.io/en/stable/)の上に使いやすい抽象化を提供します。 -## Routing +## ルーティング ---:1 Websocketハンドラーは、通常のハンドラと同様にルーターに接続できます。 :--:1 ```python -async def feed(request, ws): +from sanic import Request, Websocket + +async def feed(request: Request, ws: Websocket): pass app.add_websocket_route(feed, "/feed") ``` ```python +from sanic import Request, Websocket + @app.websocket("/feed") -async def feed(request, ws): +async def feed(request: Request, ws: Websocket): pass ``` :--- -## Handler +## ハンドラ ---:1 -通常、Websocketハンドラはループを開きたいと思うでしょう。 +通常、WebSocketハンドラはループを開いた状態に保持しようとします。 その後、ハンドラーに注入された2番目のオブジェクトで `send()` メソッドと `recv()` メソッドを使用できます。 -この例は、受信したクライアントメッセージにエコーバックする単純なエンドポイントです。 +この例は、受信したクライアントメッセージにエコーするシンプルなエンドポイントです。 :--:1 ```python +from sanic import Request, Websocket @app.websocket("/feed") -async def feed(request, ws): +async def feed(request: Request, ws: Websocket): while True: data = "hello!" print("Sending: " + data) @@ -44,15 +49,27 @@ async def feed(request, ws): data = await ws.recv() print("Received: " + data) ``` + +---:1 +You can simplify your loop by just iterating over the `Websocket` object in a for loop. + +*v22.9で追加* +:--:1 +```python +from sanic import Request, Websocket +@app.websocket("/feed") +async def feed(request: Request, ws: Websocket): + async for msg in ws: + await ws.send(msg) +``` +:--- + :--- -## Configuration +## 設定 -詳細については、[構成セクション](/guide/deployment/configuration.md)を参照してください。 +デフォルトは以下の通りです。詳細は[構成セクション](/guide/deployment/configuration.md)を参照してください。 ```python app.config.WEBSOCKET_MAX_SIZE = 2 ** 20 -app.config.WEBSOCKET_MAX_QUEUE = 32 -app.config.WEBSOCKET_READ_LIMIT = 2 ** 16 -app.config.WEBSOCKET_WRITE_LIMIT = 2 ** 16 app.config.WEBSOCKET_PING_INTERVAL = 20 app.config.WEBSOCKET_PING_TIMEOUT = 20 ``` diff --git a/src/ja/guide/basics/app.md b/src/ja/guide/basics/app.md index 54fc47b61a..1661aca198 100644 --- a/src/ja/guide/basics/app.md +++ b/src/ja/guide/basics/app.md @@ -1,9 +1,9 @@ -# Sanic Application +# Sanicアプリケーション -## Instance +## インスタンス化 ---:1 -最も基本的な構成要素は、`Sanic()`インスタンスです。これは必須ではありませんが、カスタムはこれを`server.py`というファイルでインスタンス化します。 +最も基本的な構成要素は、`Sanic()`インスタンスです。これは必須ではありませんが、カスタマイズする場合はこれを`server.py`というファイルでインスタンス化します。 :--:1 ```python # /path/to/server.py @@ -14,14 +14,15 @@ app = Sanic("My Hello, world app") ``` :--- -## Application context +## アプリケーションコンテキスト ほとんどのアプリケーションでは、コード・ベースのさまざまな部分でデータやオブジェクトを共有/再利用する必要があります。最も一般的な例はDB接続です。 + ---:1 v21.3より前のバージョンのSanicでは、これは通常、属性をアプリケーションインスタンスにアタッチすることによって行われていました。 :--:1 ```python -# Raises a warning as deprecated feature in 21.3 +# 21.3では非推奨として警告を出力する app = Sanic("MyApp") app.db = Database() ``` @@ -31,15 +32,16 @@ app.db = Database() これにより、名前の競合に関する潜在的な問題が発生したり、[要求コンテキスト](./request.md#context)オブジェクトv 21.3では、アプリケーションレベルのコンテキストオブジェクトが導入されました。 :--:1 ```python -# Correct way to attach objects to the application +# アプリケーションにオブジェクトを添付する正しい方法 app = Sanic("MyApp") app.ctx.db = Database() ``` :--- -## App Registry +## アプリケーションの登録 ---:1 + Sanicインスタンスをインスタンス化すると、後でSanicアプリケーションレジストリから取得できます。これは、他の方法ではアクセスできない場所からSanicインスタンスにアクセスする必要がある場合などに便利です。 :--:1 ```python @@ -56,6 +58,7 @@ app = Sanic.get_app("my_awesome_server") :--- ---:1 + 存在しないアプリケーションで`Sanic.get_app("non-existing")`を呼び出すと、デフォルトで`SanicException'が発生します。代わりに、その名前の新しいSanicインスタンスを返すようにメソッドに強制できます。 :--:1 ```python @@ -67,7 +70,7 @@ app = Sanic.get_app( :--- ---:1 -**Sanicインスタンスが1つしか登録されていない**場合、引数なしで`Sanic.get_app () `を呼び出すと、そのインスタンスが返されます。 +Sanicインスタンスが**1つしか**登録されていない場合、引数なしで`Sanic.get_app ()`を呼び出すと、そのインスタンスが返されます。 :--:1 ```python Sanic("My only app") @@ -76,11 +79,11 @@ app = Sanic.get_app() ``` :--- -## Configuration +## 構成 ---:1 -Sanicは、Sanicインスタンスのconfig属性に設定を保持します。構成は、ドット表記を使用するか、辞書のように変更できます。 -:--:1 +Sanicは、`Sanic`インスタンスの`config`属性に設定を保持します。設定は、ドット表記**または**辞書の**どちらかを**使用して変更できます。 +---:1 ```python app = Sanic('myapp') @@ -97,27 +100,28 @@ app.config.update(db_settings) :--- ::: tip Heads up -構成キーは大文字でなければなりません。しかし、これは主に規約によるもので、ほとんどの場合小文字で動作します。 +構成キーは大文字で _なければなりません_ 。 しかし、これは主に規約によるもので、ほとんどの場合小文字で動作します。 ``` app.config.GOOD = "yay!" app.config.bad = "boo" ``` ::: -[設定の詳細](/guide/deployment/configuration.md)については後で説明します。 +There is much [more detail about configuration](/guide/deployment/configuration.md) later on. -## Customization +## カスタマイズ Sanicアプリケーションインスタンスは、インスタンス化時にさまざまな方法でアプリケーションのニーズに合わせてカスタマイズできます。 -### Custom configuration +### カスタムな構成 ---:1 -カスタム設定の最も単純な形式は、独自のオブジェクトを直接そのSanicアプリケーションインスタンスに渡すことです。 +この最も単純なカスタム設定の方法は、独自のオブジェクトを直接Sanicアプリケーションのインスタンスに渡すことです。 -カスタム設定オブジェクトを作成する場合は、Sanicの`Config`オプションをサブクラス化して、その動作を継承することを強くお勧めします。このオプションを使用して、プロパティを追加することも、独自のカスタムロジックセットを追加することもできます。 +カスタム設定オブジェクトを作成する場合は、Sanicの`Config`オプションをサブクラス化して、その動作を継承することを強くお勧めします。 このオプションを使用して、プロパティを追加することも、独自のカスタムロジックセットを追加することもできます。 +*v21.6で追加* :--:1 ```python from sanic.config import Config @@ -130,7 +134,6 @@ app = Sanic(..., config=MyConfig()) :--- ---:1 - この機能の有用な例は、 [supported](../deployment/configuration.md#using-sanic-update-config)とは異なる形式の設定ファイルを使用する場合です。 :--:1 ```python @@ -165,11 +168,11 @@ toml_config = TomlConfig(path="/path/to/config.toml") app = Sanic(toml_config.APP_NAME, config=toml_config) ``` :--- -### Custom context +### カスタム コンテキスト ---:1 +By default, the application context is a [`SimpleNamespace()`](https://docs.python.org/3/library/types.html#types.SimpleNamespace) that allows you to set any properties you want on it. ただし、代わりに任意のオブジェクトを渡すこともできます。 -デフォルトでは、アプリケーション・コンテキストは [`SimpleNamespace()`](https://docs.python.org/3/library/types.html#types.SimpleNamespace) であり、必要なプロパティを設定できます。ただし、代わりに任意のオブジェクトを渡すこともできます。 - +*Added in v21.6* :--:1 ```python app = Sanic(..., ctx=1) @@ -180,17 +183,17 @@ app = Sanic(..., ctx={}) ``` ```python -class MyContext: +class CustomContext: ... app = Sanic(..., ctx=MyContext()) ``` :--- -### Custom requests +### カスタムリクエスト ---:1 -独自の 「Request」 クラスを用意し、デフォルトの代わりにそれを使用するようにSanicに指示すると便利な場合があります。たとえば、デフォルトの`request.id`ジェネレータを変更する場合です。 +独自の 「Request」 クラスを用意し、デフォルトの代わりにそれを使用するようにSanicに指示すると便利な場合があります。 たとえば、デフォルトの`request.id`ジェネレータを変更する場合です。 -::: tip Important +::: tip 重要 クラスのインスタンスではなく、*クラス*を渡すことを覚えておくことが重要です。 @@ -217,7 +220,7 @@ async def handler(request): ``` :--- -### Custom error handler +### カスタムエラー処理 ---:1 詳細については、[exception handling](../best-practices/exceptions.md#custom-error-handling)を参照してください。 @@ -227,10 +230,237 @@ from sanic.handlers import ErrorHandler class CustomErrorHandler(ErrorHandler): def default(self, request, exception): - ''' handles errors that have no error handlers assigned ''' - # You custom error handling logic... + ''' エラーハンドラが割り当てられていないエラーを処理する ''' + # あなた独自のエラーハンドリングロジック... return super().default(request, exception) app = Sanic(..., error_handler=CustomErrorHandler()) ``` :--- + +### Custom dumps function + +---:1 +It may sometimes be necessary or desirable to provide a custom function that serializes an object to JSON data. +:--:1 +```python +import ujson + +dumps = partial(ujson.dumps, escape_forward_slashes=False) +app = Sanic(__name__, dumps=dumps) +``` +:--- + +---:1 +Or, perhaps use another library or create your own. +:--:1 +```python +from orjson import dumps + +app = Sanic(__name__, dumps=dumps) +``` +:--- + +### Custom loads function + +---:1 +Similar to `dumps`, you can also provide a custom function for deserializing data. + +*Added in v22.9* +:--:1 +```python +from orjson import loads + +app = Sanic(__name__, loads=loads) +``` +:--- + +::: new NEW in v23.6 +### Custom typed application + +The correct, default type of a Sanic application instance is: + +```python +sanic.app.Sanic[sanic.config.Config, types.SimpleNamespace] +``` + +It refers to two generic types: + +1. The first is the type of the configuration object. It defaults to `sanic.config.Config`, but can be any subclass of that. +2. The second is the type of the application context. It defaults to `types.SimpleNamespace`, but can be **any object** as show above. + +Let's look at some examples of how the type will change. + +---:1 +Consider this example where we pass a custom subclass of `Config` and a custom context object. + +:--:1 +```python +from sanic import Sanic +from sanic.config import Config + +class CustomConfig(Config): + pass + +app = Sanic("test", config=CustomConfig()) +reveal_type(app) # N: Revealed type is "sanic.app.Sanic[main.CustomConfig, types.SimpleNamespace]" +``` +``` +sanic.app.Sanic[main.CustomConfig, types.SimpleNamespace] +``` +:--- + +---:1 +Similarly, when passing a custom context object, the type will change to reflect that. +:--:1 +```python +from sanic import Sanic + +class Foo: + pass + +app = Sanic("test", ctx=Foo()) +reveal_type(app) # N: Revealed type is "sanic.app.Sanic[sanic.config.Config, main.Foo]" +``` +``` +sanic.app.Sanic[sanic.config.Config, main.Foo] +``` +:--- + +---:1 +Of course, you can set both the config and context to custom types. +:--:1 +```python +from sanic import Sanic +from sanic.config import Config + +class CustomConfig(Config): + pass + +class Foo: + pass + +app = Sanic("test", config=CustomConfig(), ctx=Foo()) +reveal_type(app) # N: Revealed type is "sanic.app.Sanic[main.CustomConfig, main.Foo]" +``` +``` +sanic.app.Sanic[main.CustomConfig, main.Foo] +``` +:--- + +This pattern is particularly useful if you create a custom type alias for your application instance so that you can use it to annotate listeners and handlers. + +```python +# ./path/to/types.py +from sanic.app import Sanic +from sanic.config import Config +from myapp.context import MyContext +from typing import TypeAlias + +MyApp = TypeAlias("MyApp", Sanic[Config, MyContext]) +``` + +```python +# ./path/to/listeners.py +from myapp.types import MyApp + + +def add_listeners(app: MyApp): + @app.before_server_start + async def before_server_start(app: MyApp): + # do something with your fully typed app instance + await app.ctx.db.connect() +``` + +```python +# ./path/to/server.py +from myapp.types import MyApp +from myapp.context import MyContext +from myapp.config import MyConfig +from myapp.listeners import add_listeners + +app = Sanic("myapp", config=MyConfig(), ctx=MyContext()) +add_listeners(app) +``` + +*Added in v23.6* + +### Custom typed request + +Sanic also allows you to customize the type of the request object. This is useful if you want to add custom properties to the request object, or be able to access your custom properties of a typed application instance. + +The correct, default type of a Sanic request instance is: + +```python +sanic.request.Request[ + sanic.app.Sanic[sanic.config.Config, types.SimpleNamespace], + types.SimpleNamespace +] +``` + +It refers to two generic types: + +1. The first is the type of the application instance. It defaults to `sanic.app.Sanic[sanic.config.Config, types.SimpleNamespace]`, but can be any subclass of that. +2. The second is the type of the request context. It defaults to `types.SimpleNamespace`, but can be **any object** as show above in [custom requests](#custom-requests). + +Let's look at some examples of how the type will change. + +---:1 +Expanding upon the full example above where there is a type alias for a customized application instance, we can also create a custom request type so that we can access those same type annotations. + +Of course, you do not need type aliases for this to work. We are only showing them here to cut down on the amount of code shown. +:--:1 +```python +from sanic import Request +from myapp.types import MyApp +from types import SimpleNamespace + +def add_routes(app: MyApp): + @app.get("/") + async def handler(request: Request[MyApp, SimpleNamespace]): + # do something with your fully typed app instance + results = await request.app.ctx.db.query("SELECT * FROM foo") +``` +:--- + +---:1 +Perhaps you have a custom request object that generates a custom context object. You can type annotate it to properly access those properties with your IDE as shown here. +:--:1 +```python +from sanic import Request, Sanic +from sanic.config import Config + +class CustomConfig(Config): + pass + +class Foo: + pass + +class RequestContext: + foo: Foo + +class CustomRequest(Request[Sanic[CustomConfig, Foo], RequestContext]): + @staticmethod + def make_context() -> RequestContext: + ctx = RequestContext() + ctx.foo = Foo() + return ctx + +app = Sanic( + "test", config=CustomConfig(), ctx=Foo(), request_class=CustomRequest +) + +@app.get("/") +async def handler(request: CustomRequest): + # Full access to typed: + # - custom application configuration object + # - custom application context object + # - custom request context object + pass +``` +:--- + +See more information in the [custom request context](./request.md#custom-request-context) section. + +*Added in v23.6* +::: diff --git a/src/ja/guide/basics/cookies.md b/src/ja/guide/basics/cookies.md index 7350a88b4a..089af5c795 100644 --- a/src/ja/guide/basics/cookies.md +++ b/src/ja/guide/basics/cookies.md @@ -1,6 +1,6 @@ -# Cookies +# クッキー -## Reading +## 読み込み ---:1 @@ -10,12 +10,22 @@ @app.route("/cookie") async def test(request): test_cookie = request.cookies.get("test") - return text("Test cookie: {}".format(test_cookie)) + return text(f"Test cookie: {test_cookie}") ``` + :--- +::: tip FYI + +💡 The `request.cookies` object is one of a few types that is a dictionary with each value being a `list`. This is because HTTP allows a single key to be reused to send multiple values. + +Most of the time you will want to use the `.get()` method to access the first element and not a `list`. If you do want a `list` of all items, you can use `.getlist()`. + +*Added in v23.3* +::: + -## Writing +## 書き込み ---:1 @@ -24,26 +34,38 @@ async def test(request): ```python @app.route("/cookie") async def test(request): - response = text("There's a cookie up in this response") - response.cookies["test"] = "It worked!" - response.cookies["test"]["domain"] = ".yummy-yummy-cookie.com" - response.cookies["test"]["httponly"] = True + response = text("このレスポンスにはクッキーがあります") + response.add_cookie( + "test", + "It worked!", + domain=".yummy-yummy-cookie.com", + httponly=True + ) return response ``` :--- 応答クッキーは辞書の値のように設定でき、次のパラメータを使用できます。 -- `expires: datetime` - クライアントのブラウザでクッキーが期限切れになる時間。 - `path: str` - このクッキーが適用されるURLのサブセット。デフォルトは `/` です。 -- `comment: str` - コメント(メタデータ)。 - `domain: str` - クッキーが有効なドメインを指定します。明示的に指定されたドメインは常にドットで始まる必要があります。 -- `max-age: int` - クッキーが存息する秒数。 -- `secure: bool` - クッキーがHTTPS経由でのみ送信されるかどうかを指定します。 +- `max_age: int` - クッキーが存息する秒数。 +- `expires: datetime` - The time for the cookie to expire on the client’s browser. Usually it is better to use max-age instead. +- `secure: bool` - Specifies whether the cookie will only be sent via HTTPS. Defaults to `True`. - `httponly: bool` - クッキーをJavaScriptで読み取ることができないかどうかを指定します。 -- `samesite: str` - デフォルトはブラウザに依存し、仕様状態(Lax、Strict、None)は有効な値です。 +- `samesite: str` - Available values: Lax, Strict, and None. Defaults to `Lax`. +- `comment: str` - A comment (metadata). +- `host_prefix: bool` - Whether to add the `__Host-` prefix to the cookie. +- `secure_prefix: bool` - Whether to add the `__Secure-` prefix to the cookie. +- `partitioned: bool` - Whether to mark the cookie as partitioned. -## Deleting +To better understand the implications and usage of these values, it might be helpful to read the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) on [setting cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie). + +::: tip FYI +By default, Sanic will set the `secure` flag to `True` to ensure that cookies are only sent over HTTPS as a sensible default. This should not be impactful for local development since secure cookies over HTTP should still be sent to `localhost`. For more information, you should read the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) on [secure cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Secure). +::: + +## 削除 ---:1 @@ -52,25 +74,20 @@ async def test(request): ```python @app.route("/cookie") async def test(request): - response = text("Time to eat some cookies muahaha") + response = text("クッキーを食べる時間だ!ハハハ") - # This cookie will be set to expire in 0 seconds - del response.cookies["kill_me"] + # 0秒後にこのクッキーは削除されます + response.delete_cookie("eat_me") - # This cookie will self destruct in 5 seconds - response.cookies["short_life"] = "Glad to be here" - response.cookies["short_life"]["max-age"] = 5 - del response.cookies["favorite_color"] - - # This cookie will remain unchanged - response.cookies["favorite_color"] = "blue" - response.cookies["favorite_color"] = "pink" - del response.cookies["favorite_color"] + # このクッキーは5秒後に自分から消えます + response.add_cookie("fast_bake", "Be quick!", max_age=5) return response ``` + +*Don't forget to add `path` or `domain` if needed!* :--- -## Eating +## 食べる -私はクッキーが好きです:🍪: +Sanicはクッキーが好きなんです :cookie: diff --git a/src/ja/guide/basics/handlers.md b/src/ja/guide/basics/handlers.md index 4c15b683a4..0d666a667a 100644 --- a/src/ja/guide/basics/handlers.md +++ b/src/ja/guide/basics/handlers.md @@ -1,8 +1,8 @@ # Handlers -次の重要な構成要素は、あなたの_handlers_です。これらは「ビュー」とも呼ばれます。 +次の重要な構成要素は、あなたの _handlers_ です。これらは「ビュー」とも呼ばれます。 -Sanicでは、ハンドラは、少なくとも「Request`インスタンスを引数として受け取り、`HTTPResponse`インスタンス、または同じことを行うコルーチンのいずれかを返す呼び出し可能物です。 +Sanicでは、ハンドラは、少なくとも「`Request`インスタンスを引数として受け取り、`HTTPResponse`インスタンス、または同じことを行うコルーチンのいずれかを返す呼び出し可能物です。 diff --git a/src/ja/guide/basics/headers.md b/src/ja/guide/basics/headers.md index fb9497da86..416bac1f9c 100644 --- a/src/ja/guide/basics/headers.md +++ b/src/ja/guide/basics/headers.md @@ -44,7 +44,7 @@ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4 #### Proxy headers -Sanicはプロキシヘッダを特別に扱います。詳細については、 [proxy headers] (/guide/advanced/proxy-headers.md) セクションを参照してください。 +Sanicはプロキシヘッダを特別に扱います。詳細については、 [proxy headers](/guide/advanced/proxy-headers.md) セクションを参照してください。 #### Host header and dynamic URL construction @@ -205,7 +205,7 @@ async def add_csp(request, response): ---:1 -一般的な [ミドルウェア] (middleware.md) は、すべての応答に`X-Request-ID`ヘッダーを追加することです。前述のように、`request.id`は着信要求からIDを提供します。ただし、リクエストヘッダーにIDが指定されていない場合でも、自動的にIDが指定されます。 +一般的な [ミドルウェア](middleware.md) は、すべての応答に`X-Request-ID`ヘッダーを追加することです。前述のように、`request.id`は着信要求からIDを提供します。ただし、リクエストヘッダーにIDが指定されていない場合でも、自動的にIDが指定されます。 [詳細については、APIドキュメントを参照してください。](https://sanic.readthedocs.io/en/latest/sanic/api_reference.html#sanic.request.Request.id) diff --git a/src/ja/guide/basics/listeners.md b/src/ja/guide/basics/listeners.md index 008a168b8e..888e98f67e 100644 --- a/src/ja/guide/basics/listeners.md +++ b/src/ja/guide/basics/listeners.md @@ -1,12 +1,19 @@ # Listeners -Sanicは、アプリケーションのライフサイクルにオペレーションを注入する6つの機会を提供します。 +Sanicは、アプリケーションのライフサイクルにオペレーションを注入する6つの機会を提供します。This does not include the [signals](../advanced/signals.md), which allow further injection customization. -メインのSanicプロセスで**のみ**を実行するものが2つあります(つまり、`sanic server.app`への呼び出しごとに1回です。)。 +メインのSanicプロセスで**のみ**を実行するものが2つあります(つまり、`sanic server.app`への呼び出しごとに1回です)。 - `main_process_start` - `main_process_stop` +There are also two (2) that run **only** in a reloader process if auto-reload has been turned on. + +- `reload_process_start` +- `reload_process_stop` + +*Added `reload_process_start` and `reload_process_stop` in v22.3* + サーバの起動時または終了時にスタートアップ/ティアダウンコードを実行できるようにするには、4つの方法があります。 - `before_server_start` @@ -60,16 +67,30 @@ loop end Note over Process: exit ``` + +The reloader process live outside of this worker process inside of a process that is responsible for starting and stopping the Sanic processes. Consider the following example: + +```python +@app.reload_process_start +async def reload_start(*_): + print(">>>>>> reload_start <<<<<<") +@app.main_process_start +async def main_start(*_): + print(">>>>>> main_start <<<<<<") +``` + +If this application were run with auto-reload turned on, the `reload_start` function would be called once. This is contrasted with `main_start`, which would be run every time a file is save and the reloader restarts the applicaition process. + ## Attaching a listener ---:1 関数をリスナーとして設定するプロセスは、ルートの宣言に似ています。 -注入される2つの引数は、現在実行中の`Sanic()`インスタンスと現在実行中のループです。 +The currently running `Sanic()` instance is injected into the listener. :--:1 ```python -async def setup_db(app, loop): +async def setup_db(app,): app.ctx.db = await db_setup() app.register_listener(setup_db, "before_server_start") diff --git a/src/ja/guide/basics/request.md b/src/ja/guide/basics/request.md index eeeeedf7ae..ef1307d5e7 100644 --- a/src/ja/guide/basics/request.md +++ b/src/ja/guide/basics/request.md @@ -61,7 +61,7 @@ bar ::: tip FYI :bulb: `request.form`オブジェクトは、各値がリストであるディクショナリの、いくつかのタイプの1つです。これは、HTTPでは1つのキーを再利用して複数の値を送信できるためです。 -ほとんどの場合、リストではなく最初の要素にアクセスするには、`.get()`メソッドを使用します。すべての項目のリストが必要な場合は、`.getlist()`を使用できます。 +Most of the time you will want to use the `.get()` method to access the first element and not a list. If you do want a list of all items, you can use `.getlist()`. ::: ::: tab Uploaded @@ -122,7 +122,6 @@ async def hi_my_name_is(request): 多くの場合、APIは同じクライアントに対して複数の同時 (または連続) リクエストを処理する必要があります。たとえば、データを取得するために複数のエンドポイントにクエリを実行する必要があるプログレッシブウェブアプリでは、これが頻繁に発生します。 - HTTPプロトコルでは、[keep alive headers](../ deployment/configuration.md#keep-alive-timeout)を使用した接続によって発生するオーバーヘッド時間を緩和する必要があります。 複数のリクエストが1つの接続を共有する場合、Sanicはそれらのリクエストが状態を共有できるようにコンテキストオブジェクトを提供します。 @@ -148,6 +147,67 @@ request.conn_info.ctx.foo=3 ``` :--- +### Custom Request Objects + +As dicussed in [application customization](./app.md#custom-requests), you can create a subclass of `sanic.Request` to add additional functionality to the request object. This is useful for adding additional attributes or methods that are specific to your application. + +---:1 +For example, imagine your application sends a custom header that contains a user ID. You can create a custom request object that will parse that header and store the user ID for you. +:--:1 +```python +from sanic import Sanic, Request + +class CustomRequest(Request): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user_id = self.headers.get("X-User-ID") + +app = Sanic("Example", request_class=CustomRequest) +``` +:--- + +---:1 +Now, in your handlers, you can access the `user_id` attribute. +:--:1 +```python +@app.route("/") +async def handler(request: CustomRequest): + return text(f"User ID: {request.user_id}") +``` +:--- + +::: new NEW in v23.6 +### Custom Request Context + +By default, the request context (`request.ctx`) is a `SimpleNamespace` object allowing you to set arbitrary attributes on it. While this is super helpful to reuse logic across your application, it can be difficult in the development experience since the IDE will not know what attributes are available. + +To help with this, you can create a custom request context object that will be used instead of the default `SimpleNamespace`. This allows you to add type hints to the context object and have them be available in your IDE. + +---:1 +Start by subclassing the `sanic.Request` class to create a custom request type. Then, you will need to add a `make_context()` method that returns an instance of your custom context object. *NOTE: the `make_context` method should be a static method.* +:--:1 +```python +from sanic import Sanic, Request +from types import SimpleNamespace + +class CustomRequest(Request): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.ctx.user_id = self.headers.get("X-User-ID") + + @staticmethod + def make_context() -> CustomContext: + return CustomContext() + +@dataclass +class CustomContext: + user_id: str = None +``` +:--- + +*Added in v23.6* +::: + ## Parameters ---:1 @@ -193,5 +253,49 @@ key1=val1&key2=val2&key1=val3 ::: tip FYI :bulb: `request.args`オブジェクトは、各値がリストになっているディクショナリのタイプの1つです。これは、HTTPでは1つのキーを再利用して複数の値を送信できるためです。 -ほとんどの場合、リストではなく最初の要素にアクセスするには、`.get()`メソッドを使用します。すべての項目のリストが必要な場合は、`.getlist()`を使用できます。 +Most of the time you will want to use the `.get()` method to access the first element and not a list. If you do want a list of all items, you can use `.getlist()`. ::: + +## Current request getter + +Sometimes you may find that you need access to the current request in your application in a location where it is not accessible. A typical example might be in a `logging` format. You can use `Request.get_current()` to fetch the current request (if any). + +```python +import logging + +from sanic import Request, Sanic, json +from sanic.exceptions import SanicException +from sanic.log import LOGGING_CONFIG_DEFAULTS + +LOGGING_FORMAT = ( + "%(asctime)s - (%(name)s)[%(levelname)s][%(host)s]: " + "%(request_id)s %(request)s %(message)s %(status)d %(byte)d" +) + +old_factory = logging.getLogRecordFactory() + + +def record_factory(*args, **kwargs): + record = old_factory(*args, **kwargs) + record.request_id = "" + + try: + request = Request.get_current() + except SanicException: + ... + else: + record.request_id = str(request.id) + + return record + + +logging.setLogRecordFactory(record_factory) + +LOGGING_CONFIG_DEFAULTS["formatters"]["access"]["format"] = LOGGING_FORMAT + +app = Sanic("Example", log_config=LOGGING_CONFIG_DEFAULTS) +``` + +In this example, we are adding the `request.id` to every access log message. + +*Added in v22.6* diff --git a/src/ja/guide/basics/response.md b/src/ja/guide/basics/response.md index 91915b5fd3..9a51046fd5 100644 --- a/src/ja/guide/basics/response.md +++ b/src/ja/guide/basics/response.md @@ -1,6 +1,26 @@ # Response -すべての[ハンドラ](./handlers.md) **は**レスポンス・オブジェクトを返し、[ミドルウェア](./middleware.md)は、オプションで応答オブジェクトを返すことができます。 +All [handlers](./handlers.md) *usually* return a response object, and [middleware](./middleware.md) may optionally return a response object. + +To clarify that statement: +- unless the handler is a streaming endpoint handling its own pattern for sending bytes to the client, the return value must be an instance of `sanic.HTTPResponse` (to learn more about this exception see [streaming responses](../advanced/streaming.md#response-streaming)) +- if a middleware returns a response object, that will be used instead of whatever the handler would do (see [middleware](./middleware.md) to learn more) + +A most basic handler would look like the following. The `HTTPResponse` object will allow you to set the status, body, and headers to be returned to the client. + +```python +from sanic import HTTPResponse, Sanic + +app = Sanic("TestApp") + + +@app.route("") +def handler(_): + return HTTPResponse() +``` + +However, usually it is easier to use one of the convenience methods discussed below. + ## Methods @@ -91,28 +111,6 @@ You can also choose to override the file name: file("/path/to/whatever.png", filename="super-awesome-incredible.png") ``` ::: -::: tab Streaming - -**Default Content-Type**: `text/plain; charset=utf-8` -**Description**: Streams data to a client - -```python -from sanic.response import stream - -@app.route("/") -async def handler(request): - return stream(streaming_fn) - -async def streaming_fn(response): - await response.write('foo') - await response.write('bar') -``` -By default, Sanic will stream back to the client using chunked encoding if the client supports it. You can disable this: - -```python -stream(streaming_fn, chunked=False) -``` -::: ::: tab "File Streaming" **Default Content-Type**: N/A @@ -183,3 +181,40 @@ async def create_new(request): new_thing = await do_create(request) return json({"created": True, "id": new_thing.thing_id}, status=201) ``` + +## Returning JSON data + +Starting in v22.12, When you use the `sanic.json` convenience method, it will return a subclass of `HTTPResponse` called `JSONResponse`. This object will +have several convenient methods available to modify common JSON body. + +```python +from sanic import json + +resp = json(...) +``` + +- `resp.set_body()` - Set the body of the JSON object to the value passed +- `resp.append()` - Append a value to the body like `list.append` (only works if the root JSON is an array) +- `resp.extend()` - Extend a value to the body like `list.extend` (only works if the root JSON is an array) +- `resp.update()` - Update the body with a value like `dict.update` (only works if the root JSON is an object) +- `resp.pop()` - Pop a value like `list.pop` or `dict.pop` (only works if the root JSON is an array or an object) + +::: warning +The raw Python object is stored on the `JSONResponse` object as `raw_body`. While it is safe to overwrite this value with a new one, you should **not** attempt to mutate it. You should instead use the methods listed above. + +```python +resp = json({"foo": "bar"}) + +# This is OKAY +resp.raw_body = {"foo": "bar", "something": "else"} + +# This is better +resp.set_body({"foo": "bar", "something": "else"}) + +# This is also works well +resp.update({"something": "else"}) + +# This is NOT OKAY +resp.raw_body.update({"something": "else"}) +``` +*Added in v22.9* diff --git a/src/ja/guide/basics/routing.md b/src/ja/guide/basics/routing.md index 9f0a31d335..0fd6688ea5 100644 --- a/src/ja/guide/basics/routing.md +++ b/src/ja/guide/basics/routing.md @@ -136,18 +136,17 @@ async def handler(request): :::: ::: warning -デフォルトでは、Sanic は安全でない HTTP メソッド (`POST`、`PUT`、`PATCH`) で受信したリクエストボディ**のみ**を消費します。他のメソッドでHTTPリクエストのデータを受け取りたい場合は、以下の2つのオプションのいずれかを実行する必要があります。 +デフォルトでは、Sanic は安全でない HTTP メソッド (`POST`、`PUT`、`PATCH`, `DELETE`) で受信したリクエストボディ**のみ**を消費します。他のメソッドでHTTPリクエストのデータを受け取りたい場合は、以下の2つのオプションのいずれかを実行する必要があります。 **オプション#1 - `ignore_body`を使用してSanicにボディを消費するように指示する。** ```python -@app.delete("/path", ignore_body=False) +@app.request("/path", ignore_body=False) async def handler(_): - ... ``` **オプション #2 - ハンドラ内で `receive_body` を使って手動でボディを消費する。** ```python -@app.delete("/path") +@app.get("/path") async def handler(request: Request): await request.receive_body() ``` @@ -188,14 +187,32 @@ async def uuid_handler(request, foo_id: UUID): async def handler(request, foo: str): ... ``` -**Regular expression applied**: `r"[^/]+")` -**Cast type**: `str` +**Regular expression applied**: `r"[^/]+")` +**Cast type**: `str` **Example matches**: - `/path/to/Bob` - `/path/to/Python%203` +Beginning in v22.3 `str` will *not* match on empty strings. See `strorempty` for this behavior. -以前のバージョンのSanicでは、この形式は非推奨となり、v21.12で削除される予定です。 +::: +::: tab strorempty + +```python +@app.route("/path/to/") +async def handler(request, foo: str): + ... +``` +**Regular expression applied**: `r"[^/]*")` +**Cast type**: `str` +**Example matches**: +- `/path/to/Bob` +- `/path/to/Python%203` +- `/path/to/` + +Unlike the `str` path parameter type, `strorempty` can also match on an empty string path segment. + +*Added in v22.3* ::: ::: tab int @@ -204,8 +221,8 @@ async def handler(request, foo: str): async def handler(request, foo: int): ... ``` -**Regular expression applied**: `r"-?\d+")` -**Cast type**: `int` +**Regular expression applied**: `r"-?\d+")` +**Cast type**: `int` **Example matches**: - `/path/to/10` - `/path/to/-10` @@ -219,14 +236,13 @@ _Does not match float, hex, octal, etc_ async def handler(request, foo: float): ... ``` -**Regular expression applied**: `r"-?(?:\d+(?:\.\d*)?|\.\d+)")` -**Cast type**: `float` +**Regular expression applied**: `r"-?(?:\d+(?:\.\d*)?|\.\d+)")` +**Cast type**: `float` **Example matches**: - `/path/to/10` - `/path/to/-10` - `/path/to/1.5` -以前のバージョンのSanicでは、この形式は非推奨となり、v21.12で削除される予定です。 ::: ::: tab alpha @@ -235,8 +251,8 @@ async def handler(request, foo: float): async def handler(request, foo: str): ... ``` -**Regular expression applied**: `r"[A-Za-z]+")` -**Cast type**: `str` +**Regular expression applied**: `r"[A-Za-z]+")` +**Cast type**: `str` **Example matches**: - `/path/to/Bob` - `/path/to/Python` @@ -250,12 +266,13 @@ _Does not match a digit, or a space or other special character_ async def handler(request, article: str): ... ``` -**Regular expression applied**: `r"[a-z0-9]+(?:-[a-z0-9]+)*")` -**Cast type**: `str` +**Regular expression applied**: `r"[a-z0-9]+(?:-[a-z0-9]+)*")` +**Cast type**: `str` **Example matches**: - `/path/to/some-news-story` - `/path/to/or-has-digits-123` +*Added in v21.6* ::: ::: tab path @@ -264,15 +281,15 @@ async def handler(request, article: str): async def handler(request, foo: str): ... ``` -**Regular expression applied**: `r"[^/].*?")` -**Cast type**: `str` +**Regular expression applied**: `r"[^/].*?")` +**Cast type**: `str` **Example matches**: - `/path/to/hello` - `/path/to/hello.txt` - `/path/to/hello/world.txt` ::: warning -これは`/`で一致するため、`path`を使用するパターンを慎重に徹底的にテストして、別のエンドポイント向けのトラフィックをキャプチャしないようにする必要があります。 +これは`/`で一致するため、`path`を使用するパターンを慎重に徹底的にテストして、別のエンドポイント向けのトラフィックをキャプチャしないようにする必要があります。 Additionally, depending on how you use this type, you may be creating a path traversal vulnerability in your application. It is your job to protect your endpoint against this, but feel free to ask in our community channels for help if you need it :) ::: ::: tab ymd @@ -281,8 +298,8 @@ async def handler(request, foo: str): async def handler(request, foo: datetime.date): ... ``` -**Regular expression applied**: `r"^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))"` -**Cast type**: `datetime.date` +**Regular expression applied**: `r"^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))"` +**Cast type**: `datetime.date` **Example matches**: - `/path/to/2021-03-28` ::: @@ -294,28 +311,55 @@ async def handler(request, foo: datetime.date): async def handler(request, foo: UUID): ... ``` -**Regular expression applied**: `r"[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}"` -**Cast type**: `UUID` +**Regular expression applied**: `r"[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}"` +**Cast type**: `UUID` **Example matches**: - `/path/to/123a123a-a12a-1a1a-a1a1-1a12a1a12345` ::: +::: tab ext + +```python +@app.route("/path/to/") +async def handler(request, foo: str, ext: str): + ... +``` +**Regular expression applied**: n/a +**Cast type**: *varies* +**Example matches**: + +| definition | example | filename | extension | +| --------------------------------- | ----------- | ----------- | ---------- | +| \ | page.txt | `"page"` | `"txt"` | +| \ | cat.jpg | `"cat"` | `"jpg"` | +| \ | cat.jpg | `"cat"` | `"jpg"` | +| | 123.txt | `123` | `"txt"` | +| | 123.svg | `123` | `"svg"` | +| | 3.14.tar.gz | `3.14` | `"tar.gz"` | + +File extensions can be matched using the special `ext` parameter type. It uses a special format that allows you to specify other types of parameter types as the file name, and one or more specific extensions as shown in the example table above. + +It does *not* support the `path` parameter type. + +*Added in v22.3* +::: + ::: tab regex ```python -@app.route(r"/path/to/") +@app.route(r"/path/to/") async def handler(request, foo: str): ... ``` -**Regular expression applied**: _whatever you insert_ -**Cast type**: `str` +**Regular expression applied**: _whatever you insert_ +**Cast type**: `str` **Example matches**: - `/path/to/2021-01-01` これにより、ユースケースの特定のマッチング・パターンを自由に定義できます。 -この例では、YYYY-MM-DD形式の日付を探しています。 +この例では、YYYY-MM-DD形式の日付を探しています。 :::: @@ -366,7 +410,7 @@ Sanicは、ハンドラメソッド名`app.url_for()`に基づいてURLを生成 async def index(request): # generate a URL for the endpoint `post_handler` url = app.url_for('post_handler', post_id=5) - + # Redirect to `/posts/5` return redirect(url) @@ -381,13 +425,12 @@ async def post_handler(request, post_id): 任意の数のキーワード引数を渡すことができます。_not_a要求パラメータであるものはすべて、クエリ文字列の一部として実装されます。 :--:1 ```python ->>> app.url_for( +assert app.url_for( "post_handler", post_id=5, arg_one="one", arg_two="two", -) -'/posts/5?arg_one=one&arg_two=two' +) == "/posts/5?arg_one=one&arg_two=two" ``` :--- @@ -396,12 +439,11 @@ async def post_handler(request, post_id): また、1つのクエリキーに複数の値を渡すこともサポートされています。 :--:1 ```python ->>> app.url_for( +assert app.url_for( "post_handler", post_id=5, arg_one=["one", "two"], -) -'/posts/5?arg_one=one&arg_one=two' +) == "/posts/5?arg_one=one&arg_one=two" ``` :--- @@ -410,20 +452,20 @@ async def post_handler(request, post_id): See [API Docs]() for more details. ```python ->>> app.url_for("post_handler", post_id=5, arg_one="one", _anchor="anchor") -'/posts/5?arg_one=one#anchor' +app.url_for("post_handler", post_id=5, arg_one="one", _anchor="anchor") +# '/posts/5?arg_one=one#anchor' # _external requires you to pass an argument _server or set SERVER_NAME in app.config if not url will be same as no _external ->>> app.url_for("post_handler", post_id=5, arg_one="one", _external=True) -'//server/posts/5?arg_one=one' +app.url_for("post_handler", post_id=5, arg_one="one", _external=True) +# '//server/posts/5?arg_one=one' # when specifying _scheme, _external must be True ->>> app.url_for("post_handler", post_id=5, arg_one="one", _scheme="http", _external=True) -'http://server/posts/5?arg_one=one' +app.url_for("post_handler", post_id=5, arg_one="one", _scheme="http", _external=True) +# 'http://server/posts/5?arg_one=one' # you can pass all special arguments at once ->>> app.url_for("post_handler", post_id=5, arg_one=["one", "two"], arg_two=2, _anchor="anchor", _scheme="http", _external=True, _server="another_server:8888") -'http://another_server:8888/posts/5?arg_one=one&arg_one=two&arg_two=2#anchor' +app.url_for("post_handler", post_id=5, arg_one=["one", "two"], arg_two=2, _anchor="anchor", _scheme="http", _external=True, _server="another_server:8888") +# 'http://another_server:8888/posts/5?arg_one=one&arg_one=two&arg_two=2#anchor' ``` ### ルート名をカスタマイズ @@ -444,8 +486,7 @@ def handler(request): ここで、このカスタム名を使用してURLを取得します。 :--:1 ```python ->>> app.url_for("get_handler", foo="bar") -'/get?foo=bar' +assert app.url_for("get_handler", foo="bar") == "/get?foo=bar" ``` :--- @@ -457,10 +498,10 @@ WebsocketルーティングはHTTPメソッドと同様に動作します。 :--:1 ```python async def handler(request, ws): - messgage = "Start" + message = "Start" while True: await ws.send(message) - message = ws.recv() + message = await ws.recv() app.add_websocket_route(handler, "/test") ``` @@ -473,10 +514,10 @@ app.add_websocket_route(handler, "/test") ```python @app.websocket("/test") async def handler(request, ws): - messgage = "Start" + message = "Start" while True: await ws.send(message) - message = ws.recv() + message = await ws.recv() ``` :--- @@ -542,13 +583,19 @@ Sanicから静的ファイルを提供するには、`app.static()`を使用し 1. ファイルが提供されるルート 2. サーバー上のファイルへのパス -詳しくは[API docs]()を見てください。 +詳しくは[APIドキュメント](https://sanic.readthedocs.io/ja/stable/sanic/api/app.html#sanic.app.Sanic.static)を見てください。 + :--:1 ```python -app.static("/static", "/path/to/directory") +app.static("/static/", "/path/to/directory/") ``` :--- + +::: tip +It is generally best practice to end your directory paths with a trailing slash (`/this/is/a/directory/`). This removes ambiguity by being more explicit. +::: + ---:1 個々のファイルを提供することもできます。 @@ -564,8 +611,8 @@ app.static("/", "/path/to/index.html") :--:1 ```python app.static( - "/user/uploads", - "/path/to/uploads", + "/user/uploads/", + "/path/to/uploads/", name="uploads", ) ``` @@ -576,20 +623,18 @@ app.static( URLの取得は、ハンドラと同様に機能します。ただし、ディレクトリ内に特定のファイルが必要な場合は、`filename`引数を追加することもできます。 :--:1 ```python ->>> app.url_for( +assert app.url_for( "static", name="static", filename="file.txt", -) -'/static/file.txt' - +) == "/static/file.txt" +``` ```python ->>> app.url_for( +assert app.url_for( "static", name="uploads", filename="image.png", -) -'/user/uploads/image.png' +) == "/user/uploads/image.png" ``` :--- @@ -598,13 +643,38 @@ URLの取得は、ハンドラと同様に機能します。ただし、ディ 複数の`static()`ルートを使用する場合は、手動で名前を付けることを推奨します。これにより、バグを発見するのが難しい可能性がほぼ確実に軽減されます。 ```python -app.static("/user/uploads", "/path/to/uploads", name="uploads") -app.static("/user/profile", "/path/to/profile", name="profile_pics") +app.static("/user/uploads/", "/path/to/uploads/", name="uploads") +app.static("/user/profile/", "/path/to/profile/", name="profile_pics") ``` ::: +#### Auto index serving + +---:1 +If you have a directory of static files that should be served by an index page, you can provide the filename of the index. Now, when reaching that directory URL, the index page will be served. +:--: +```python +app.static("/foo/", "/path/to/foo/", index="index.html") +``` +:--- + +*Added in v23.3* + +#### File browser + + +---:1 +When serving a directory from a static handler, Sanic can be configured to show a basic file browser instead using directory_view=True. +:--: +```python +app.static("/uploads/", "/path/to/dir", directory_view=True) +``` +:--- +![image](~@assets/images/directory-view.png) + +*Added in v23.3* + ## ルートコンテキスト -::: new NEW in v21.12 ---:1 ルートが定義されるとき、`ctx_` という接頭辞を持つキーワード引数をいくつでも追加することができます。これらの値はルートの `ctx` オブジェクトにインジェクションされます。 @@ -628,3 +698,4 @@ async def do_something(request): ... ``` :--- +*Added in v21.12* diff --git a/src/ja/guide/basics/tasks.md b/src/ja/guide/basics/tasks.md index a5b0cf7248..aa21c27ae5 100644 --- a/src/ja/guide/basics/tasks.md +++ b/src/ja/guide/basics/tasks.md @@ -48,20 +48,20 @@ Appを実行する前にバックグラウンドタスクを追加すること `app.run`の前にタスクを追加する例 :---:1 ```python -async def slow_work(...): +async def slow_work(): + ... + +async def even_slower(num): ... app = Sanic(...) -app.add_task(slow_work) # Note: we are passing the callable and not coroutine object `slow_work(...)` +app.add_task(slow_work) # Note: we are passing the callable and not coroutine object ... +app.add_task(even_slower(10)) # ... or we can call the function and pass the coroutine. app.run(...) ``` -::: tip -上記の`slow_work`にパラメータを渡すには、`functools.partial`を使用します。 -::: ## Named tasks -::: new NEW in v21.12 _Python 3.8以上でのみサポートされます_ ---:1 @@ -123,4 +123,5 @@ async def feed(request, ws): await request.app.cancel_task(task_name) request.app.purge_tasks() ``` -::: + +*Added in v21.12* diff --git a/src/ja/guide/best-practices/blueprints.md b/src/ja/guide/best-practices/blueprints.md index 41c2547f70..71e0e8a2f5 100644 --- a/src/ja/guide/best-practices/blueprints.md +++ b/src/ja/guide/best-practices/blueprints.md @@ -43,7 +43,6 @@ Blueprintには、websocketsを実装するための同じ`websocket()`デコレ ---:1 -::: new NEW in v21.12 v21.12 以降では、ブループリントはオブジェクトを追加する前でも後でも登録することができます。以前は、登録時にブループリントにアタッチされたオブジェクトのみがアプリケーション インスタンスにロードされました。 :--:1 ```python @@ -57,11 +56,8 @@ async def bp_root(request): ## Copying ---:1 - `copy()`メソッドを使用すると、設計図とそれにアタッチされているすべてのものを新しいインスタンスにコピーできます。唯一必要な引数は、新しい`name`を渡すことです。ただし、これを使用して、古い設計図の値をオーバーライドすることもできます。 - :--:1 - ```python v1 = Blueprint("Version1", version=1) @@ -81,9 +77,10 @@ Available routes: /v2/something ``` - :--- +*v21.9で追加* + ## Blueprintグループ 設計図は、リストまたはタプルの一部として登録することもでき、レジストラは、設計図のサブシーケンスを再帰的に巡回し、それに従って登録する。Blueprint.groupメソッドは、このプロセスを単純化するために提供されており、フロントエンドから見えるものを模倣する`モック`バックエンドディレクトリ構造を可能にする。次の (かなり不自然な) 例を考えてみましょう。 @@ -185,7 +182,44 @@ app.blueprint(api) ``` :--- -## ミドルウェアー +### Blueprint group prefixes and composability + +As shown in the code above, when you create a group of blueprints you can extend the URL prefix of all the blueprints in the group by passing the `url_prefix` argument to the `Blueprint.group` method. This is useful for creating a mock directory structure for your API. + +::: new NEW in v23.6 +In addition, there is a `name_prefix` argument that can be used to make blueprints reusable and composable. The is specifically necessary when applying a single blueprint to multiple groups. By doing this, the blueprint will be registered with a unique name for each group, which allows the blueprint to be registered multiple times and have its routes each properly named with a unique identifier. + +---:1 +Consider this example. The routes built will be named as follows: +- `TestApp.group-a_bp1.route1` +- `TestApp.group-a_bp2.route2` +- `TestApp.group-b_bp1.route1` +- `TestApp.group-b_bp2.route2` +:--:1 +```python +bp1 = Blueprint("bp1", url_prefix="/bp1") +bp2 = Blueprint("bp2", url_prefix="/bp2") + +bp1.add_route(lambda _: ..., "/", name="route1") +bp2.add_route(lambda _: ..., "/", name="route2") + +group_a = Blueprint.group( + bp1, bp2, url_prefix="/group-a", name_prefix="group-a" +) +group_b = Blueprint.group( + bp1, bp2, url_prefix="/group-b", name_prefix="group-b" +) + +app = Sanic("TestApp") +app.blueprint(group_a) +app.blueprint(group_b) +``` +:--- + +*Name prefixing added in v23.6* +::: + +## ミドルウェア ---:1 @@ -336,6 +370,7 @@ group = Blueprint.group([auth, metrics], version="v1") `Blueprint`は複数のグループに登録することができ、`BlueprintGroup`自体もそれぞれ登録してさらにネストすることができる。これにより、無限の可能性を持つ`Blueprint`コンポジションが作成されます。 +*v21.6で追加* ---:1 この例を見て、2つのハンドラーが実際には5つの異なるルートとしてマウントされていることを確認してください。 :--:1 diff --git a/src/ja/guide/best-practices/decorators.md b/src/ja/guide/best-practices/decorators.md index 2f5016fe28..9a67db5824 100644 --- a/src/ja/guide/best-practices/decorators.md +++ b/src/ja/guide/best-practices/decorators.md @@ -56,7 +56,7 @@ async def test(request): デコレーターは、Sanicでアプリケーションを構築するための**基本**です。これにより、コードの移植性と保守性が向上します。 -Pythonの禅を言い換えてこう言います: 「 (装飾家は) 素晴らしいアイデアの一つです--もっといろいろやってみましょう!" +Zen of Pythonを言い換えてこう言います: 「 (装飾家は) 素晴らしいアイデアの一つです--もっといろいろやってみましょう!" 簡単に実装できるように、ここではコピー/ペースト可能なコードの例を3つ示します。 diff --git a/src/ja/guide/best-practices/exceptions.md b/src/ja/guide/best-practices/exceptions.md index 5a512390b3..ca67ea359b 100644 --- a/src/ja/guide/best-practices/exceptions.md +++ b/src/ja/guide/best-practices/exceptions.md @@ -38,7 +38,6 @@ async def login(request): raise exceptions.NotFound( f"Could not find user with username={request.json.username}" ) - ... ``` :--- @@ -50,6 +49,7 @@ Sanicのすべての例外は `SanicException` から派生します。このク - `message` - `status_code` - `quiet` +- `headers` - `context` - `extra` @@ -103,9 +103,9 @@ raise InvalidUsage("blah blah", quiet=True) :--- ---:1 -::: new NEW in v21.12 デバッグ中に、`quiet=True` プロパティをグローバルに無視したいことがあるかもしれません。このプロパティに関係なく、Sanicにすべての例外をログアウトさせるには、 `NOISY_EXCEPTIONS` を使用します。 -::: + +*v21.12で追加* :--:1 ```python app.config.NOISY_EXCEPTIONS = True @@ -113,11 +113,30 @@ app.config.NOISY_EXCEPTIONS = True :--- ---:1 -::: new NEW in v21.12 +### `headers` + +Using `SanicException` as a tool for creating responses is super powerful. This is in part because not only can you control the `status_code`, but you can also control reponse headers directly from the exception. +:--:1 +```python +class MyException(SanicException): + headers = { + "X-Foo": "bar" + } + +raise MyException +# or +raise InvalidUsage("blah blah", headers={ + "X-Foo": "bar" +}) +``` +:--- + +---:1 ### `extra` [文脈上の例外](./exceptions.md#contextual-exceptions)を参照してください。 -::: + +*v21.12で追加* :--:1 ```python raise SanicException(..., extra={"name": "Adam"}) @@ -125,11 +144,11 @@ raise SanicException(..., extra={"name": "Adam"}) :--- ---:1 -::: new NEW in v21.12 ### `context` [文脈上の例外](./exceptions.md#contextual-exceptions)を参照してください。 -::: + +*v21.12で追加* :--:1 ```python raise SanicException(..., context={"foo": "bar"}) @@ -193,11 +212,10 @@ app.error_handler.add(Exception, server_error_handler) Sanicには、例外用にHTML、JSON、およびテキストの3つの形式が用意されています。以下の [Fallback handler](#fallback-handler) セクションに例があります。 ---:1 - route_which形式を使用するには、`error_format`キーワード引数を使用します。 +*v21.9で追加* :--:1 - ```python @app.request("/", error_format="text") async def handler(request): @@ -215,10 +233,14 @@ async def handler(request): from sanic.handlers import ErrorHandler class CustomErrorHandler(ErrorHandler): - def default(self, request, exception): + def default(self, request: Request, exception: Exception) -> HTTPResponse: ''' handles errors that have no error handlers assigned ''' # You custom error handling logic... - return super().default(request, exception) + status_code = getattr(exception, "status_code", 500) + return json({ + "error": str(exception), + "foo": "bar" + }, status=status_code) app.error_handler = CustomErrorHandler() ``` @@ -227,12 +249,14 @@ app.error_handler = CustomErrorHandler() Sanicには3つのフォールバック例外ハンドラがあります。 -1. HTML (*default*) +1. HTML 2. Text 3. JSON これらのハンドラは、アプリケーションが[デバッグモード](/guide/deployment/development.md)にあるかどうかによって、異なる詳細レベルを表示します。 +By default, Sanic will be in "auto" mode, which means that it will using the incoming request and potential matching handler to choose the appropriate response format. For example, when in a browser it should always provide an HTML error page. When using curl, you might see JSON or plain text. + ### HTML ```python @@ -281,13 +305,16 @@ content-type: text/plain; charset=utf-8 That time when that thing broke that other thing? That happened. ServerError: That time when that thing broke that other thing? That happened. while handling path /exc -Traceback of __BASE__ (most recent call last): +Traceback of TestApp (most recent call last): ServerError: That time when that thing broke that other thing? That happened. - File /path/to/sanic/app.py, line 986, in handle_request + File /path/to/sanic/app.py, line 979, in handle_request response = await response - File /path/to/server.py, line 222, in exc + File /path/to/server.py, line 16, in handler + do_something(cause_error=True) + + File /path/to/something.py, line 9, in do_something raise ServerError( ``` @@ -343,22 +370,26 @@ content-type: application/json "frames": [ { "file": "/path/to/sanic/app.py", - "line": 986, + "line": 979, "name": "handle_request", "src": "response = await response" }, { "file": "/path/to/server.py", - "line": 222, - "name": "exc", + "line": 16, + "name": "handler", + "src": "do_something(cause_error=True)" + }, + { + "file": "/path/to/something.py", + "line": 9, + "name": "do_something", "src": "raise ServerError(" } ] } ] } - - ``` :--:1 @@ -370,7 +401,7 @@ app.config.DEBUG = False ```bash $ curl localhost:8000/exc -i HTTP/1.1 500 Internal Server Error -content-length: 530 +content-length: 129 connection: keep-alive content-type: application/json @@ -384,16 +415,15 @@ content-type: application/json :--- -### 自動 +### Auto -Sanicには、使用するフォールバックオプションを推測するためのオプションも用意されています。これはまだ**実験的な機能です**. +Sanicには、使用するフォールバックオプションを推測するためのオプションも用意されています。 ```python app.config.FALLBACK_ERROR_FORMAT = "auto" ``` ## 文脈上の例外 -::: new NEW in v21.12 デフォルトの例外メッセージにより、アプリケーション全体で一貫して例外を発生させる機能を簡素化できます。 ```python @@ -409,7 +439,27 @@ raise TeapotError 1. ダイナミックで予測可能なメッセージのフォーマット 2. エラーメッセージに追加のコンテキストを追加する機能(詳細は後述します) -### `Extra` を使用した動的で予測可能なメッセージ +*v21.12で追加* + +Using one of Sanic's exceptions, you have two options to provide additional details at runtime: + +```python +raise TeapotError(extra={"foo": "bar"}, context={"foo": "bar"}) +``` + +What's the difference and when should you decide to use each? + +- `extra` - The object itself will **never** be sent to a production client. It is meant for internal use only. What could it be used for? + - Generating (as we will see in a minute) a dynamic error message + - Providing runtime details to a logger + - Debug information (when in development mode, it is rendered) +- `context` - This object is **always** sent to production clients. It is generally meant to be used to send additional details about the context of what happened. What could it be used for? + - Providing alternative values on a `BadRequest` validation issue + - Responding with helpful details for your customers to open a support ticket + - Displaying state information like current logged in user info + + +### `extra` を使用した動的で予測可能なメッセージ Sanic の例外は `extra` キーワード引数を使って発生させることができ、発生した例外インスタンスに追加情報を提供することができます。 @@ -495,4 +545,24 @@ raise TeapotError(context={"foo": "bar"}) } ``` :--- + + +::: new NEW in v23.6 + +## Error reporting + +Sanic has a [signal](../advanced/signals.md#built-in-signals) that allows you to hook into the exception reporting process. This is useful if you want to send exception information to a third party service like Sentry or Rollbar. This can be conveniently accomplished by attaching an error reporting handler as show below: + +```python +@app.report_exception +async def catch_any_exception(app: Sanic, exception: Exception): + print("Caught exception:", exception) +``` + +::: tip NOTE +This handler will be dispatched into a background task and **IS NOT** intended for use to manipulate any response data. It is intended to be used for logging or reporting purposes only, and should not impact the ability of your application to return the error response to the client. ::: + +*Added in v23.6* +::: + diff --git a/src/ja/guide/best-practices/testing.md b/src/ja/guide/best-practices/testing.md index 54743da43b..9a31101d6a 100644 --- a/src/ja/guide/best-practices/testing.md +++ b/src/ja/guide/best-practices/testing.md @@ -1,3 +1,3 @@ # Testing -[sanic-testing](../../plugins/sanic-testing/testing.md)をみて +[sanic-testing](../../plugins/sanic-testing/testing.md)を参照 diff --git a/src/ja/guide/deployment/app-loader.md b/src/ja/guide/deployment/app-loader.md new file mode 100644 index 0000000000..eb61f6c147 --- /dev/null +++ b/src/ja/guide/deployment/app-loader.md @@ -0,0 +1,81 @@ +# Dynamic Applications + +Running Sanic has been optimized to work with the CLI. If you have not read it yet, you should read [Running Sanic](./running.md#sanic-server) to become familiar with the options. + +---:1 +This includes running it as a global scope object... +:--:1 +```sh +sanic path.to.server:app +``` +```python +# server.py +app = Sanic("TestApp") + +@app.get("/") +async def handler(request: Request): + return json({"foo": "bar"}) +``` +:--- + + +---:1 +...or, a factory function that creates the `Sanic` application object. +:--:1 +```sh +sanic path.to.server:create_app --factory +``` +```python +# server.py +def create_app(): + app = Sanic("TestApp") + + @app.get("/") + async def handler(request: Request): + return json({"foo": "bar"}) + + return app +``` +:--- + + +**Sometimes, this is not enough ... :thinking:** + +Introduced in [v22.9](../release-notes/v22.9.md), Sanic has an `AppLoader` object that is responsible for creating an application in the various [worker processes](./manager.md#how-sanic-server-starts-processes). You can take advantage of this if you need to create a more dynamic startup experience for your application. + +---:1 +An `AppLoader` can be passed a callable that returns a `Sanic` instance. That `AppLoader` could be used with the low-level application running API. +:--:1 +```python +import sys +from functools import partial + +from sanic import Request, Sanic, json +from sanic.worker.loader import AppLoader + + +def attach_endpoints(app: Sanic): + @app.get("/") + async def handler(request: Request): + return json({"app_name": request.app.name}) + + +def create_app(app_name: str) -> Sanic: + app = Sanic(app_name) + attach_endpoints(app) + return app + + +if __name__ == "__main__": + app_name = sys.argv[-1] + loader = AppLoader(factory=partial(create_app, app_name)) + app = loader.load() + app.prepare(port=9999, dev=True) + Sanic.serve(primary=app, app_loader=loader) +``` +```sh +python path/to/server.py MyTestAppName +``` +:--- + +In the above example, the `AppLoader` is created with a `factory` that can be used to create copies of the same application across processes. When doing this, you should explicitly use the `Sanic.serve` pattern shown above so that the `AppLoader` that you create is not replaced. diff --git a/src/ja/guide/deployment/caddy.md b/src/ja/guide/deployment/caddy.md new file mode 100644 index 0000000000..1875a93ba1 --- /dev/null +++ b/src/ja/guide/deployment/caddy.md @@ -0,0 +1,74 @@ +# Caddy Deployment + +## Introduction + +Caddy is a state-of-the-art web server and proxy that supports up to HTTP/3. Its simplicity lies in its minimalistic configuration and the inbuilt ability to automatically procure TLS certificates for your domains from Let's Encrypt. In this setup, we will configure the Sanic application to serve locally at 127.0.0.1:8001, with Caddy playing the role of the public-facing server for the domain example.com. + +You may install Caddy from your favorite package menager on Windows, Linux and Mac. The package is named `caddy`. + +## Proxied Sanic app + +```python +from sanic import Sanic +from sanic.response import text + +app = Sanic("proxied_example") + +@app.get("/") +def index(request): + # This should display external (public) addresses: + return text( + f"{request.remote_addr} connected to {request.url_for('index')}\n" + f"Forwarded: {request.forwarded}\n" + ) +``` + +To run this application, save as `proxied_example.py`, and use the sanic command-line interface as follows: + +```bash +SANIC_PROXIES_COUNT=1 sanic proxied_example --port 8001 +``` + +Setting the SANIC_PROXIES_COUNT environment variable instructs Sanic to trust the X-Forwarded-* headers sent by Caddy, allowing it to correctly identify the client's IP address and other information. + +## Caddy is simple + +If you have no other web servers running, you can simply run Caddy CLI (needs `sudo` on Linux): + +```bash +caddy reverse-proxy --from example.com --to :8001 +``` + +This is a complete server that includes a certificate for your domain, http-to-https redirect, proxy headers, streaming and WebSockets. Your Sanic application should now be available on the domain you specified by HTTP versions 1, 2 and 3. Remember to open up UDP/443 on your firewall to enable H3 communications. + +All done? + +Soon enough you'll be needing more than one server, or more control over details, which is where the configuration files come in. The above command is equivalent to this `Caddyfile`, serving as a good starting point for your install: + +```caddy +example.com { + reverse_proxy localhost:8001 +} +``` + +Some Linux distributions install Caddy such that it reads configuration from `/etc/caddy/Caddyfile`, which `import /etc/caddy/conf.d/*` for each site you are running. If not, you'll need to manually run `caddy run` as a system service, pointing it at the proper config file. Alternatively, use Caddy API mode with `caddy run --resume` for persistent config changes. Note that any Caddyfile loading will replace all prior configuration and thus `caddy-api` is not configurable in this traditional manner. + +## Advanced configuration + +At times, you might need to mix static files and handlers at the site root for cleaner URLs. In Sanic, you'd use `app.static("/", "static", index="index.html")` to achieve this. However, for improved performance, you can offload serving static files to Caddy: + +```caddy +app.example.com { + # Look for static files first, proxy to Sanic if not found + route { + file_server { + root /srv/sanicexample/static + precompress br # brotli your large scripts and styles + pass_thru + } + reverse_proxy unix//tmp/sanic.socket # sanic --unix /tmp/sanic.socket + } +} +``` + +Please refer to [Caddy documentation](https://caddyserver.com/docs/) for more options. diff --git a/src/ja/guide/deployment/configuration.md b/src/ja/guide/deployment/configuration.md index 9b3140f273..a6f58bb74a 100644 --- a/src/ja/guide/deployment/configuration.md +++ b/src/ja/guide/deployment/configuration.md @@ -57,7 +57,7 @@ $ export SANIC_REQUEST_TIMEOUT=10 $ export MYAPP_REQUEST_TIMEOUT=10 ``` ```python ->>> app = Sanic(__name__, load_env='MYAPP_') +>>> app = Sanic(__name__, env_prefix='MYAPP_') >>> print(app.config.REQUEST_TIMEOUT) 10 ``` @@ -163,16 +163,17 @@ app.update_config(MyConfig()) - **`True`**: `y`, `yes`, `yep`, `yup`, `t`, `true`, `on`, `enable`, `enabled`, `1` - **`False`**: `n`, `no`, `f`, `false`, `off`, `disable`, `disabled`, `0` -::: new NEW in v21.12 +If a value cannot be cast, it will default to a `str`. ---:1 さらに、Sanicは追加のタイプコンバータを使用して、追加の型をキャストするように設定することができます。これは、値を返すか、`ValueError`を発生させる任意のcallableでなければならない。 + +*Added in v21.12* :--:1 ```python app = Sanic(..., config=Config(converters=[UUID])) ``` :--- -::: ## 組み込み値 @@ -180,18 +181,24 @@ app = Sanic(..., config=Config(converters=[UUID])) | **変数** | **デフォルト** | **説明** | |--|--|--| | ACCESS_LOG | True | アクセスログを無効または有効にする。 -| AUTO_EXTEND ^ | True | [Sanic Extensions](../../plugins/sanic-ext/getting-started.md) が既存の仮想環境内にある場合にロードするかどうかを制御する | +| AUTO_EXTEND | True | [Sanic Extensions](../../plugins/sanic-ext/getting-started.md) が既存の仮想環境内にある場合にロードするかどうかを制御する | | AUTO_RELOAD | True | ファイルが変更されたときにアプリケーションが自動的にリロードするかどうかを制御します。 | | EVENT_AUTOREGISTER | True | `True` のとき、存在しないシグナルに対して `app.event()` メソッドを使用すると、自動的にシグナルを生成して例外を発生させないEVENT_AUTOREGISTER.index.index. | -| FALLBACK_ERROR_FORMAT|html| 例外が発生し処理されなかった場合のエラー応答のフォーマット | -| FORWARDED_FOR_HEADER| X-Forwarded-For| クライアントとプロキシのIPを含む「X-Forwarded-For」HTTPヘッダの名前です。 | +| FALLBACK_ERROR_FORMAT | html | 例外が発生し処理されなかった場合のエラー応答のフォーマット | +| FORWARDED_FOR_HEADER | X-Forwarded-For| クライアントとプロキシのIPを含む「X-Forwarded-For」HTTPヘッダの名前です。 | | FORWARDED_SECRET|なし|特定のプロキシサーバーを安全に識別するために使用される(下記参照) | | GRACEFUL_SHUTDOWN_TIMEOUT | 15.0 | アイドルでない接続を強制終了するまでの時間(秒) | +| INSPECTOR | False | Whether to enable the Inspector | +| INSPECTOR_HOST | localhost | The host for the Inspector | +| INSPECTOR_PORT | 6457 | The port for the Inspector | +| INSPECTOR_TLS_KEY | - | The TLS key for the Inspector | +| INSPECTOR_TLS_CERT | - | The TLS certificate for the Inspector | +| INSPECTOR_API_KEY | - | The API key for the Inspector | +| KEEP_ALIVE_TIMEOUT | 120 | How long to hold a TCP connection open (sec) | | KEEP_ALIVE | True | Falseの場合、キープアライブを無効にする。 | -| KEEP_ALIVE_TIMEOUT | 5 | TCP接続を開いたままにする時間(秒) | -| MOTD ^ | True | 起動時にMOTD(今日のメッセージ)を表示するかどうか | -| MOTD_DISPLAY ^ | {} | MOTDに任意のデータを追加表示するためのキー/バリュー・ペア | -| NOISY_EXCEPTIONS ^ | False | すべての `quiet` 例外を強制的にログに記録する | +| MOTD | True | 起動時にMOTD(今日のメッセージ)を表示するかどうか | +| MOTD_DISPLAY | {} | MOTDに任意のデータを追加表示するためのキー/バリュー・ペア | +| NOISY_EXCEPTIONS | False | すべての `quiet` 例外を強制的にログに記録する | | PROXIES_COUNT | なし | アプリの前にあるプロキシサーバーの数(例:nginx) | | REAL_IP_HEADER | なし | 本当のクライアントIPを含む「X-Real-IP」HTTPヘッダーの名前 | REAL_IP_HEADER | なし | | REGISTER | True | アプリのレジストリを有効にするかどうか。 | @@ -206,13 +213,12 @@ app = Sanic(..., config=Config(converters=[UUID])) | WEBSOCKET_PING_INTERVAL | 20 | Pingフレームはping_interval秒ごとに送信されます。 | | WEBSOCKET_PING_TIMEOUT | 20 |ping_timeout秒後にPongを受信しない場合、接続を終了します。| -::: new NEW in v21.12 -新要素: `AUTO_EXTEND`, `MOTD`, `MOTD_DISPLAY`, `NOISY_EXCEPTIONS` -::: - ::: tip FYI - `USE_UVLOOP` の値は、Gunicorn で実行されている場合、無視されます。サポートされていないプラットフォーム (Windows) では、デフォルトは `False` である。 - ASGI モードでは `WEBSOCKET_` 値は無視されます。 +- v21.12 added: `AUTO_EXTEND`, `MOTD`, `MOTD_DISPLAY`, `NOISY_EXCEPTIONS` +- v22.9 added: `INSPECTOR` +- v22.12 added: `INSPECTOR_HOST`, `INSPECTOR_PORT`, `INSPECTOR_TLS_KEY`, `INSPECTOR_TLS_CERT`, `INSPECTOR_API_KEY` ::: ## タイムアウト @@ -233,13 +239,14 @@ app = Sanic(..., config=Config(converters=[UUID])) Sanicでは、`KEEP_ALIVE`設定変数がデフォルトで `True` に設定されています。アプリケーションでこの機能を必要としない場合は、`False`に設定すると、リクエストの `Keep-Alive` ヘッダに関係なく、レスポンスが送信された後にすべてのクライアント接続を直ちに終了するようになります。 -サーバーが TCP 接続を開いたままにする時間は、サーバー自身が決定します。Sanic では、その値は `KEEP_ALIVE_TIMEOUT` 値を使用して設定されます。デフォルトでは、5秒に設定されています。これは Apache HTTP サーバーと同じデフォルト設定で、クライアントが新しいリクエストを送信するのに十分な時間を与えることと、一度に多くのコネクションをオープンしないことのバランスが取れています。クライアントが、その時間だけ開いたままの TCP 接続をサポートするブラウザを使用していることが分かっている場合を除き、75 秒を超えないようにしてください。 +サーバーが TCP 接続を開いたままにする時間は、サーバー自身が決定します。Sanic では、その値は `KEEP_ALIVE_TIMEOUT` 値を使用して設定されます。デフォルトでは、**it is set to 120 seconds**. This means that if the client sends a `Keep-Alive` header, the server will hold the TCP connection open for 120 seconds after sending the response, and the client can reuse the connection to send another HTTP request within that time. 参考までに * Apache httpd サーバーのデフォルトのキープアライブタイムアウト = 5 秒 * Nginxサーバのデフォルトのキープアライブタイムアウトは75秒です。 * Nginx パフォーマンスチューニングガイドラインでは、keepalive = 15 秒を使用しています。 +* Caddy server default keepalive timeout = 120 seconds * IE(5-9)クライアントのハードキープアライブ制限 = 60秒 * Firefoxクライアントハードキープアライブ制限=115秒 * Opera 11クライアントハードキープアライブ制限 = 120秒 diff --git a/src/ja/guide/deployment/development.md b/src/ja/guide/deployment/development.md index df8759e7a2..8cae9faa31 100644 --- a/src/ja/guide/deployment/development.md +++ b/src/ja/guide/deployment/development.md @@ -1,14 +1,15 @@ # Development -まず、Sanicに統合されているウェブサーバは、単なる開発サーバではありません。 +The first thing that should be mentioned is that the webserver that is integrated into Sanic is **not** just a development server. -デバッグ・モードで*not*であれば、本番環境で使用できます。 +It is production ready out-of-the-box, *unless you enable in debug mode*. -## デバッグ・モード +## Debug mode -デバッグモードを設定すると、Sanicからより詳細な出力が出力され、Automatic Reloaderがアクティブになります。 +By setting the debug mode, Sanic will be more verbose in its output and will disable several run-time optimizations. ```python +# server.py from sanic import Sanic from sanic.response import json @@ -17,21 +18,86 @@ app = Sanic(__name__) @app.route("/") async def hello_world(request): return json({"hello": "world"}) - -if __name__ == "__main__": - app.run(host="0.0.0.0", port=1234, debug=True) +``` +```sh +sanic server:app --host=0.0.0.0 --port=1234 --debug ``` ::: warning -Sanicのデバッグモードは、サーバのパフォーマンスを低下させるため、開発環境でのみ有効にすることをお勧めします。 +Sanic's debug mode will slow down the server's performance and is therefore advised to enable it only in development environments. ::: -## 自動的に読み込む +## Automatic Reloader + +---:1 + +Sanic offers a way to enable or disable the Automatic Reloader. The easiest way to enable it is using the CLI's `--reload` argument to activate the Automatic Reloader. Every time a Python file is changed, the reloader will restart your application automatically. This is very convenient while developing. + +*NOTE: The reloader is only available when using Sanic's [worker manager](./manager.md). If you have disabled it using `--single-process` then the reloader will not be available to you.* +:--:1 +```sh +sanic path.to:app --reload +``` +You can also use the shorthand property +```sh +sanic path.to:app -r +``` +:--- ---:1 +If you have additional directories that you would like to automatically reload on file save (for example, a directory of HTML templates), you can add that using `--reload-dir`. +:--:1 +```sh +sanic path.to:app --reload --reload-dir=/path/to/templates +``` +Or multiple directories, shown here using the shorthand properties +```sh +sanic path.to:app -r -R /path/to/one -R /path/to/two +``` +:--- + +## Best of both worlds +---:1 +If you would like to be in debug mode **and** have the Automatic Reloader running, you can pass `dev=True`. This is equivalent to **debug + auto reload**. + +*Added in v22.3* +:--:1 +```sh +sanic path.to:app --dev +``` +You can also use the shorthand property +```sh +sanic path.to:app -d +``` +:--- + +## Automatic TLS certificate + +When running in `DEBUG` mode, you can ask Sanic to handle setting up localhost temporary TLS certificates. This is helpful if you want to access your local development environment with `https://`. -Sanicでは、Automatic Reloaderを手動で (デバッグモードから独立して) 有効または無効にする方法を提供しています。`auto_reload`引数は、自動リローダーをアクティブまたは非アクティブにします。 +This functionality is provided by either [mkcert](https://github.com/FiloSottile/mkcert) or [trustme](https://github.com/python-trio/trustme). Both are good choices, but there are some differences. `trustme` is a Python library and can be installed into your environment with `pip`. This makes for easy envrionment handling, but it is not compatible when running a HTTP/3 server. `mkcert` might be a more involved installation process, but can install a local CA and make it easier to use. + +---:1 +You can choose which platform to use by setting `config.LOCAL_CERT_CREATOR`. When set to `"auto"`, it will select either option, preferring `mkcert` if possible. :--:1 ```python -app.run(auto_reload=True) +app.config.LOCAL_CERT_CREATOR = "auto" +app.config.LOCAL_CERT_CREATOR = "mkcert" +app.config.LOCAL_CERT_CREATOR = "trustme" +``` +:--- + + +---:1 +Automatic TLS can be enabled at Sanic server run time: +:--:1 +```sh +sanic path.to.server:app --auto-tls --debug ``` :--- + +::: warning + +Localhost TLS certificates (like those generated by both `mkcert` and `trustme`) are **NOT** suitable for production environments. If you are not familiar with how to obtain a *real* TLS certificate, checkout the [How to...](../how-to/tls.md) section. +::: + +*Added in v22.6* diff --git a/src/ja/guide/deployment/docker.md b/src/ja/guide/deployment/docker.md index c597eaa5eb..47f4966b27 100644 --- a/src/ja/guide/deployment/docker.md +++ b/src/ja/guide/deployment/docker.md @@ -1 +1,183 @@ -# Docker +# Docker Deployment + +## Introduction + +For a long time, the environment has always been a difficult problem for deployment. If there are conflicting configurations in your project, you have to spend a lot of time resolving them. Fortunately, virtualization provides us with a good solution. Docker is one of them. If you don't know Docker, you can visit [Docker official website](https://www.docker.com/) to learn more. + +## Build Image + +Let's start with a simple project. We will use a Sanic project as an example. Assume the project path is `/path/to/SanicDocker`. + +---:1 + +The directory structure looks like this: + +:--:1 + +```text +# /path/to/SanicDocker +SanicDocker +├── requirements.txt +├── dockerfile +└── server.py +``` + +:--- + +---:1 + +And the `server.py` code looks like this: + +:--:1 + +```python +app = Sanic("MySanicApp") + +@app.get('/') +async def hello(request): + return text("OK!") + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=8000) +``` + +:--- + +::: tip + +Please note that the host cannot be 127.0.0.1 . In docker container, 127.0.0.1 is the default network interface of the container, only the container can communicate with other containers. more information please visit [Docker network](https://docs.docker.com/engine/reference/commandline/network/) + +::: + +Code is ready, let's write the `Dockerfile`: + +```Dockerfile + +FROM sanicframework/sanic:3.8-latest + +WORKDIR /sanic + +COPY . . + +RUN pip install -r requirements.txt + +EXPOSE 8000 + +CMD ["python", "server.py"] +``` + +Run the following command to build the image: + +```shell +docker build -t my-sanic-image . +``` + +## Start Container + +---:1 + +After the image built, we can start the container use `my-sanic-image`: + +:--:1 + +```shell +docker run --name mysanic -p 8000:8000 -d my-sanic-image +``` + +:--- + +---:1 + +Now we can visit `http://localhost:8000` to see the result: + +:--:1 + +```text +OK! +``` + +:--- + +## Use docker-compose + +If your project consist of multiple services, you can use [docker-compose](https://docs.docker.com/compose/) to manage them. + +for example, we will deploy `my-sanic-image` and `nginx`, achieve through nginx access sanic server. + +---:1 + +First of all, we need prepare nginx configuration file. create a file named `mysanic.conf`: + +:--:1 + +```nginx +server { + listen 80; + listen [::]:80; + location / { + proxy_pass http://mysanic:8000/; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection upgrade; + proxy_set_header Accept-Encoding gzip; + } +} +``` + +:--- + +---:1 + +Then, we need to prepare `docker-compose.yml` file. The content follows: + +:--:1 + +```yml +version: "3" + +services: + mysanic: + image: my-sanic-image + ports: + - "8000:8000" + restart: always + + mynginx: + image: nginx:1.13.6-alpine + ports: + - "80:80" + depends_on: + - mysanic + volumes: + - ./mysanic.conf:/etc/nginx/conf.d/mysanic.conf + restart: always + +networks: + default: + driver: bridge +``` + +:--- + +---:1 + +After that, we can start them: + +:--:1 + +```shell +docker-compose up -d +``` + +:--- + +---:1 + +Now, we can visit `http://localhost:80` to see the result: + +:--:1 + +```text +OK! +``` + +:--- diff --git a/src/ja/guide/deployment/inspector.md b/src/ja/guide/deployment/inspector.md new file mode 100644 index 0000000000..a75dbaae56 --- /dev/null +++ b/src/ja/guide/deployment/inspector.md @@ -0,0 +1,180 @@ +# Inspector + +The Sanic Inspector is a feature of Sanic Server. It is *only* available when running Sanic with the built-in [worker manager](./manager.md). + +It is an HTTP application that *optionally* runs in the background of your application to allow you to interact with the running instance of your application. + +::: tip INFO +The Inspector was introduced in limited capacity in v22.9, but the documentation on this page assumes you are using v22.12 or higher. +::: + +## Getting Started + +The inspector is disabled by default. To enable it, you have two options. + +---:1 +Set a flag when creating your application instance. +:--:1 +```python +app = Sanic("TestApp", inspector=True) +``` +:--- + +---:1 +Or, set a configuration value. +:--:1 +```python +app = Sanic("TestApp") +app.config.INSPECTOR = True +``` +:--- + +::: warning +If you are using the configuration value, it *must* be done early and before the main worker process starts. This means that it should either be an environment variable, or it should be set shortly after creating the application instance as shown above. +::: + +## Using the Inspector + +Once the inspector is running, you will have access to it via the CLI or by directly accessing its web API via HTTP. + +---:1 +**Via CLI** +```sh +sanic inspect +``` +:--:1 +**Via HTTP** +```sh +curl http://localhost:6457 +``` +:--- + +::: tip +Remember, the Inspector is not running on your Sanic application. It is a seperate process, with a seperate application, and exposed on a seperate socket. +::: + +## Built-in Commands + +The Inspector comes with the following built-in commands. + +| CLI Command | HTTP Action | Description | +|--------------------|------------------------------------|--------------------------------------------------------------------------| +| `inspect` | `GET /` | Display basic details about the running application. | +| `inspect reload` | `POST /reload` | Trigger a reload of all server workers. | +| `inspect shutdown` | `POST /shutdown` | Trigger a shutdown of all processes. | +| `inspect scale N` | `POST /scale`
`{"replicas": N}` | Scale the number of workers. Where `N` is the target number of replicas. | + +## Custom Commands + +The Inspector is easily extendable to add custom commands (and endpoints). + +---:1 +Subclass the `Inspector` class and create arbitrary methods. As long as the method name is not preceded by an underscore (`_`), then the name of the method will be a new subcommand on the inspector. +:--:1 +```python +from sanic import json +from sanic.worker.inspector import Inspector + + +class MyInspector(Inspector): + async def something(self, *args, **kwargs): + print(args) + print(kwargs) + + +app = Sanic("TestApp", inspector_class=MyInspector, inspector=True) +``` +:--- + +This will expose custom methods in the general pattern: + +- CLI: `sanic inspect ` +- HTTP: `POST /` + +It is important to note that the arguments that the new method accepts are derived from how you intend to use the command. For example, the above `something` method accepts all positional and keyword based parameters. + +---:1 +In the CLI, the positional and keyword parameters are passed as either positional or keyword arguments to your method. All values will be a `str` with the following exceptions: + +- A keyword parameter with no assigned value will be: `True` +- Unless the parameter is prefixed with `no-`, then it will be: `False` +:--:1 +```sh +sanic inspect something one two three --four --no-five --six=6 +``` +In your application log console, you will see: +``` +('one', 'two', 'three') +{'four': True, 'five': False, 'six': '6'} +``` +:--- + +---:1 +The same can be achieved by hitting the API directly. You can pass arguments to the method by exposing them in a JSON payload. The only thing to note is that the positional arguments should be exposed as `{"args": [...]}`. +:--:1 +```sh +curl http://localhost:6457/something \ + --json '{"args":["one", "two", "three"], "four":true, "five":false, "six":6}' +``` +In your application log console, you will see: +``` +('one', 'two', 'three') +{'four': True, 'five': False, 'six': 6} +``` +:--- + + +## Using in production + +::: warning +Before exposing the Inspector on a product, please consider all of the options in this section carefully. +::: + +When running Inspector on a remote production instance, you can protect the endpoints by requiring TLS encryption, and requiring API key authentication. + +### TLS encryption + +---:1 +To the Inspector HTTP instance over TLS, pass the paths to your certificate and key. +:--:1 +```python +app.config.INSPECTOR_TLS_CERT = "/path/to/cert.pem" +app.config.INSPECTOR_TLS_KEY = "/path/to/key.pem" +``` +:--- + +---:1 +This will require use of the `--secure` flag, or `https://`. +:--:1 +```sh +sanic inspect --secure --host= +``` +```sh +curl https://:6457 +``` +:--- + +### API Key Authentication + +---:1 +You can secure the API with bearer token authentication. +:--:1 +```python +app.config.INSPECTOR_API_KEY = "Super-Secret-200" +``` +:--- + +---:1 +This will require the `--api-key` parameter, or bearer token authorization header. +:--:1 +```sh +sanic inspect --api-key=Super-Secret-200 +``` +```sh +curl http://localhost:6457 -H "Authorization: Bearer Super-Secret-200" +``` +:--- + +## Configuration + +See [configuration](./configuration.md) diff --git a/src/ja/guide/deployment/manager.md b/src/ja/guide/deployment/manager.md new file mode 100644 index 0000000000..efbf284a62 --- /dev/null +++ b/src/ja/guide/deployment/manager.md @@ -0,0 +1,313 @@ +# Worker Manager + +The worker manager and its functionality was introduced in version 22.9. + +*The details of this section are intended for more advanced usages and **not** necessary to get started.* + +The purpose of the manager is to create consistency and flexibility between development and production environments. Whether you intend to run a single worker, or multiple workers, whether with, or without auto-reload: the experience will be the same. + + +In general it looks like this: + +![](https://user-images.githubusercontent.com/166269/178677618-3b4089c3-6c6a-4ecc-8d7a-7eba2a7f29b0.png) + +When you run Sanic, the main process instantiates a `WorkerManager`. That manager is in charge of running one or more `WorkerProcess`. There generally are two kinds of processes: + +- server processes, and +- non-server processes. + +For the sake of ease, the User Guide generally will use the term "worker" or "worker process" to mean a server process, and "Manager" to mean the single worker manager running in your main process. + +## How Sanic Server starts processes + +Sanic will start processes using the [spawn](https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods) start method. This means that for every process/worker, the global scope of your application will be run on its own thread. The practical impact of this that *if* you do not run Sanic with the CLI, you will need to nest the execution code inside a block to make sure it only runs on `__main__`. + +```python +if __name__ == "__main__": + app.run() +``` + +If you do not, you are likely to see an error message like this: + +``` +sanic.exceptions.ServerError: Sanic server could not start: [Errno 98] Address already in use. + +This may have happened if you are running Sanic in the global scope and not inside of a `if __name__ == "__main__"` block. + +See more information: https://sanic.dev/en/guide/deployment/manager.html#how-sanic-server-starts-processes +``` + +The likely fix for this problem is nesting your Sanic run call inside of the `__name__ == "__main__"` block. If you continue to receive this message after nesting, or if you see this while using the CLI, then it means the port you are trying to use is not available on your machine and you must select another port. + +### Starting a worker + +All worker processes *must* send an acknowledgement when starting. This happens under the hood, and you as a developer do not need to do anything. However, the Manager will exit with a status code `1` if one or more workers do not send that `ack` message, or a worker process throws an exception while trying to start. If no exceptions are encountered, the Manager will wait for up to thirty (30) seconds for the acknowledgement. + +---:1 +In the situation when you know that you will need more time to start, you can monkeypatch the Manager. The threshold does not include anything inside of a listener, and is limited to the execution time of everything in the global scope of your application. + +If you run into this issue, it may indicate a need to look deeper into what is causing the slow startup. +:--:1 +```python +from sanic.worker.manager import WorkerManager + +WorkerManager.THRESHOLD = 100 # Value is in 0.1s +``` +:--- + +See [worker ack](#worker-ack) for more information. + +---:1 +As stated above, Sanic will use [spawn](https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods) to start worker processes. If you would like to change this behavior and are aware of the implications of using different start methods, you can modify as shown here. +:--:1 +```python +from sanic import Sanic + +Sanic.start_method = "fork" +``` +:--- + + +### Worker ack + +When all of your workers are running in a subprocess a potential problem is created: deadlock. This can occur when the child processes cease to function, but the main process is unaware that this happened. Therefore, Sanic servers will automatically send an `ack` message (short for acknowledge) to the main process after startup. + +In version 22.9, the `ack` timeout was short and limited to `5s`. In version 22.12, the timeout was lengthened to `30s`. If your application is shutting down after thirty seconds then it might be necessary to manually increase this threshhold. + +---:1 +The value of `WorkerManager.THRESHOLD` is in `0.1s` increments. Therefore, to set it to one minute, you should set the value to `600`. + +This value should be set as early as possible in your application, and should ideally happen in the global scope. Setting it after the main process has started will not work. +:--:1 +```python +from sanic.worker.manager import WorkerManager + +WorkerManager.THRESHOLD = 600 +``` +:--- + +### Zero downtime restarts + +By default, when restarting workers, Sanic will teardown the existing process first before starting a new one. + +If you are intending to use the restart functionality in production then you may be interested in having zero-downtime reloading. This can be accomplished by forcing the reloader to change the order to start a new process, wait for it to [ack](#worker-ack), and then teardown the old process. + +---:1 +From the multiplexer, use the `zero_downtime` argument +:--:1 +```python +app.m.restart(zero_downtime=True) +``` +:--- + +*Added in v22.12* + +## Using shared context between worker processes + +Python provides a few methods for [exchanging objects](https://docs.python.org/3/library/multiprocessing.html#exchanging-objects-between-processes), [synchronizing](https://docs.python.org/3/library/multiprocessing.html#synchronization-between-processes), and [sharing state](https://docs.python.org/3/library/multiprocessing.html#sharing-state-between-processes) between processes. This usually involves objects from the `multiprocessing` and `ctypes` modules. + +If you are familiar with these objects and how to work with them, you will be happy to know that Sanic provides an API for sharing these objects between your worker processes. If you are not familiar, you are encouraged to read through the Python documentation linked above and try some of the examples before proceeding with implementing shared context. + +Similar to how [application context](../basics/app.md#application-context) allows an applicaiton to share state across the lifetime of the application with `app.ctx`, shared context provides the same for the special objects mentioned above. This context is available as `app.shared_ctx` and should **ONLY** be used to share objects intended for this purpose. + +The `shared_ctx` will: + +- *NOT* share regular objects like `int`, `dict`, or `list` +- *NOT* share state between Sanic instances running on different machines +- *NOT* share state to non-worker processes +- **only** share state between server workers managed by the same Manager + +Attaching an inappropriate object to `shared_ctx` will likely result in a warning, and not an error. You should be careful to not accidentally add an unsafe object to `shared_ctx` as it may not work as expected. If you are directed here because of one of those warnings, you might have accidentally used an unsafe object in `shared_ctx`. + +---:1 +In order to create a shared object you **must** create it in the main process and attach it inside of the `main_process_start` listener. +:--:1 +```python +from multiprocessing import Queue + +@app.main_process_start +async def main_process_start(app): + app.shared_ctx.queue = Queue() +``` +:--- + +Trying to attach to the `shared_ctx` object outside of this listener may result in a `RuntimeError`. + +---:1 +After creating the objects in the `main_process_start` listener and attaching to the `shared_ctx`, they will be available in your workers wherever the application instance is available (example: listeners, middleware, request handlers). +:--:1 +```python +from multiprocessing import Queue + +@app.get("") +async def handler(request): + request.app.shared_ctx.queue.put(1) + ... +``` +:--- + +## Access to the multiplexer + +The application instance has access to an object that provides access to interacting with the Manager and other worker processes. The object is attached as the `app.multiplexer` property, but it is more easily accessed by its alias: `app.m`. + +---:1 +For example, you can get access to the current worker state. +:--:1 +```python +@app.on_request +async def print_state(request: Request): + print(request.app.m.name) + print(request.app.m.pid) + print(request.app.m.state) +``` +``` +Sanic-Server-0-0 +99999 +{'server': True, 'state': 'ACKED', 'pid': 99999, 'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc), 'starts': 2, 'restart_at': datetime.datetime(2022, 10, 1, 0, 0, 12, 861332, tzinfo=datetime.timezone.utc)} +``` +:--- + +---:1 +The `multiplexer` also has access to terminate the Manager, or restart worker processes +:--:1 +```python +# shutdown the entire application and all processes +app.m.name.terminate() + +# restart the current worker only +app.m.name.restart() + +# restart specific workers only (comma delimited) +app.m.name.restart("Sanic-Server-4-0,Sanic-Server-7-0") + +# restart ALL workers +app.m.name.restart(all_workers=True) # Available v22.12+ +``` +:--- + +## Worker state + +---:1 +As shown above, the `multiplexer` has access to report upon the state of the current running worker. However, it also contains the state for ALL processes running. +:--:1 +```python +@app.on_request +async def print_state(request: Request): + print(request.app.m.workers) +``` +``` +{ + 'Sanic-Main': {'pid': 99997}, + 'Sanic-Server-0-0': { + 'server': True, + 'state': 'ACKED', + 'pid': 9999, + 'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc), + 'starts': 2, + 'restart_at': datetime.datetime(2022, 10, 1, 0, 0, 12, 861332, tzinfo=datetime.timezone.utc) + }, + 'Sanic-Reloader-0': { + 'server': False, + 'state': 'STARTED', + 'pid': 99998, + 'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc), + 'starts': 1 + } +} +``` +:--- + + +## Built-in non-server processes + +As mentioned, the Manager also has the ability to run non-server processes. Sanic comes with two built-in types of non-server processes, and allows for [creating custom processes](#running-custom-processes). + +The two built-in processes are + +- the [auto-reloader](./development.md#automatic-reloader), optionally enabled to watch the file system for changes and trigger a restart +- [inspector](#inspector), optionally enabled to provide external access to the state of the running instance + +## Inspector + +Sanic has the ability to expose the state and the functionality of the `multiplexer` to the CLI. Currently, this requires the CLI command to be run on the same machine as the running Sanic instance. By default the inspector is disabled. + +---:1 +To enable it, set the config value to `True`. +:--:1 +```python +app.config.INSPECTOR = True +``` +:--- + +You will now have access to execute any of these CLI commands: + +``` +sanic inspect reload Trigger a reload of the server workers +sanic inspect shutdown Shutdown the application and all processes +sanic inspect scale N Scale the number of workers to N +sanic inspect Run a custom command +``` + +![](https://user-images.githubusercontent.com/166269/190099384-2f2f3fae-22d5-4529-b279-8446f6b5f9bd.png) + +---:1 +This works by exposing a small HTTP service on your machine. You can control the location using configuration values: +:--:1 +```python +app.config.INSPECTOR_HOST = "localhost" +app.config.INSPECTOR_PORT = 6457 +``` +:--- + +[Learn more](./inspector.md) to find out what is possible with the Inspector. + +## Running custom processes + +To run a managed custom process on Sanic, you must create a callable. If that process is meant to be long-running, then it should handle a shutdown call by a `SIGINT` or `SIGTERM` signal. + +---:1 +The simplest method for doing that in Python will be to just wrap your loop in `KeyboardInterrupt`. + +If you intend to run another application, like a bot, then it is likely that it already has capability to handle this signal and you likely do not need to do anything. +:--:1 +```python +from time import sleep + +def my_process(foo): + try: + while True: + sleep(1) + except KeyboardInterrupt: + print("done") +``` +:--- + +---:1 +That callable must be registered in the `main_process_ready` listener. It is important to note that is is **NOT** the same location that you should register [shared context](#using-shared-context-between-worker-processes) objects. +:--:1 +```python +@app.main_process_ready +async def ready(app: Sanic, _): +# app.manager.manage(, , ) + app.manager.manage("MyProcess", my_process, {"foo": "bar"}) +``` +:--- + +## Single process mode + +---:1 +If you would like to opt out of running multiple processes, you can run Sanic in a single process only. In this case, the Manager will not run. You will also not have access to any features that require processes (auto-reload, the inspector, etc). +:--:1 +```sh +sanic path.to.server:app --single-process +``` +```python +if __name__ == "__main__": + app.run(single_process=True) +``` +```python +if __name__ == "__main__": + app.prepare(single_process=True) + Sanic.serve_single() +``` +:--- diff --git a/src/ja/guide/deployment/nginx.md b/src/ja/guide/deployment/nginx.md index 4bde3db20e..4a0df9be07 100644 --- a/src/ja/guide/deployment/nginx.md +++ b/src/ja/guide/deployment/nginx.md @@ -1,25 +1,25 @@ # Nginx Deployment -## イントロダクション +## Introduction +Although Sanic can be run directly on Internet, it may be useful to use a proxy +server such as Nginx in front of it. This is particularly useful for running +multiple virtual hosts on the same IP, serving NodeJS or other services beside +a single Sanic app, and it also allows for efficient serving of static files. +TLS and HTTP/2 are also easily implemented on such proxy. -Sanicはインターネット上で直接実行できますが、プロキシを使用すると便利な場合があります。 -Nginxのようなサーバーを目の前にします。これは、同じIP上で複数の仮想ホストを実行したり、単一のSanicアプリに加えてNodeJSやその他のサービスを提供したり、静的ファイルを効率的に提供したりする場合に特に便利です。 -SSLとHTTP/2も、このようなプロキシに簡単に実装できます。 +We are setting the Sanic app to serve only locally at 127.0.0.1:8001, while the +Nginx installation is responsible for providing the service to public Internet +on domain example.com. Static files will be served by Nginx for maximal +performance. -私たちはSanicのアプリを`127.0.0.1:8000`でローカルのみにサービスを提供するように設定していますが、Nginxのインストールはドメイン`example.com`上のパブリックインターネットにサービスを提供する責任があります。静的ファイルは`/var/www/`。 - - -## プロキシSanicアプリ - -信頼できるプロキシを識別するために使用される秘密キーを使用してアプリを設定し、実際のクライアントIPおよびその他の情報を識別できるようにする必要があります。これにより、IPアドレスやその他の詳細を偽装するために、インターネット上で偽のヘッダーを送信するすべてのユーザーを保護できます。任意のランダムな文字列を選択し、アプリとNginx configの両方で設定します。 +## Proxied Sanic app ```python from sanic import Sanic from sanic.response import text app = Sanic("proxied_example") -app.config.FORWARDED_SECRET = "YOUR SECRET" @app.get("/") def index(request): @@ -28,29 +28,55 @@ def index(request): f"{request.remote_addr} connected to {request.url_for('index')}\n" f"Forwarded: {request.forwarded}\n" ) +``` -if __name__ == "__main__": - app.run(host="127.0.0.1", port=8000, workers=8, access_log=False) +Since this is going to be a system service, save your code to +`/srv/sanicservice/proxied_example.py`. + +For testing, run your app in a terminal using the `sanic` CLI in the folder where you saved the file. + +```bash +SANIC_FORWARDED_SECRET=_hostname sanic proxied_example --port 8001 ``` -これはシステムサービスになるので、コードを次の場所に保存します。 -`/srv/sanicexample/sanicexample.py` +We provide Sanic config `FORWARDED_SECRET` to identify which proxy it gets +the remote addresses from. Note the `_` in front of the local hostname. +This gives basic protection against users spoofing these headers and faking +their IP addresses and more. -テストでは、ターミナルでアプリを実行します。 +## SSL certificates -## Nginxの設定 +Install Certbot and obtain a certicate for all your domains. This will spin up its own webserver on port 80 for a moment to verify you control the given domain names. -高速透過プロキシを可能にするためにはかなり多くの設定が必要ですが、これらの大部分は修正する必要がないので、私に我慢してください。 +```bash +certbot -d example.com -d www.example.com +``` -HTTPキープアライブを有効にするには、アップストリームサーバを個別の`upstream`ブロックで設定する必要があります。これにより、パフォーマンスが大幅に向上します。そこで、`proxy_pass`ディレクティブでアップストリームアドレスを直接指定する代わりに、これを使用します。この例では、アップストリーム・セクションの名前`server_name`、つまりパブリック・ドメイン名であり、これも`Host`ヘッダーでSanicに渡されます。必要に応じて名前を変更できます。ロード・バランシングとフェイルオーバーのために、複数のサーバを用意することもできます。 +## Nginx configuration -`example.com`の2つの出現箇所を実際のドメイン名に変更し、`YOUR SECRET`の代わりにアプリ用に選択したシークレットを使用します。 +Quite much configuration is required to allow fast transparent proxying, but +for the most part these don't need to be modified, so bear with me. + +::: tip Note +Separate upstream section, rather than simply adding the IP after `proxy_pass` +as in most tutorials, is needed for HTTP keep-alive. We also enable streaming, +WebSockets and Nginx serving static files. +::: + +The following config goes inside the `http` section of `nginx.conf` or if your +system uses multiple config files, `/etc/nginx/sites-available/default` or +your own files (be sure to symlink them to `sites-enabled`): ```nginx +# Files managed by Certbot +ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; + +# Sanic service upstream example.com { keepalive 100; - server 127.0.0.1:8000; - #server unix:/tmp/sanic.sock; + server 127.0.0.1:8001; + #server unix:/tmp//sanic.sock; } server { @@ -59,7 +85,7 @@ server { listen [::]:443 ssl http2 default_server; # Serve static files if found, otherwise proxy to Sanic location / { - root /var/www; + root /srv/sanicexample/static; try_files $uri @sanic; } location @sanic { @@ -68,128 +94,76 @@ server { proxy_http_version 1.1; proxy_request_buffering off; proxy_buffering off; - # Proxy forwarding (password configured in app.config.FORWARDED_SECRET) - proxy_set_header forwarded "$proxy_forwarded;secret=\"YOUR SECRET\""; + proxy_set_header forwarded by=\"_$hostname\";$for_addr;proto=$scheme;host=\"$http_host\"; # Allow websockets and keep-alive (avoid connection: close) proxy_set_header connection "upgrade"; proxy_set_header upgrade $http_upgrade; } } -``` - -Cookieの可視性の問題および検索エンジンでのアドレスの一貫性を回避するには、次の手順を実行します。 -すべての訪問者を1つの真のドメインにリダイレクトすることをお勧めします。 -HTTPS: - -```nginx -# Redirect all HTTP to HTTPS with no-WWW -server { - listen 80 default_server; - listen [::]:80 default_server; - server_name ~^(?:www\.)?(.*)$; - return 301 https://$1$request_uri; -} # Redirect WWW to no-WWW server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ~^www\.(.*)$; - return 301 $scheme://$1$request_uri; + return 308 $scheme://$1$request_uri; } -``` - -上記の設定セクションは、`/etc/nginx/sites-available/default`または他のサイト設定に配置できます (新しい設定セクションを作成する場合は、必ず`sites-enabled`にシンボリックリンクしてください) 。 - -SSL証明書がメイン設定で設定されていることを確認します。 -それぞれに`ssl_certificate`ディレクティブと`ssl_certificate_key`ディレクティブを追加します。 -SSLでリスニングする`server`セクション。 - -さらに、これらすべてを`nginx/conf.d/forwarded.conf`にコピー&ペーストします。 -```nginx -# RFC 7239 Forwarded header for Nginx proxy_pass - -# Add within your server or location block: -# proxy_set_header forwarded "$proxy_forwarded;secret=\"YOUR SECRET\""; - -# Configure your upstream web server to identify this proxy by that password -# because otherwise anyone on the Internet could spoof these headers and fake -# their real IP address and other information to your service. - - -# Provide the full proxy chain in $proxy_forwarded -map $proxy_add_forwarded $proxy_forwarded { - default "$proxy_add_forwarded;by=\"_$hostname\";proto=$scheme;host=\"$http_host\";path=\"$request_uri\""; -} - -# The following mappings are based on -# https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/ - -map $remote_addr $proxy_forwarded_elem { - # IPv4 addresses can be sent as-is - ~^[0-9.]+$ "for=$remote_addr"; - - # IPv6 addresses need to be bracketed and quoted - ~^[0-9A-Fa-f:.]+$ "for=\"[$remote_addr]\""; - - # Unix domain socket names cannot be represented in RFC 7239 syntax - default "for=unknown"; +# Redirect all HTTP to HTTPS with no-WWW +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name ~^(?:www\.)?(.*)$; + return 308 https://$1$request_uri; } -map $http_forwarded $proxy_add_forwarded { - # If the incoming Forwarded header is syntactically valid, append to it - "~^(,[ \\t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*([ \\t]*,([ \\t]*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*)?)*$" "$http_forwarded, $proxy_forwarded_elem"; - - # Otherwise, replace it - default "$proxy_forwarded_elem"; +# Forwarded for= client IP address formatting +map $remote_addr $for_addr { + ~^[0-9.]+$ "for=$remote_addr"; # IPv4 client address + ~^[0-9A-Fa-f:.]+$ "for=\"[$remote_addr]\""; # IPv6 bracketed and quoted + default "for=unknown"; # Unix socket } ``` -::: tip Note -`conf.d`と`sites-available`を使用しないインストールの場合、上記の設定はすべて、メインの`nginx.conf`の`http`セクション内に配置することもできます。 -::: - -変更後にNginxの設定をリロード: +Start or restart Nginx for changes to take effect. E.g. ```bash -sudo nginx -s reload +systemctl restart nginx ``` -これで、`https://example.com/`でアプリを接続できるようになります。404エラーなどはすべてSanicのエラーページで処理され、静的ファイルが与えられたパスに存在する時はいつでもNginxによって提供されます。 - -## SSL certificates - -サーバで有効な証明書をまだ設定していない場合は、ここで設定します。`certbot`と`python 3-certbot-nginx`をインストールしてください。 - -```bash -certbot --nginx -d example.com -d www.example.com -``` +You should be able to connect your app on `https://example.com`. Any 404 +errors and such will be handled by Sanic's error pages, and whenever a static +file is present at a given path, it will be served by Nginx. -``_ -## サービスとして実行 +## Running as a service -このパートは`systemd`に基づくLinuxディストリビューション用です。ユニットファイル`/etc/systemd/system/sanicexample.service`を作成します。 +This part is for Linux distributions based on `systemd`. Create a unit file +`/etc/systemd/system/sanicexample.service` -```text +```systemd [Unit] Description=Sanic Example [Service] -User=nobody -WorkingDirectory=/srv/sanicexample -ExecStart=/usr/bin/env python3 sanicexample.py +DynamicUser=Yes +WorkingDirectory=/srv/sanicservice +Environment=SANIC_PROXY_SECRET=_hostname +ExecStart=sanic proxied_example --port 8001 --fast Restart=always [Install] WantedBy=multi-user.target ``` -次に、サービスファイルをリロードし、サービスを起動してブート時に有効にします。 +Then reload service files, start your service and enable it on boot: ```bash -sudo systemctl daemon-reload -sudo systemctl start sanicexample -sudo systemctl enable sanicexample +systemctl daemon-reload +systemctl start sanicexample +systemctl enable sanicexample ``` + +::: tip Note +For brevity we skipped setting up a separate user account and a Python virtual environment or installing your app as a Python module. There are good tutorials on those topics elsewhere that easily apply to Sanic as well. The DynamicUser setting creates a strong sandbox which basically means your application cannot store its data in files, so you may consider setting `User=sanicexample` instead if you need that. +::: diff --git a/src/ja/guide/deployment/running.md b/src/ja/guide/deployment/running.md index 47e2fd9b18..ff8e205469 100644 --- a/src/ja/guide/deployment/running.md +++ b/src/ja/guide/deployment/running.md @@ -1,118 +1,86 @@ -# Sanicの実行 +# Running Sanic -Sanicには、独自の内部Webサーバが付属しています。ほとんどの状況では、これがデプロイメントに適した方法です。さらに、Sanicは、ASGI対応ウェブサーバーにバンドルされたASGIアプリとして、またはgunicornを使用してデプロイすることもできます。 +Sanic ships with its own internal web server. Under most circumstances, this is the preferred method for deployment. In addition, you can also deploy Sanic as an ASGI app bundled with an ASGI-able web server. -## Sanicサーバー +## Sanic Server -`sanic.Sanic`の場合、次のキーワード引数を使用してrunメソッドを呼び出すことができます。 +The main way to run Sanic is to use the included [CLI](#sanic-cli). -| Parameter | Default | Description | -| :-------------: | :------------: | :---------------------------------------------------------------------------------------- | -| **host** | `"127.0.0.1"` | サーバーをホストするアドレス。 | -| **port** | `8000` | サーバをホストするポート。 | -| **unix** | `None` | サーバをホストするUnixソケット名 (TCPではありません) | -| **debug** | `False` | デバッグ出力をイネーブルにします (サーバの速度が低下します) | -| **ssl** | `None` | workersのSSL暗号化のためのSSLContext。 | -| **sock** | `None` | サーバーがからの接続を受け入れるためのソケット。 | -| **workers** | `1` | 作成するworkersもしくはprocessの数 | -| **loop** | `None` | 非同期互換イベントループ。何も指定しないのであれば、独自のイベントループが作成されます | -| **protocol** | `HttpProtocol` | asyncio.protocolのサブクラス。 | -| **access_log** | `True` | 要求の処理でログオンを有効にします (サーバの処理速度が大幅に低下します) 。 | - ----:1 - -上記の例では、パフォーマンスを向上させるためにアクセスログをオフにしました。 - -:--:1 - -```python -# server.py -app = Sanic("My App") -app.run(host='0.0.0.0', port=1337, access_log=False) +```sh +sanic path.to.server:app ``` -:--- +In this example, Sanic is instructed to look for a python module called `path.to.server`. Inside of that module, it will look for a global variable called `app`, which should be an instance of `Sanic(...)`. ----:1 +```python +# ./path/to/server.py +from sanic import Sanic, Request, json -`app.run(...)`を持つPythonスクリプトを実行します。 +app = Sanic("TestApp") -:--:1 -```bash -python server.py +@app.get("/") +async def handler(request: Request): + return json({"foo": "bar"}) ``` -:--- +You may also dropdown to the [lower level API](#low-level-apprun) to call `app.run` as a script. However, if you choose this option you should be more comfortable handling issues that may arise with `multiprocessing`. + ### Workers ---:1 -デフォルトでは、Sanicは1つのCPUコアだけを使用してメインプロセスをリッスンします。具体的には、run引数にworkersの数を指定します。 +By default, Sanic runs a main process and a single worker process (see [worker manager](./manager.md) for more details). + +To crank up the juice, just specify the number of workers in the run arguments. :--:1 -```python -app.run(host='0.0.0.0', port=1337, workers=4) +```sh +sanic server:app --host=0.0.0.0 --port=1337 --workers=4 ``` :--- -Sanicは自動的に複数のプロセスを起動し、それらの間でトラフィックをルーティングする。使用可能なプロセッサと同じ数のworkersを推奨します。 +Sanic will automatically spin up multiple processes and route traffic between them. We recommend as many workers as you have available processors. -::: new NEW in v21.12 ---:1 -CPUの性能を最大限に引き出す最も簡単な方法は、 `fast` オプションを使用することです。これは、システムの制約を考慮して、自動的に最大数のワーカーを実行します。 +The easiest way to get the maximum CPU performance is to use the `--fast` option. This will automatically run the maximum number of workers given the system constraints. + +*Added in v21.12* :--:1 -```python -app.run(host='0.0.0.0', port=1337, fast=True) -``` -```python -$ sanic server:app --host=0.0.0.0 --port=1337 --fast +```sh +sanic server:app --host=0.0.0.0 --port=1337 --fast ``` :--- -::: -古いバージョンのSanicで `fast` オプションがない場合、LinuxベースのOSでよくある確認方法を試してみてください。。 - -``` -$ nproc -``` +In version 22.9, Sanic introduced a new worker manager to provide more consistency and flexibility between development and production servers. Read [about the manager](./manager.md) for more details about workers. -Or, let Python do it: +---:1 +If you only want to run Sanic with a single process, specify `single_process` in the run arguments. This means that auto-reload, and the worker manager will be unavailable. -```python -import multiprocessing -workers = multiprocessing.cpu_count() -app.run(..., workers=workers) +*Added in v22.9* +:--:1 +```sh +sanic server:app --host=0.0.0.0 --port=1337 --single-process ``` +:--- -### viaコマンドの実行 +### Running via command #### Sanic CLI ----:1 -コマンドラインから起動できるシンプルなCLIも用意されています。 +Use `sanic --help` to see all the options. -たとえば、`server.py`という名前のファイルでアプリケーションとしてSanicを初期化した場合、次のようにサーバを実行できます。 -:--:1 -```bash -sanic server.app --host=0.0.0.0 --port=1337 --workers=4 -``` -:--- +::: details Sanic CLI help output - -すべてのオプションを表示するには、`sanic --help`を使用します。 ```text $ sanic --help -usage: sanic [-h] [--version] [--factory] [-s] [-H HOST] [-p PORT] [-u UNIX] [--cert CERT] [--key KEY] [--tls DIR] [--tls-strict-host] - [-w WORKERS | --fast] [--access-logs | --no-access-logs] [--debug] [-d] [-r] [-R PATH] [--motd | --no-motd] [-v] - [--noisy-exceptions | --no-noisy-exceptions] - module - ▄███ █████ ██ ▄█▄ ██ █ █ ▄██████████ + ▄███ █████ ██ ▄█▄ ██ █ █ ▄██████████ ██ █ █ █ ██ █ █ ██ ▀███████ ███▄ ▀ █ █ ██ ▄ █ ██ ██ █████████ █ ██ █ █ ▄▄ ████ ████████▀ █ █ █ ██ █ ▀██ ███████ + To start running a Sanic application, provide a path to the module, where app is a Sanic() instance: @@ -129,153 +97,382 @@ usage: sanic [-h] [--version] [--factory] [-s] [-H HOST] [-p PORT] [-u UNIX] [-- Required ======== Positional: - module Path to your Sanic app. Example: path.to.server:app - If running a Simple Server, path to directory to serve. Example: ./ + module Path to your Sanic app. Example: path.to.server:app + If running a Simple Server, path to directory to serve. Example: ./ Optional ======== General: - -h, --help show this help message and exit - --version show program's version number and exit + -h, --help show this help message and exit + --version show program's version number and exit Application: - --factory Treat app as an application factory, i.e. a () -> callable - -s, --simple Run Sanic as a Simple Server, and serve the contents of a directory - (module arg should be a path) + --factory Treat app as an application factory, i.e. a () -> callable + -s, --simple Run Sanic as a Simple Server, and serve the contents of a directory + (module arg should be a path) + --inspect Inspect the state of a running instance, human readable + --inspect-raw Inspect the state of a running instance, JSON output + --trigger-reload Trigger worker processes to reload + --trigger-shutdown Trigger all processes to shutdown + + HTTP version: + --http {1,3} Which HTTP version to use: HTTP/1.1 or HTTP/3. Value should + be either 1, or 3. [default 1] + -1 Run Sanic server using HTTP/1.1 + -3 Run Sanic server using HTTP/3 Socket binding: - -H HOST, --host HOST Host address [default 127.0.0.1] - -p PORT, --port PORT Port to serve on [default 8000] - -u UNIX, --unix UNIX location of unix socket + -H HOST, --host HOST + Host address [default 127.0.0.1] + -p PORT, --port PORT + Port to serve on [default 8000] + -u UNIX, --unix UNIX + location of unix socket TLS certificate: - --cert CERT Location of fullchain.pem, bundle.crt or equivalent - --key KEY Location of privkey.pem or equivalent .key file - --tls DIR TLS certificate folder with fullchain.pem and privkey.pem - May be specified multiple times to choose multiple certificates - --tls-strict-host Only allow clients that send an SNI matching server certs + --cert CERT Location of fullchain.pem, bundle.crt or equivalent + --key KEY Location of privkey.pem or equivalent .key file + --tls DIR TLS certificate folder with fullchain.pem and privkey.pem + May be specified multiple times to choose multiple certificates + --tls-strict-host Only allow clients that send an SNI matching server certs Worker: - -w WORKERS, --workers WORKERS Number of worker processes [default 1] - --fast Set the number of workers to max allowed - --access-logs Display access logs - --no-access-logs No display access logs + -w WORKERS, --workers WORKERS + Number of worker processes [default 1] + --fast Set the number of workers to max allowed + --single-process Do not use multiprocessing, run server in a single process + --legacy Use the legacy server manager + --access-logs Display access logs + --no-access-logs No display access logs Development: - --debug Run the server in debug mode - -d, --dev Currently is an alias for --debug. But starting in v22.3, - --debug will no longer automatically trigger auto_restart. - However, --dev will continue, effectively making it the - same as debug + auto_reload. - -r, --reload, --auto-reload Watch source directory for file changes and reload on changes - -R PATH, --reload-dir PATH Extra directories to watch and reload on changes + --debug Run the server in debug mode + -r, --reload, --auto-reload + Watch source directory for file changes and reload on changes + -R PATH, --reload-dir PATH + Extra directories to watch and reload on changes + -d, --dev debug + auto reload + --auto-tls Create a temporary TLS certificate for local development (requires mkcert or trustme) Output: - --motd Show the startup display - --no-motd No show the startup display - -v, --verbosity Control logging noise, eg. -vv or --verbosity=2 [default 0] - --noisy-exceptions Output stack traces for all exceptions - --no-noisy-exceptions No output stack traces for all exceptions + --coffee Uhm, coffee? + --no-coffee No uhm, coffee? + --motd Show the startup display + --no-motd No show the startup display + -v, --verbosity Control logging noise, eg. -vv or --verbosity=2 [default 0] + --noisy-exceptions Output stack traces for all exceptions + --no-noisy-exceptions + No output stack traces for all exceptions + ``` +::: -#### モジュールとして +#### As a module ---:1 -モジュールとして直接呼び出すこともできます。 +Sanic applications can also be called directly as a module. :--:1 ```bash python -m sanic server.app --host=0.0.0.0 --port=1337 --workers=4 ``` :--- -::: tip FYI -どちらの方法(CLIまたはモジュール)でも、Pythonファイルの`app.run()`を*呼び出さない*でください。もしも実行する場合は、インタプリタによって直接実行される場合にのみ実行されるようにラップしてください。 +#### Using a factory + +A very common solution is to develop your application *not* as a global variable, but instead using the factory pattern. In this context, "factory" means a function that returns an instance of `Sanic(...)`. + +---:1 +Suppose that you have this in your `server.py` +:--:1 +```python +from sanic import Sanic + +def create_app() -> Sanic: + app = Sanic("MyApp") + + return app +``` +:--- + +---:1 +You can run this application now by referencing it in the CLI explicitly as a factory: +:--:1 +```sh +sanic server:create_app --factory +``` +Or, explicitly like this: +```sh +sanic "server:create_app()" +``` +Or, implicitly like this: +```sh +sanic server:create_app +``` + +*Implicit command added in v23.3* + +:--- + +### Low level `app.run` + + +When using `app.run` you will just call your Python file like any other script. + +---:1 +`app.run` must be properly nested inside of a name-main block. +:--:1 ```python -if __name__ == '__main__': - app.run(host='0.0.0.0', port=1337, workers=4) +# server.py +app = Sanic("MyApp") + +if __name__ == "__main__": + app.run() +``` +:--- + +::: danger +Be *careful* when using this pattern. A very common mistake is to put too much logic inside of the `if __name__ == "__main__":` block. + +🚫 This is a mistake + +```python +from sanic import Sanic +from my.other.module import bp + +app = Sanic("MyApp") + +if __name__ == "__main__": + app.blueprint(bp) + app.run() +``` + +If you do this, your [blueprint](../best-practices/blueprints.md) will not be attached to your application. This is because the `__main__` block will only run on Sanic's main worker process, **NOT** any of its [worker processes](../deployment/manager.md). This goes for anything else that might impact your application (like attaching listeners, signals, middleware, etc). The only safe operations are anything that is meant for the main process, like the `app.main_*` listeners. + +Perhaps something like this is more appropriate: + +```python +from sanic import Sanic +from my.other.module import bp + +app = Sanic("MyApp") + +if __name__ == "__mp_main__": + app.blueprint(bp) +elif __name__ == "__main__": + app.run() ``` ::: +To use the low-level `run` API, after defining an instance of `sanic.Sanic`, we can call the run method with the following keyword arguments: + +| Parameter | Default | Description | +| :-------------------: | :--------------: | :---------------------------------------------------------------------------------------- | +| **host** | `"127.0.0.1"` | Address to host the server on. | +| **port** | `8000` | Port to host the server on. | +| **unix** | `None` | Unix socket name to host the server on (instead of TCP). | +| **dev** | `False` | Equivalent to `debug=True` and `auto_reload=True`. | +| **debug** | `False` | Enables debug output (slows server). | +| **ssl** | `None` | SSLContext for SSL encryption of worker(s). | +| **sock** | `None` | Socket for the server to accept connections from. | +| **workers** | `1` | Number of worker processes to spawn. Cannot be used with fast. | +| **loop** | `None` | An asyncio-compatible event loop. If none is specified, Sanic creates its own event loop. | +| **protocol** | `HttpProtocol` | Subclass of asyncio.protocol. | +| **version** | `HTTP.VERSION_1` | The HTTP version to use (`HTTP.VERSION_1` or `HTTP.VERSION_3`). | +| **access_log** | `True` | Enables log on handling requests (significantly slows server). | +| **auto_reload** | `None` | Enables auto-reload on the source directory. | +| **reload_dir** | `None` | A path or list of paths to directories the auto-reloader should watch. | +| **noisy_exceptions** | `None` | Whether to set noisy exceptions globally. None means leave as default. | +| **motd** | `True` | Whether to display the startup message. | +| **motd_display** | `None` | A dict with extra key/value information to display in the startup message | +| **fast** | `False` | Whether to maximize worker processes. Cannot be used with workers. | +| **verbosity** | `0` | Level of logging detail. Max is 2. | +| **auto_tls** | `False` | Whether to auto-create a TLS certificate for local development. Not for production. | +| **single_process** | `False` | Whether to run Sanic in a single process. | + +---:1 +For example, we can turn off the access log in order to increase performance, and bind to a custom host and port. +:--:1 +```python +# server.py +app = Sanic("MyApp") -#### Sanicシンプルサーバー +if __name__ == "__main__": + app.run(host='0.0.0.0', port=1337, access_log=False) +``` +:--- ---:1 -提供する必要がある静的ファイルのディレクトリだけがある場合もあります。これは特に、localhostサーバーを素早く立ち上げる場合に便利です。SanicにはSimple Serverが付属しており、ディレクトリを指定するだけです。 +Now, just execute the python script that has `app.run(...)` :--:1 -```bash +```sh +python server.py +``` +:--- + +For a slightly more advanced implementation, it is good to know that `app.run` will call `app.prepare` and `Sanic.serve` under the hood. + +---:1 +Therefore, these are equivalent: +:--:1 +```python +if __name__ == "__main__": + app.run(host='0.0.0.0', port=1337, access_log=False) +``` +```python +if __name__ == "__main__": + app.prepare(host='0.0.0.0', port=1337, access_log=False) + Sanic.serve() +``` +:--- +---:1 +This can be useful if you need to bind your appliction(s) to multiple ports. +:--:1 +```python +if __name__ == "__main__": + app1.prepare(host='0.0.0.0', port=9990) + app1.prepare(host='0.0.0.0', port=9991) + app2.prepare(host='0.0.0.0', port=5555) + Sanic.serve() +``` +:--- + +### Sanic Simple Server + +---:1 +Sometimes you just have a directory of static files that need to be served. This especially can be handy for quickly standing up a localhost server. Sanic ships with a Simple Server, where you only need to point it at a directory. +:--:1 +```sh sanic ./path/to/dir --simple ``` :--- ---:1 -自動リロードと組み合わせることもできます。 +This could also be paired with auto-reloading. :--:1 -```bash +```sh sanic ./path/to/dir --simple --reload --reload-dir=./path/to/dir ``` :--- -## ASGI +*Added in v21.6* + +### HTTP/3 + + +Sanic server offers HTTP/3 support using [aioquic](https://github.com/aiortc/aioquic). This **must** be installed to use HTTP/3: + +```sh +pip install sanic aioquic +``` + +```sh +pip install sanic[http3] +``` + +To start HTTP/3, you must explicitly request it when running your application. + +---:1 +```sh +sanic path.to.server:app --http=3 +``` -SanicもASGIに準拠しています。つまり、任意のASGI Webサーバを使用してSanicを実行できます。ASGIの3つの主要な実装は、[Daphne](http://github.com/django/daphne),[Uvicorn](https://www.uvicorn.org/),と[Hypercorn](https://pgjones.gitlab.io/hypercorn/index.html)です。 +```sh +sanic path.to.server:app -3 +``` +:--:1 -実行方法は次のようになります。 -※適切な実行方法についてはドキュメントを参照してください。 +```python +app.run(version=3) +``` +:--- + +To run both an HTTP/3 and HTTP/1.1 server simultaneously, you can use [application multi-serve](../release-notes/v22.3.html#application-multi-serve) introduced in v22.3. This will automatically add an [Alt-Svc](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc) header to your HTTP/1.1 requests to let the client know that it is also available as HTTP/3. + + +---:1 +```sh +sanic path.to.server:app --http=3 --http=1 +``` + +```sh +sanic path.to.server:app -3 -1 +``` +:--:1 +```python +app.prepare(version=3) +app.prepare(version=1) +Sanic.serve() ``` -daphne myapp:app +:--- + +Because HTTP/3 requires TLS, you cannot start a HTTP/3 server without a TLS certificate. You should [set it up yourself](../how-to/tls.html) or use `mkcert` if in `DEBUG` mode. Currently, automatic TLS setup for HTTP/3 is not compatible with `trustme`. See [development](./development.md) for more details. + +*Added in v22.6* + +## ASGI + +Sanic is also ASGI-compliant. This means you can use your preferred ASGI webserver to run Sanic. The three main implementations of ASGI are [Daphne](http://github.com/django/daphne), [Uvicorn](https://www.uvicorn.org/), and [Hypercorn](https://pgjones.gitlab.io/hypercorn/index.html). + +::: warning +Daphne does not support the ASGI `lifespan` protocol, and therefore cannot be used to run Sanic. See [Issue #264](https://github.com/django/daphne/issues/264) for more details. +::: + +Follow their documentation for the proper way to run them, but it should look something like: + +```sh uvicorn myapp:app +``` +```sh hypercorn myapp:app ``` -ASGIを使用する際には、次の点に注意してください。 +A couple things to note when using ASGI: -1. Sanic Webサーバを使用する場合、websocketsは`websockets`パッケージを使用して実行されますが。ASGIモードでは、websocketsはASGIサーバで管理されるため、このパッケージは必要ありません。 -2. ASGIライフスパンプロトコルは、スタートアップとシャットダウンの2つのサーバイベントだけをサポートします。Sanicには、起動前、起動後、シャットダウン前、シャットダウン後の4つがあります。したがって、ASGIモードでは、スタートアップイベントとシャットダウンイベントは連続して実行され、実際にはサーバプロセスの開始と終了の前後では実行されません(なぜなら現在、ASGIサーバによって制御されているためです)。したがって、`after_server_start`および`before_server_stop`を使用することをお薦めします。 +1. When using the Sanic webserver, websockets will run using the `websockets` package. In ASGI mode, there is no need for this package since websockets are managed in the ASGI server. +2. The ASGI lifespan protocol , supports only two server events: startup and shutdown. Sanic has four: before startup, after startup, before shutdown, and after shutdown. Therefore, in ASGI mode, the startup and shutdown events will run consecutively and not actually around the server process beginning and ending (since that is now controlled by the ASGI server). Therefore, it is best to use `after_server_start` and `before_server_stop`. ### Trio -SanicはTrio上での実行を実験的にサポートしています。 +Sanic has experimental support for running on Trio with: -``` +```sh hypercorn -k trio myapp:app ``` ## Gunicorn -[Gunicorn](http://gunicorn.org/)("Green Unicorn")は、UNIXベースのオペレーティング・システム用のWSGI HTTP Serverです。これはRubyのUnicornプロジェクトから移植されたフォーク前のworkerモデルです。 +[Gunicorn](http://gunicorn.org/) ("Green Unicorn") is a WSGI HTTP Server for UNIX based operating systems. It is a pre-fork worker model ported from Ruby’s Unicorn project. -GunicornでSanicアプリケーションを実行するには、特殊な`sanic.worker.GunicornWorker`を実行する必要があります: +In order to run Sanic application with Gunicorn, you need to use it with the adapter from [uvicorn](https://www.uvicorn.org/). Make sure uvicorn is installed and run it with `uvicorn.workers.UvicornWorker` for Gunicorn worker-class argument: -```bash -gunicorn myapp:app --bind 0.0.0.0:1337 --worker-class sanic.worker.GunicornWorker +```sh +gunicorn myapp:app --bind 0.0.0.0:1337 --worker-class uvicorn.workers.UvicornWorker ``` -アプリケーションでメモリリークが発生した場合、Gunicornを設定して、指定した数のリクエストを処理したあとでワーカーを正常に再起動できます。これは、メモリリークの影響を制限するのに役立つ便利な方法です。 - -詳細については、[Gunicorn Docs](http://docs.gunicorn.org/en/latest/settings.html#max-requests) を参照してください。 +See the [Gunicorn Docs](http://docs.gunicorn.org/en/latest/settings.html#max-requests) for more information. ::: warning -`gunicorn`経由でSanicを実行すると、`async/await`のパフォーマンス上の利点の多くを失うことになります。慎重に検討してから選択してください。Gunicornには多くの設定オプションが用意されていますが、Sanicを最速で動作させるには最適な選択肢ではありません。 +It is generally advised to not use `gunicorn` unless you need it. The Sanic Server is primed for running Sanic in production. Weigh your considerations carefully before making this choice. Gunicorn does provide a lot of configuration options, but it is not the best choice for getting Sanic to run at its fastest. ::: -## パフォーマンスに関する考慮事項 +## Performance considerations ---:1 -本番環境で実行する場合は、`debug`を必ずオフにしてください。 +When running in production, make sure you turn off `debug`. :--:1 -```python -app.run(..., debug=False) +```sh +sanic path.to.server:app ``` :--- ---:1 -また、`access_log`をオフにすると、Sanicは最も高速に動作します。 +Sanic will also perform fastest if you turn off `access_log`. -それでもアクセスログが必要だが、このパフォーマンス向上を享受したい場合は、[Nginxをプロキシとして](./nginx.md)使用すればアクセスログを処理できます。Pythonが処理できるものよりもはるかに高速になります。 +If you still require access logs, but want to enjoy this performance boost, consider using [Nginx as a proxy](./nginx.md), and letting that handle your access logging. It will be much faster than anything Python can handle. :--:1 -```python -app.run(..., access_log=False) +```sh +sanic path.to.server:app --no-access-logs ``` :--- diff --git a/src/ja/guide/deployment/server-choice.md b/src/ja/guide/deployment/server-choice.md index 9af6345235..31f22e224c 100644 --- a/src/ja/guide/deployment/server-choice.md +++ b/src/ja/guide/deployment/server-choice.md @@ -1 +1 @@ -# Choosing a server +# サーバーを選択する diff --git a/src/ja/guide/how-to/autodiscovery.md b/src/ja/guide/how-to/autodiscovery.md index 74663a4228..2e0aeb1672 100644 --- a/src/ja/guide/how-to/autodiscovery.md +++ b/src/ja/guide/how-to/autodiscovery.md @@ -159,3 +159,41 @@ def print_something(app, loop): ``` ::: :::: + + +```text +here is the dir tree +generate with 'find . -type d -name "__pycache__" -exec rm -rf {} +; tree' + +. # run 'sanic sever -d' here +├── blueprints +│ ├── __init__.py # you need add this file, just empty +│ ├── level1.py +│ └── one +│ └── two +│ └── level3.py +├── listeners +│ └── something.py +├── parent +│ └── child +│ ├── __init__.py +│ └── nested.py +├── server.py +└── utility.py +``` + +```bash +. ./.venv/bin/activate # activate the python venv which sanic is installed in +sanic sever -d # run this in the directory containing server.py +``` + +```text +you will see "something ***" like this: + +[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something +[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something inside __init__.py +[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something @ level3 +[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something @ level1 +[2023-07-12 11:23:36 +0000] [113704] [DEBUG] something @ nested +``` + diff --git a/src/ja/guide/how-to/cors.md b/src/ja/guide/how-to/cors.md index fe445ab72b..3de1b02614 100644 --- a/src/ja/guide/how-to/cors.md +++ b/src/ja/guide/how-to/cors.md @@ -7,6 +7,8 @@ title: CORS > アプリケーションをCORS用に構成する方法は? +The best solution is to use [Sanic Extensions](../../plugins/sanic-ext/http/cors.md). However, if you would like to build your own version, you could use this limited example. + :::: tabs ::: tab server.py ```python @@ -53,11 +55,7 @@ def _add_cors_headers(response, methods: Iterable[str]) -> None: def add_cors_headers(request, response): if request.method != "OPTIONS": - methods = [ - method - for methods in request.route.methods.values() - for method in methods - ] + methods = [method for method in request.route.methods] _add_cors_headers(response, methods) ``` ::: @@ -76,11 +74,11 @@ def _compile_routes_needing_options( routes: Dict[str, Route] ) -> Dict[str, FrozenSet]: needs_options = defaultdict(list) - # This is 21.3 and later. You will need to change this for older versions. + # This is 21.12 and later. You will need to change this for older versions. for route in routes.values(): - for uri, methods in route.methods.items(): - if "OPTIONS" not in methods: - needs_options[uri].extend(methods) + if "OPTIONS" not in route.methods: + needs_options[route.uri].extend(route.methods) + return { uri: frozenset(methods) for uri, methods in dict(needs_options).items() } diff --git a/src/ja/guide/how-to/orm.md b/src/ja/guide/how-to/orm.md index 08346f1fc8..d430c17b55 100644 --- a/src/ja/guide/how-to/orm.md +++ b/src/ja/guide/how-to/orm.md @@ -5,41 +5,157 @@ すべてのORMツールはSanicで動作しますが、非同期ORMツールはSanicのパフォーマンスに影響します。 これをサポートするormパッケージがいくつかあります。 -現在、非同期性をサポートするORMはたくさんあります。一般的なライブラリには、次の2つがあります。 +At present, there are many ORMs that support Python's `async`/`await` keywords. Some possible choices include: +- [Mayim](https://ahopkins.github.io/mayim/) - [SQLAlchemy 1.4](https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html) - [tortoise-orm](https://github.com/tortoise/tortoise-orm) のSanicアプリケーションへの統合は非常に簡単です。 +## Mayim + +Mayim ships with [an extension for Sanic Extensions](https://ahopkins.github.io/mayim/guide/extensions.html#sanic), which makes it super simple to get started with Sanic. It is certainly possible to run Mayim with Sanic without the extension, but it is recommended because it handles all of the [lifecycle events](https://sanic.dev/en/guide/basics/listeners.html) and [dependency injections](https://sanic.dev/en/plugins/sanic-ext/injection.html). + +---:1 +### Dependencies + +First, we need to install the required dependencies. See [Mayim docs](https://ahopkins.github.io/mayim/guide/install.html#postgres) for the installation needed for your DB driver. +:--:1 +```shell +pip install sanic-ext +pip install mayim[postgres] +``` +:--- + +---:1 +### Define ORM Model + +Mayim allows you to use whatever you want for models. Whether it is [dataclasses](https://docs.python.org/3/library/dataclasses.html), [pydantic](https://pydantic-docs.helpmanual.io/), [attrs](https://www.attrs.org/en/stable/), or even just plain `dict` objects. Since it works very nicely [out of the box with Pydantic](https://ahopkins.github.io/mayim/guide/pydantic.html), that is what we will use here. +:--:1 +```python +# ./models.py +from pydantic import BaseModel + + +class City(BaseModel): + id: int + name: str + district: str + population: int + + +class Country(BaseModel): + code: str + name: str + continent: str + region: str + capital: City +``` +:--- + +---:1 +### Define SQL + +If you are unfamiliar, Mayim is different from other ORMs in that it is one-way, SQL-first. This means you define your own queries either inline, or in a separate `.sql` file, which is what we will do here. +:--:1 +```sql +-- ./queries/select_all_countries.sql +SELECT country.code, + country.name, + country.continent, + country.region, + ( + SELECT row_to_json(q) + FROM ( + SELECT city.id, + city.name, + city.district, + city.population + ) q + ) capital +FROM country + JOIN city ON country.capital = city.id +ORDER BY country.name ASC +LIMIT $limit OFFSET $offset; +``` +:--- + +---:1 +### Create Sanic App and Async Engine + +We need to create the app instance and attach the `SanicMayimExtension` with any executors. +:--:1 +```python +# ./server.py +from sanic import Sanic, Request, json +from sanic_ext import Extend +from mayim.executor import PostgresExecutor +from mayim.extensions import SanicMayimExtension +from models import Country + + +class CountryExecutor(PostgresExecutor): + async def select_all_countries( + self, limit: int = 4, offset: int = 0 + ) -> list[Country]: + ... + + +app = Sanic("Test") +Extend.register( + SanicMayimExtension( + executors=[CountryExecutor], + dsn="postgres://...", + ) +) +``` +:--- + +---:1 +### Register Routes + +Because we are using Mayim's extension for Sanic, we have the automatic `CountryExecutor` injection into the route handler. It makes for an easy, type-annotated development experience. +:--:1 +```python +@app.get("/") +async def handler(request: Request, executor: CountryExecutor): + countries = await executor.select_all_countries() + return json({"countries": [country.dict() for country in co +``` +:--- + +---:1 +### Send Requests +:--:1 +```sh +curl 'http://127.0.0.1:8000' +{"countries":[{"code":"AFG","name":"Afghanistan","continent":"Asia","region":"Southern and Central Asia","capital":{"id":1,"name":"Kabul","district":"Kabol","population":1780000}},{"code":"ALB","name":"Albania","continent":"Europe","region":"Southern Europe","capital":{"id":34,"name":"Tirana","district":"Tirana","population":270000}},{"code":"DZA","name":"Algeria","continent":"Africa","region":"Northern Africa","capital":{"id":35,"name":"Alger","district":"Alger","population":2168000}},{"code":"ASM","name":"American Samoa","continent":"Oceania","region":"Polynesia","capital":{"id":54,"name":"Fagatogo","district":"Tutuila","population":2323}}]} +``` +:--- + + ## SQLAlchemy [SQLAlchemy 1.4関数](https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html)が`asyncio`のネイティブサポートを追加したので、SanicはついにSQLAlchemyでうまく動作するようになりました。SQLAlchemyプロジェクトでは、この機能はまだ*ベータ*と見なされていることに注意してください。 ---:1 - ### 依存関係 まず、必要な依存関係をインストールする必要があります。以前は、インストールされる依存関係は`sqlalchemy'と`pymysql'でしたが、現在は`sqlalchemy'と`aiomysql'が必要です。 - :--:1 - ```shell pip install -U sqlalchemy pip install -U aiomysql ``` - :--- ---:1 - ### ORMモデルの定義 ORMモデルの作成は同じままです。 - :--:1 - ```python # ./models.py from sqlalchemy import INTEGER, Column, ForeignKey, String @@ -69,17 +185,13 @@ class Car(BaseModel): user_id = Column(ForeignKey("person.id")) user = relationship("Person", back_populates="cars") ``` - :--- ---:1 - ### Sanicアプリケーションと非同期エンジンの作成 ここではデータベースとしてmysqlを使用しますが、PostgreSQL/SQLiteを選択することもできます。ドライバを`aiomysql`から`asyncpg`/`aiosqlite`に変更することに注意してください。 :--:1 - - ```python # ./server.py from sanic import Sanic @@ -89,20 +201,15 @@ app = Sanic("my_app") bind = create_async_engine("mysql+aiomysql://root:root@localhost/test", echo=True) ``` - :--- ---:1 - ### ミドルウェアの登録 リクエスト・ミドルウェアは、使用可能な`AsyncSession`オブジェクトを作成し、それを`request.ctx`および`_base_model_session_ctx`に設定します。 スレッドセーフな変数`_base_model_session_ctx`を使用すると、`request.ctx`からセッション・オブジェクトをフェッチするかわりにセッション・オブジェクトを使用できます。 - - :--:1 - ```python # ./server.py from contextvars import ContextVar @@ -126,17 +233,13 @@ async def close_session(request, response): _base_model_session_ctx.reset(request.ctx.session_ctx_token) await request.ctx.session.close() ``` - :--- ---:1 - ### ルートの登録 sqlalchemyの公式ドキュメントによると、`session.query`は2.0年にレガシーになり、ORMオブジェクトをクエリする2.0の方法は`select`を使用します。 - :--:1 - ```python # ./server.py from sqlalchemy import select @@ -169,11 +272,11 @@ async def get_user(request, pk): return json(person.to_dict()) ``` - :--- +---:1 ### リクエストを送信 - +---:1 ```sh curl --location --request POST 'http://127.0.0.1:8000/user' {"name":"foo","cars":[{"brand":"Tesla"}]} @@ -183,32 +286,26 @@ curl --location --request POST 'http://127.0.0.1:8000/user' curl --location --request GET 'http://127.0.0.1:8000/user/1' {"name":"foo","cars":[{"brand":"Tesla"}]} ``` +:--- ## Tortoise-ORM ---:1 - ### 依存関係 tortoise-ormの依存関係は非常に単純で、tortoise-ormをインストールするだけです。 - :--:1 - ```shell pip install -U tortoise-orm ``` - :--- ---:1 - ### ORMモデルの定義 Djangoに精通している方であれば、この部分は非常に馴染みがあるはずです。 - :--:1 - ```python # ./models.py from tortoise import Model, fields @@ -221,18 +318,14 @@ class Users(Model): def __str__(self): return f"I am {self.name}" ``` - :--- ---:1 - ### Sanicアプリケーションと非同期エンジンの作成 Tortoise-ormは、ユーザーにとって便利な登録インタフェースのセットを提供し、これを使用してデータベース接続を簡単に作成できます。 - :--:1 - ```python # ./main.py @@ -247,17 +340,12 @@ register_tortoise( ) ``` - :--- ---:1 - ### ルートの登録 - :--:1 - ```python - # ./main.py from models import Users @@ -278,11 +366,11 @@ async def get_user(request, pk): if __name__ == "__main__": app.run(port=5000) ``` - :--- +---:1 ### リクエストを送信 - +---:1 ```sh curl --location --request POST 'http://127.0.0.1:8000/user' {"users":["I am foo", "I am bar"]} @@ -292,3 +380,4 @@ curl --location --request POST 'http://127.0.0.1:8000/user' curl --location --request GET 'http://127.0.0.1:8000/user/1' {"user": "I am foo"} ``` +:--- diff --git a/src/ja/guide/how-to/toc.md b/src/ja/guide/how-to/toc.md index 0f6f129714..a07d597216 100644 --- a/src/ja/guide/how-to/toc.md +++ b/src/ja/guide/how-to/toc.md @@ -4,18 +4,10 @@ | Page | How do I ... | |:-----|:------------| -| [Applicationのマウント](./mounting.md) | ... どうやってルートより上のパスにアプリケーションをマウントする? | -| [Authentication](./authentication.md) | ... どうやって認証と許可を制御しますか? | -| [Autodiscovery](./autodiscovery.md) | ... どうやってアプリケーションの構築に使用しているコンポーネントを自動検出しますか? | -| [CORS](./cors.md) | ... どうやってCORS用にアプリケーションを構成しますか? | -| CSRF | *Coming soon* | -| Databases | *Coming soon* | -| IPv6 | *Coming soon* | -| Request ID Logging | *Coming soon* | -| Request validation | *Coming soon* | -| Serialization | *Coming soon* | -| Server Sent Events | *Coming soon* | -| [ORM](./orm) | ... どうやってSanicでORMを使う? | -| Task queues | *Coming soon* | -| [TLS/SSL/HTTPS](./tls.md) | ... どうやってHTTPS経由でSanicを実行する? ... どうやってHTTPをHTTPSにリダイレクトしますか? | -| Websocket feeds | *Coming soon* | +| [Application mounting](./mounting.md) | ... mount my application at some path above the root? | +| [Authentication](./authentication.md) | ... control authentication and authorization? | +| [Autodiscovery](./autodiscovery.md) | ... autodiscover the components I am using to build my application? | +| [CORS](./cors.md) | ... configure my application for CORS? | +| [ORM](./orm) | ... use an ORM with Sanic? | +| ["Static" Redirects](./static-redirects.md) | ... configure static redirects | +| [TLS/SSL/HTTPS](./tls.md) | ... run Sanic via HTTPS?
... redirect HTTP to HTTPS? | diff --git a/src/ja/guide/release-notes/v21.12.md b/src/ja/guide/release-notes/v21.12.md index ec3691ce87..9266226e1f 100644 --- a/src/ja/guide/release-notes/v21.12.md +++ b/src/ja/guide/release-notes/v21.12.md @@ -1,4 +1,4 @@ -# Version 21.12 +# Version 21.12 (LTS) [[toc]] diff --git a/src/ja/guide/release-notes/v22.12.md b/src/ja/guide/release-notes/v22.12.md new file mode 100644 index 0000000000..0ff738cb2f --- /dev/null +++ b/src/ja/guide/release-notes/v22.12.md @@ -0,0 +1,184 @@ +# Version 22.12 + +[[toc]] + +## Introduction + +This is the final release of the version 22 [release cycle](../../org/policies.md#release-schedule). As such it is a **long-term support** release, and will be supported as stated in the [policies](../../org/policies.md#long-term-support-v-interim-releases). + +## What to know + +More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade... + +### 🚨 *BREAKING CHANGE* - Sanic Inspector is now an HTTP server + +Sanic v22.9 introduced the [Inspector](./v22.9.md#inspector) to allow live inspection of a running Sanic instance. This feature relied upon opening a TCP socket and communicating over a custom protocol. That basic TCP protocol has been dropped in favor of running a full HTTP service in its place. [Learn more about the Inspector](../deployment/inspector.md). + +The current release introduces a new HTTP server and a refreshed CLI experience. This enables several new features highlighted here. Perhaps the most significant change, however, is to move all of the Inspector's commands to a subparser on the CLI instance. + +``` +$ sanic inspect --help + + ▄███ █████ ██ ▄█▄ ██ █ █ ▄██████████ + ██ █ █ █ ██ █ █ ██ + ▀███████ ███▄ ▀ █ █ ██ ▄ █ ██ + ██ █████████ █ ██ █ █ ▄▄ + ████ ████████▀ █ █ █ ██ █ ▀██ ███████ + +Optional +======== + General: + -h, --help show this help message and exit + --host HOST, -H HOST Inspector host address [default 127.0.0.1] + --port PORT, -p PORT Inspector port [default 6457] + --secure, -s Whether to access the Inspector via TLS encryption + --api-key API_KEY, -k API_KEY Inspector authentication key + --raw Whether to output the raw response information + + Subcommands: + Run one or none of the below subcommands. Using inspect without a subcommand will fetch general information about the state of the application instance. + + Or, you can optionally follow inspect with a subcommand. If you have created a custom Inspector instance, then you can run custom commands. See https://sanic.dev/en/guide/deployment/inspector.html for more details. + + {reload,shutdown,scale,} + reload Trigger a reload of the server workers + shutdown Shutdown the application and all processes + scale Scale the number of workers + Run a custom command +``` + +#### CLI remote access now available + +The `host` and `port` of the Inspector are now explicitly exposed on the CLI as shown above. Previously in v22.9, they were inferred by reference to the application instance. Because of this change, it will be more possible to expose the Inspector on live production instances and access from a remote installation of the CLI. + +For example, you can check your running production deployment from your local development machine. + +``` +$ sanic inspect --host=1.2.3.4 +``` + +::: warning +For **production** instances, make sure you are _using TLS and authentication_ described below. +::: + +#### TLS encryption now available + +You can secure your remote Inspector access by providing a TLS certificate to encrypt the web traffic. + +```python +app.config.INSPECTOR_TLS_CERT = "/path/to/cert.pem" +app.config.INSPECTOR_TLS_KEY = "/path/to/key.pem" +``` + +To access an encrypted installation via the CLI, use the `--secure` flag. + +``` +$ sanic inspect --secure +``` + +#### Authentication now available + +To control access to the remote Inspector, you can protect the endpoints using an API key. + +```python +app.config.INSPECTOR_API_KEY = "Super-Secret-200" +``` + +To access a protected installation via the CLI, use the `--api-key` flag. + +``` +$ sanic inspect --api-key=Super-Secret-200 +``` + +This is equivalent to the header: `Authorization: Bearer `. + +``` +$ curl http://localhost:6457 -H "Authorization: Bearer Super-Secret-200" +``` + +### Scale number of running server workers + +The Inspector is now capable of scaling the number of worker processes. For example, to scale to 3 replicas, use the following command: + +``` +$ sanic inspect scale 3 +``` + +### Extend Inspector with custom commands + +The Inspector is now fully extendable to allow for adding custom commands to the CLI. For more information see [Custom Commands](../deployment/inspector.md#custom-commands). + +``` +$ sanic inspect foo --bar +``` + +### Early worker exit on failure + +The process manager shipped with v22.9 had a very short startup timeout. This was to protect against deadlock. This was increased to 30s, and a new mechanism has been added to fail early if there is a crash in a worker process on startup. + +### Introduce `JSONResponse` with convenience methods to update a JSON response body + +The `sanic.response.json` convenience method now returns a new subclass of `HTTPResponse` appropriately named: `JSONResponse`. This new type has some convenient methods for handling changes to a response body after its creation. + +```python +resp = json({"foo": "bar"}) +resp.update({"another": "value"}) +``` + +See [Returning JSON Data](../basics/response.md#returning-json-data) for more information. + +### Updates to downstream requirements: `uvloop` and `websockets` + +Minimum `uvloop` was set to `0.15.0`. Changes were added to make Sanic compliant with `websockets` version `11.0`. + +### Force exit on 2nd `ctrl+c` + +On supporting operating systems, the existing behavior is for Sanic server to try to perform a graceful shutdown when hitting `ctrl+c`. This new release will perform an immediate shutdown on subsequent `ctrl+c` after the initial shutdown has begun. + +### Deprecations and Removals + +1. *DEPRECATED* - The `--inspect*` commands introduced in v22.9 have been replaced with a new subcommand parser available as `inspect`. The flag versions will continue to operate until v23.3. You are encouraged to use the replacements. While this short deprecation period is a deviation from the standard two-cycles, we hope this change will be minimally disruptive. + ``` + OLD sanic ... --inspect + NEW sanic ... inspect + + OLD sanic ... --inspect-raw + NEW sanic ... inspect --raw + + OLD sanic ... --inspect-reload + NEW sanic ... inspect reload + + OLD sanic ... --inspect-shutdown + NEW sanic ... inspect shutdown + ``` + +## News + +The Sanic Community Organization will be headed by a new Steering Council for 2023. There are two returning and two new members. + +[@ahopkins](https://github.com/ahopkins) *returning* \ +[@prryplatypus](https://github.com/prryplatypus) *returning* \ +[@sjsadowski](https://github.com/sjsadowski) *NEW* \ +[@Tronic](https://github.com/Tronic) *NEW* + +The 2023 release managers are [@ahopkins](https://github.com/ahopkins) and [@sjsadowski](https://github.com/sjsadowski). + +If you are interested in getting more involved with Sanic, contact us on the [Discord server](https://discord.gg/FARQzAEMAA). + +## Thank you + +Thank you to everyone that participated in this release: :clap: + +[@aaugustin](https://github.com/aaugustin) +[@ahopkins](https://github.com/ahopkins) +[@ChihweiLHBird](https://github.com/ChihweiLHBird) +[@kijk2869](https://github.com/kijk2869) +[@LiraNuna](https://github.com/LiraNuna) +[@prryplatypus](https://github.com/prryplatypus) +[@sjsadowski](https://github.com/sjsadowski) +[@todddialpad](https://github.com/todddialpad) +[@Tronic](https://github.com/Tronic) + +--- + +If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: [financial contributions](https://opencollective.com/sanic-org/). diff --git a/src/ja/guide/release-notes/v22.3.md b/src/ja/guide/release-notes/v22.3.md new file mode 100644 index 0000000000..4bc98ad66c --- /dev/null +++ b/src/ja/guide/release-notes/v22.3.md @@ -0,0 +1,221 @@ +# Version 22.3 + +[[toc]] + +## Introduction + +This is the first release of the version 22 [release cycle](../../org/policies.md#release-schedule). All of the standard SCO libraries are now entering the same release cycle and will follow the same versioning pattern. Those packages are: + +- [`sanic-routing`](https://github.com/sanic-org/sanic-routing) +- [`sanic-testing`](https://github.com/sanic-org/sanic-testing) +- [`sanic-ext`](https://github.com/sanic-org/sanic-ext) + +## What to know + +More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade... + +### Application multi-serve + +The Sanic server now has an API to allow you to run multiple applications side-by-side in the same process. This is done by calling `app.prepare(...)` on one or more application instances, one or many times. Each time it should be bound to a unique host/port combination. Then, you begin serving the applications by calling `Sanic.serve()`. + +```python +app = Sanic("One") +app2 = Sanic("Two") + +app.prepare(port=9999) +app.prepare(port=9998) +app.prepare(port=9997) +app2.prepare(port=8888) +app2.prepare(port=8887) + +Sanic.serve() +``` + +In the above snippet, there are two applications that will be run concurrently and bound to multiple ports. This feature is *not* supported in the CLI. + +This pattern is meant to be an alternative to running `app.run(...)`. It should be noted that `app.run` is now just a shorthand for the above pattern and is still fully supported. + +### 👶 *BETA FEATURE* - New path parameter type: file extensions + +A very common pattern is to create a route that dynamically generates a file. The endpoint is meant to match on a file with an extension. There is a new path parameter to match files: ``. + +```python +@app.get("/path/to/") +async def handler(request, filename, ext): + ... +``` + +This will catch any pattern that ends with a file extension. You may, however want to expand this by specifying which extensions, and also by using other path parameter types for the file name. + +For example, if you want to catch a `.jpg` file that is only numbers: + +```python +@app.get("/path/to/") +async def handler(request, filename, ext): + ... +``` + +Some potential examples: + +| definition | example | filename | extension | +| --------------------------------- | ----------- | ----------- | ---------- | +| \ | page.txt | `"page"` | `"txt"` | +| \ | cat.jpg | `"cat"` | `"jpg"` | +| \ | cat.jpg | `"cat"` | `"jpg"` | +| | 123.txt | `123` | `"txt"` | +| | 123.svg | `123` | `"svg"` | +| | 3.14.tar.gz | `3.14` | `"tar.gz"` | + +### 🚨 *BREAKING CHANGE* - Path parameter matching of non-empty strings + +A dynamic path parameter will only match on a non-empty string. + +Previously a route with a dynamic string parameter (`/` or `/`) would match on any string, including empty strings. It will now only match a non-empty string. To retain the old behavior, you should use the new parameter type: `/`. + +```python +@app.get("/path/to/") +async def handler(request, foo) + ... +``` + +### 🚨 *BREAKING CHANGE* - `sanic.worker.GunicornWorker` has been removed + +Departing from our normal deprecation policy, the `GunicornWorker` was removed as a part of the process of upgrading the Sanic server to include multi-serve. This decision was made largely in part because even while it existed it was not an optimal strategy for deploying Sanic. + +If you want to deploy Sanic using `gunicorn`, then you are advised to do it using [the strategy implemented by `uvicorn`](https://www.uvicorn.org/#running-with-gunicorn). This will effectively run Sanic as an ASGI application through `uvicorn`. You can upgrade to this pattern by installing `uvicorn`: + +``` +pip install uvicorn +``` + +Then, you should be able to run it with a pattern like this: + +``` +gunicorn path.to.sanic:app -k uvicorn.workers.UvicornWorker +``` + +### Authorization header parsing + +The `Authorization` header has been partially parseable for some time now. You have been able to use `request.token` to gain access to a header that was in one of the following two forms: + +``` +Authorization: Token +Authorization: Bearer +``` + +Sanic can now parse more credential types like `BASIC`: + +``` +Authorization: Basic Z2lsLWJhdGVzOnBhc3N3b3JkMTIz +``` + +This can be accessed now as `request.credentials`: + +```python +print(request.credentials) +# Credentials(auth_type='Basic', token='Z2lsLWJhdGVzOnBhc3N3b3JkMTIz', _username='gil-bates', _password='password123') +``` + +### CLI arguments optionally injected into application factory + +Sanic will now attempt to inject the parsed CLI arguments into your factory if you are using one. + +```python +def create_app(args): + app = Sanic("MyApp") + print(args) + return app +``` +``` +$sanic p:create_app --factory +Namespace(module='p:create_app', factory=True, simple=False, host='127.0.0.1', port=8000, unix='', cert=None, key=None, tls=None, tlshost=False, workers=1, fast=False, access_log=False, debug=False, auto_reload=False, path=None, dev=False, motd=True, verbosity=None, noisy_exceptions=False) +``` + +If you are running the CLI with `--factory`, you also have the option of passing arbitrary arguments to the command, which will be injected into the argument `Namespace`. + +``` +sanic p:create_app --factory --foo=bar +Namespace(module='p:create_app', factory=True, simple=False, host='127.0.0.1', port=8000, unix='', cert=None, key=None, tls=None, tlshost=False, workers=1, fast=False, access_log=False, debug=False, auto_reload=False, path=None, dev=False, motd=True, verbosity=None, noisy_exceptions=False, foo='bar') +``` + +### New reloader process listener events + +When running Sanic server with auto-reload, there are two new events that trigger a listener *only* on the reloader process: + +- `reload_process_start` +- `reload_process_stop` + +These are only triggered if the reloader is running. + +```python +@app.reload_process_start +async def reload_start(*_): + print(">>>>>> reload_start <<<<<<") + + +@app.reload_process_stop +async def reload_stop(*_): + print(">>>>>> reload_stop <<<<<<") +``` + +### The event loop is no longer a required argument of a listener + +You can leave out the `loop` argument of a listener. Both of these examples work as expected: + +```python +@app.before_server_start +async def without(app): + ... + +@app.before_server_start +async def with(app, loop): + ... +``` + +### Removal - Debug mode does not automatically start the reloader + +When running with `--debug` or `debug=True`, the Sanic server will not automatically start the auto-reloader. This feature of doing both on debug was deprecated in v21 and removed in this release. If you would like to have *both* debug mode and auto-reload, you can use `--dev` or `dev=True`. + +**dev = debug mode + auto reloader** + +### Deprecation - Loading of lower case environment variables + +Sanic loads prefixed environment variables as configuration values. It has not distinguished between uppercase and lowercase as long as the prefix matches. However, it has always been the convention that the keys should be uppercase. This is deprecated and you will receive a warning if the value is not uppercase. In v22.9 only uppercase and prefixed keys will be loaded. + +## News + +### Packt publishes new book on Sanic web development + +---:1 +There is a new book on **Python Web Development with Sanic** by [@ahopkins](https://github.com/ahopkins). The book is endorsed by the SCO and part of the proceeds of all sales go directly to the SCO for further development of Sanic. + +You can learn more at [sanicbook.com](https://sanicbook.com/) +:--:1 +![Python Web Development with Sanic](https://sanicbook.com/images/SanicCoverFinal.png) +:--- + +## Thank you + +Thank you to everyone that participated in this release: :clap: + +[@aericson](https://github.com/aericson) +[@ahankinson](https://github.com/ahankinson) +[@ahopkins](https://github.com/ahopkins) +[@ariebovenberg](https://github.com/ariebovenberg) +[@ashleysommer](https://github.com/ashleysommer) +[@Bluenix2](https://github.com/Bluenix2) +[@ChihweiLHBird](https://github.com/ChihweiLHBird) +[@dotlambda](https://github.com/dotlambda) +[@eric-spitler](https://github.com/eric-spitler) +[@howzitcdf](https://github.com/howzitcdf) +[@jonra1993](https://github.com/jonra1993) +[@prryplatypus](https://github.com/prryplatypus) +[@raphaelauv](https://github.com/raphaelauv) +[@SaidBySolo](https://github.com/SaidBySolo) +[@SerGeRybakov](https://github.com/SerGeRybakov) +[@Tronic](https://github.com/Tronic) + + +--- + +If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: [financial contributions](https://opencollective.com/sanic-org/). diff --git a/src/ja/guide/release-notes/v22.6.md b/src/ja/guide/release-notes/v22.6.md new file mode 100644 index 0000000000..0f3dd716ef --- /dev/null +++ b/src/ja/guide/release-notes/v22.6.md @@ -0,0 +1,162 @@ +# Version 22.6 + +[[toc]] + +## Introduction + +This is the second release of the version 22 [release cycle](../../org/policies.md#release-schedule). Version 22 will be "finalized" in the December long-term support version release. + +## What to know + +More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade... + + +### Automatic TLS setup in `DEBUG` mode + +The Sanic server can automatically setup a TLS certificate using either [mkcert](https://github.com/FiloSottile/mkcert) or [trustme](https://github.com/python-trio/trustme). This certificate will enable `https://localhost` (or another local address) for local development environments. You must install either `mkcert` or `trustme` on your own for this to work. + +---:1 +``` +$ sanic path.to.server:app --auto-tls --debug +``` +:--:1 + +```python +app.run(debug=True, auto_tls=True) +``` +:--- + +This feature is not available when running in `ASGI` mode, or in `PRODUCTION` mode. When running Sanic in production, you should be using a real TLS certificate either purchased through a legitimate vendor, or using [Let's Encrypt](https://letsencrypt.org/). + + +### HTTP/3 Server :rocket: + +In June 2022, the IETF finalized and published [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114.html), the specification for HTTP/3. In short, HTTP/3 is a **very** different protocol than HTTP/1.1 and HTTP/2 because it implements HTTP over UDP instead of TCP. The new HTTP protocol promises faster webpage load times and solving some of the problems of the older standards. You are encouraged to [read more about](https://http3-explained.haxx.se/) this new web technology. You likely will need to install a [capable client](https://curl.se/docs/http3.html) as traditional tooling will not work. + +Sanic server offers HTTP/3 support using [aioquic](https://github.com/aiortc/aioquic). This **must** be installed: + +``` +pip install sanic aioquic +``` + +``` +pip install sanic[http3] +``` + +To start HTTP/3, you must explicitly request it when running your application. + +---:1 +``` +$ sanic path.to.server:app --http=3 +``` + +``` +$ sanic path.to.server:app -3 +``` +:--:1 + +```python +app.run(version=3) +``` +:--- + +To run both an HTTP/3 and HTTP/1.1 server simultaneously, you can use [application multi-serve](./v22.3.html#application-multi-serve) introduced in v22.3. + + +---:1 +``` +$ sanic path.to.server:app --http=3 --http=1 +``` + +``` +$ sanic path.to.server:app -3 -1 +``` +:--:1 + +```python +app.prepre(version=3) +app.prepre(version=1) +Sanic.serve() +``` +:--- + +Because HTTP/3 requires TLS, you cannot start a HTTP/3 server without a TLS certificate. You should [set it up yourself](../how-to/tls.html) or use `mkcert` if in `DEBUG` mode. Currently, automatic TLS setup for HTTP/3 is not compatible with `trustme`. + +**:baby: This feature is being released as an *EARLY RELEASE FEATURE*.** It is **not** yet fully compliant with the HTTP/3 specification, lacking some features like [websockets](https://websockets.spec.whatwg.org/), [webtransport](https://w3c.github.io/webtransport/), and [push responses](https://http3-explained.haxx.se/en/h3/h3-push). Instead the intent of this release is to bring the existing HTTP request/response cycle towards feature parity with HTTP/3. Over the next several releases, more HTTP/3 features will be added and the API for it finalized. + +### Consistent exception naming + +Some of the Sanic exceptions have been renamed to be more compliant with standard HTTP response names. + +- `InvalidUsage` >> `BadRequest` +- `MethodNotSupported` >> `MethodNotAllowed` +- `ContentRangeError` >> `RangeNotSatisfiable` + +All old names have been aliased and will remain backwards compatible. + +### Current request getter + +Similar to the API to access an application (`Sanic.get_app()`), there is a new method for retrieving the current request when outside of a request handler. + +```python +from sanic import Request + +Request.get_current() +``` + +### Improved API support for setting cache control headers + +The `file` response helper has some added parameters to make it easier to handle setting of the [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) header. + +```python +file( + ..., + last_modified=..., + max_age=..., + no_store=..., +) +``` + + +### Custom `loads` function + +Just like Sanic supports globally setting a custom `dumps`, you can now set a global custom `loads`. + +```python +from orjson import loads + +app = Sanic("Test", loads=loads) +``` + + +### Deprecations and Removals + +1. *REMOVED* - Applications may no longer opt-out of the application registry +1. *REMOVED* - Custom exception handlers will no longer run after some part of an exception has been sent +1. *REMOVED* - Fallback error formats cannot be set on the `ErrorHandler` and must **only** be set in the `Config` +1. *REMOVED* - Setting a custom `LOGO` for startup is no longer allowed +1. *REMOVED* - The old `stream` response convenience method has been removed +1. *REMOVED* - `AsyncServer.init` is removed and no longer an alias of `AsyncServer.app.state.is_started` + + + +## Thank you + +Thank you to everyone that participated in this release: :clap: + +[@ahopkins](https://github.com/ahopkins) +[@amitay87](https://github.com/amitay87 ) +[@ashleysommer](https://github.com/ashleysommer) +[@azimovMichael](https://github.com/azimovMichael) +[@ChihweiLHBird](https://github.com/ChihweiLHBird) +[@kijk2869](https://github.com/kijk2869) +[@prryplatypus](https://github.com/prryplatypus) +[@SaidBySolo](https://github.com/SaidBySolo) +[@sjsadowski](https://github.com/sjsadowski) +[@timmo001](https://github.com/timmo001) +[@zozzz](https://github.com/zozzz) + + +--- + +If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: [financial contributions](https://opencollective.com/sanic-org/). diff --git a/src/ja/guide/release-notes/v22.9.md b/src/ja/guide/release-notes/v22.9.md new file mode 100644 index 0000000000..64bd25ec7d --- /dev/null +++ b/src/ja/guide/release-notes/v22.9.md @@ -0,0 +1,315 @@ +# Version 22.9 + +[[toc]] + +## Introduction + +This is the third release of the version 22 [release cycle](../../org/policies.md#release-schedule). Version 22 will be "finalized" in the December long-term support version release. + +## What to know + +More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade... + + +### :warning: *IMPORTANT* - New worker manager :rocket: + +Sanic server has been overhauled to provide more consistency and flexbility in how it operates. More details about the motivations are outlined in [PR #2499](https://github.com/sanic-org/sanic/pull/2499) and discussed in a live stream [discussion held on YouTube](https://youtu.be/m8HCO8NK7HE). + +This **does NOT apply** to Sanic in ASGI mode + +#### Overview of the changes + +- The worker servers will **always** run in a child process. + - Previously this could change depending upon one versus many workers, and the usage or not of the reloader. This should lead to much more predictable development environments that more closely match their production counterparts. +- Multi-workers is **now supported on Windows**. + - This was impossible because Sanic relied upon the `multiprocessing` module using `fork`, which is not available on Windows. + - Now, Sanic will always use `spawn`. This does have some noticeable differences, particularly if you are running Sanic in the global scope with `app.run` (see below re: upgrade issues). +- The application instance now has a new `multiplexer` object that can be used to restart one or many workers. This could, for example, be triggered by a request. +- There is a new Inspector that can provide details on the state of your server. +- Sanic worker manager can run arbitrary processes. + - This allows developers to add any process they want from within Sanic. + - Possible use cases: + - Health monitor, see [Sanic Extensions]() + - Logging queue, see [Sanic Extensions]() + - Background worker queue in a seperate process + - Running another application, like a bot +- There is a new listener called: `main_process_ready`. It really should only be used for adding arbitrary processes to Sanic. +- Passing shared objects between workers. + - Python does allow some types of objects to share state between processes, whether through shared memory, pipes, etc. + - Sanic will now allow these types of object to be shared on the `app.shared_ctx` object. + - Since this feature relies upon Pythons `multiprocessing` library, it obviously will only work to share state between Sanic worker instances that are instantiated from the same execution. This is *not* meant to provide an API for horizontal scaling across multiple machines for example. + +#### Adding a shared context object + +To share an object between worker processes, it *MUST* be assigned inside of the `main_process_start` listener. + +```python +from multiprocessing import Queue + +@app.main_process_start +async def main_process_start(app): + app.shared_ctx.queue = Queue() +``` + +All objects on `shared_ctx` will be available now within each worker process. + +```python +@app.before_server_starts +async def before_server_starts(app): + assert isinstance(app.shared_ctx.queue, Queue) + +@app.on_request +async def on_request(request): + assert isinstance(request.app.shared_ctx.queue, Queue) + +@app.get("/") +async def handler(request): + assert isinstance(request.app.shared_ctx.queue, Queue) +``` + +*NOTE: Sanic will not stop you from registering an unsafe object, but may warn you. Be careful not to just add a regular list object, for example, and expect it to work. You should have an understanding of how to share state between processes.* + +#### Running arbitrary processes + +Sanic can run any arbitrary process for you. It should be capable of being stopped by a `SIGINT` or `SIGTERM` OS signal. + +These processes should be registered inside of the `main_process_ready` listener. + +```python +@app.main_process_ready +async def ready(app: Sanic, _): + app.manager.manage("MyProcess", my_process, {"foo": "bar"}) +# app.manager.manage(, , ) +``` + +#### Inspector + +Sanic ships with an optional Inspector, which is a special process that allows for the CLI to inspect the running state of an application and issue commands. It currently will only work if the CLI is being run on the same machine as the Sanic instance. + +``` +sanic path.to:app --inspect +``` + +![Sanic inspector](https://user-images.githubusercontent.com/166269/190099384-2f2f3fae-22d5-4529-b279-8446f6b5f9bd.png) + +The new CLI commands are: + +``` + --inspect Inspect the state of a running instance, human readable + --inspect-raw Inspect the state of a running instance, JSON output + --trigger-reload Trigger worker processes to reload + --trigger-shutdown Trigger all processes to shutdown +``` + +This is not enabled by default. In order to have it available, you must opt in: + +```python +app.config.INSPECTOR = True +``` + +*Note: [Sanic Extensions]() provides a [custom request](../basics/app.md#custom-requests) class that will add a request counter to the server state. + +#### Application multiplexer + +Many of the same information and functionality is available on the application instance itself. There is a new `multiplexer` object on the application instance that has the ability to restart one or more workers, and fetch information about the current state. + +You can access it as `app.multiplexer`, or more likely by its short alias `app.m`. + +```python +@app.on_request +async def print_state(request: Request): + print(request.app.m.state) +``` + +#### Potential upgrade issues + +Because of the switch from `fork` to `spawn`, if you try running the server in the global scope you will receive an error. If you see something like this: + +``` +sanic.exceptions.ServerError: Sanic server could not start: [Errno 98] Address already in use. +This may have happened if you are running Sanic in the global scope and not inside of a `if __name__ == "__main__"` block. +``` + +... then the change is simple. Make sure `app.run` is inside a block. + +```python +if __name__ == "__main__": + app.run(port=9999, dev=True) +``` + +#### Opting out of the new functionality + +If you would like to run Sanic without the new process manager, you may easily use the legacy runners. Please note that support for them **will be removed** in the future. A date has not yet been set, but will likely be sometime in 2023. + +To opt out of the new server and use the legacy, choose the appropriate method depending upon how you run Sanic: + +---:1 +If you use the CLI... +:--:1 +``` +sanic path.to:app --legacy +``` +:--- + +---:1 +If you use `app.run`... +:--:1 +``` +app.run(..., legacy=True) +``` +:--- + +---:1 +If you `app.prepare`... +:--:1 +``` +app.prepare(...) +Sanic.serve_legacy() +``` +:--- + +Similarly, you can force Sanic to run in a single process. This however means there will not be any access to the auto-reloader. + +---:1 +If you use the CLI... +:--:1 +``` +sanic path.to:app --single-process +``` +:--- + +---:1 +If you use `app.run`... +:--:1 +``` +app.run(..., single_process=True) +``` +:--- + +---:1 +If you `app.prepare`... +:--:1 +``` +app.prepare(...) +Sanic.serve_single() +``` +:--- +### Middleware priority + +Middleware is executed in an order based upon when it was defined. Request middleware are executed in sequence and response middleware in reverse. This could have an unfortunate impact if your ordering is strictly based upon import ordering with global variables for example. + +A new addition is to break-out of the strict construct and allow a priority to be assigned to a middleware. The higher the number for a middleware definition, the earlier in the sequence it will be executed. This applies to **both** request and response middleware. + +```python +@app.on_request +async def low_priority(_): + ... + +@app.on_request(priority=10) +async def high_priority(_): + ... +``` + +In the above example, even though `low_priority` is defined first, `high_priority` will run first. + +### Custom `loads` function + + +Sanic has supported the ability to add a [custom `dumps` function](https://sanic.readthedocs.io/en/stable/sanic/api/app.html#sanic.app.Sanic) when instantiating an app. The same functionality has been extended to `loads`, which will be used when deserializing. + +```python +from json import loads + +Sanic("Test", loads=loads) +``` + +### Websocket objects are now iterable + + +Rather than calling `recv` in a loop on a `Websocket` object, you can iterate on it in a `for` loop. + + +```python +from sanic import Request, Websocket + +@app.websocket("/ws") +async def ws_echo_handler(request: Request, ws: Websocket): + async for msg in ws: + await ws.send(msg) +``` + +### Appropriately respond with 304 on static files + +When serving a static file, the Sanic server can respond appropriately to a request with `If-Modified-Since` using a `304` response instead of resending a file. + +### Two new signals to wrap handler execution + +Two new [signals](../advanced/signals.md) have been added that wrap the execution of a request handler. + +- `http.handler.before` - runs after request middleware but before the route handler +- `http.handler.after` - runs after the route handler + - In *most* circumstances, this also means that it will run before response middleware. However, if you call `request.respond` from inside of a route handler, then your middleware will come first + +### New Request properties for HTTP method information + +The HTTP specification defines which HTTP methods are: safe, idempotent, and cacheable. New properties have been added that will respond with a boolean flag to help identify the request property based upon the method. + +```python +request.is_safe +request.is_idempotent +request.is_cacheable +``` + +### 🚨 *BREAKING CHANGE* - Improved cancel request exception + +In prior version of Sanic, if a `CancelledError` was caught it could bubble up and cause the server to respond with a `503`. This is not always the desired outcome, and it prevented the usage of that error in other circumstances. As a result, Sanic will now use a subclass of `CancelledError` called: `RequestCancelled` for this functionality. It likely should have little impact unless you were explicitly relying upon the old behavior. + + +For more details on the specifics of these properties, checkout the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods). + +### New deprecation warning filter + +You can control the level of deprecation warnings from Sanic using [standard library warning filter values](https://docs.python.org/3/library/warnings.html#the-warnings-filter). Default is `"once"`. + +```python +app.config.DEPRECATION_FILTER = "ignore" +``` + +### Deprecations and Removals + +1. *DEPRECATED* - Duplicate route names have been deprecated and will be removed in v23.3 +1. *DEPRECATED* - Registering duplicate exception handlers has been deprecated and will be removed in v23.3 +1. *REMOVED* - `route.ctx` not set by Sanic, and is a blank object for users, therefore ... + - `route.ctx.ignore_body` >> `route.extra.ignore_body` + - `route.ctx.stream` >> `route.extra.stream` + - `route.ctx.hosts` >> `route.extra.hosts` + - `route.ctx.static` >> `route.extra.static` + - `route.ctx.error_format` >> `route.extra.error_format` + - `route.ctx.websocket` >> `route.extra.websocket` +1. *REMOVED* - `app.debug` is READ-ONLY +1. *REMOVED* - `app.is_running` removed +1. *REMOVED* - `app.is_stopping` removed +1. *REMOVED* - `Sanic._uvloop_setting` removed +1. *REMOVED* - Prefixed environment variables will be ignored if not uppercase + + +## Thank you + +Thank you to everyone that participated in this release: :clap: + +[@ahopkins](https://github.com/ahopkins) +[@azimovMichael](https://github.com/azimovMichael) +[@ChihweiLHBird](https://github.com/ChihweiLHBird) +[@huntzhan](https://github.com/huntzhan) +[@monosans](https://github.com/monosans) +[@prryplatypus](https://github.com/prryplatypus) +[@SaidBySolo](https://github.com/SaidBySolo) +[@seemethere](https://github.com/seemethere) +[@sjsadowski](https://github.com/sjsadowski) +[@timgates42](https://github.com/timgates42) +[@Tronic](https://github.com/Tronic) + + +--- + +If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: [financial contributions](https://opencollective.com/sanic-org/). diff --git a/src/ja/guide/release-notes/v23.3.md b/src/ja/guide/release-notes/v23.3.md new file mode 100644 index 0000000000..a64025b5dd --- /dev/null +++ b/src/ja/guide/release-notes/v23.3.md @@ -0,0 +1,384 @@ +# Version 23.3 + +[[toc]] + +## Introduction + +This is the first release of the version 23 [release cycle](../../org/policies.md#release-schedule). As such contains some deprecations and hopefully some *small* breaking changes. If you run into any issues, please raise a concern on [GitHub](https://github.com/sanic-org/sanic/issues/new/choose). + +## What to know + +More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade... + +### Nicer traceback formatting + +The SCO adopted two projects into the Sanic namespace on GitHub: [tracerite](https://github.com/sanic-org/tracerite) and [html5tagger](https://github.com/sanic-org/html5tagger). These projects team up to provide and incredible new error page with more details to help the debugging process. + +This is provided out of the box, and will adjust to display only relevant information whether in DEBUG more or PROD mode. + +---:1 +**Using PROD mode** +![image](~@assets/images/error-html-no-debug.png) +:--: +**Using DEBUG mode** +![image](~@assets/images/error-html-debug.png) +:--- + +Light and dark mode HTML pages are available and will be used implicitly. + +### Basic file browser on directories + +When serving a directory from a static handler, Sanic can be configured to show a basic file browser instead using `directory_view=True`. + +---:1 +```python +app.static("/uploads/", "/path/to/dir/", directory_view=True) +``` +:--: +![image](~@assets/images/directory-view.png) +:--- + + +Light and dark mode HTML pages are available and will be used implicitly. + +### HTML templating with Python + +Because Sanic is using [html5tagger](https://github.com/sanic-org/html5tagger) under the hood to render the [new error pages](#nicer-traceback-formatting), you now have the package available to you to easily generate HTML pages in Python code: + + +---:1 +```python +from html5tagger import Document +from sanic import Request, Sanic, html + +app = Sanic("TestApp") + + +@app.get("/") +async def handler(request: Request): + doc = Document("My Website") + doc.h1("Hello, world.") + with doc.table(id="data"): + doc.tr.th("First").th("Second").th("Third") + doc.tr.td(1).td(2).td(3) + doc.p(class_="text")("A paragraph with ") + doc.a(href="/files")("a link")(" and ").em("formatting") + return html(doc) +``` +:--: +```html + + +My Website +

Hello, world.

+ + + +
First + Second + Third +
1 + 2 + 3 +
+

+ A paragraph with a link and formatting +``` +:--- + +### Auto-index serving is available on static handlers + +Sanic can now be configured to serve an index file when serving a static directory. + +```python +app.static("/assets/", "/path/to/some/dir", index="index.html") +``` + +When using the above, requests to `http://example.com/assets/` will automatically serve the `index.html` file located in that directory. + +### Simpler CLI targets + +It is common practice for Sanic applications to use the variable `app` as the application instance. Because of this, the CLI application target (the second value of the `sanic` CLI command) now tries to infer the application instance based upon what the target is. If the target is a module that contains an `app` variable, it will use that. + +There are now four possible ways to launch a Sanic application from the CLI. + +#### 1. Application instance + + +As normal, providing a path to a module and an application instance will work as expected. + +```sh +sanic path.to.module:app # global app instance +``` + +#### 2. Application factory + +Previously, to serve the factory pattern, you would need to use the `--factory` flag. This can be omitted now. + +```sh +sanic path.to.module:create_app # factory pattern +``` + +#### 3. Path to launch Sanic Simple Server + +Similarly, to launch the Sanic simple server (serve static directory), you previously needed to use the `--simple` flag. This can be omitted now, and instead simply provide the path to the directory. + +```sh +sanic ./path/to/directory/ # simple serve +``` + +#### 4. Python module containing an `app` variable + +As stated above, if the target is a module that contains an `app` variable, it will use that (assuming that `app` variable is a `Sanic` instance). + +```sh +sanic path.to.module # module with app instance +``` + +### More convenient methods for setting and deleting cookies + +The old cookie pattern was awkward and clunky. It didn't look like regular Python because of the "magic" going on under the hood. + +---:1 +😱 This is not intuitive and is confusing for newcomers. +:--: +```python +response = text("There's a cookie up in this response") +response.cookies["test"] = "It worked!" +response.cookies["test"]["domain"] = ".yummy-yummy-cookie.com" +response.cookies["test"]["httponly"] = True +``` +:--- + +There are now new methods (and completely overhauled `Cookie` and `CookieJar` objects) to make this process more convenient. + +---:1 +😌 Ahh... Much nicer. +:--: +```python +response = text("There's a cookie up in this response") +response.add_cookie( + "test", + "It worked!", + domain=".yummy-yummy-cookie.com", + httponly=True +) +``` +:--- + +### Better cookie compatibility + +Sanic has added support for [cookie prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#cookie_prefixes), making it seemless and easy to read and write cookies with the values. + +While setting the cookie... + +```py +response.cookies.add_cookie("foo", "bar", host_prefix=True) +``` + +This will create the prefixed cookie: `__Host-foo`. However, when accessing the cookie on an incoming request, you can do so without knowing about the existence of the header. + +```py +request.cookies.get("foo") +``` + +It should also be noted, cookies can be accessed as properties just like [headers](#access-any-header-as-a-property). + +```python +request.cookies.foo +``` + +And, cookies are similar to the `request.args` and `request.form` objects in that multiple values can be retrieved using `getlist`. + +```py +request.cookies.getlist("foo") +``` + +Also added is support for creating [partitioned cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#partitioned_cookie). + +```py +response.cookies.add_cookie(. . ., partitioned=True) +``` + +### 🚨 *BREAKING CHANGE* - More consistent and powerful `SanicException` + +Sanic has for a while included the `SanicException` as a base class exception. This could be extended to add `status_code`, etc. [See more details](http://localhost:8080/en/guide/best-practices/exceptions.html). + +**NOW**, using all of the various exceptions has become easier. The commonly used exceptions can be imported directly from the root level module. + +```python +from sanic import NotFound, Unauthorized, BadRequest, ServerError +``` + +In addition, all of these arguments are available as keyword arguments on every exception type: + +| argument | type | description | +|--|--|--| +| `quiet` | `bool` | Suppress the traceback from the logs | +| `context` | `dict` | Additional information shown in error pages *always* | +| `extra` | `dict` | Additional information shown in error pages in *DEBUG* mode | +| `headers` | `dict` | Additional headers sent in the response | + +None of these are themselves new features. However, they are more consistent in how you can use them, thus creating a powerful way to control error responses directly. + +```py +raise ServerError(headers={"foo": "bar"}) +``` + +The part of this that is a breaking change is that some formerly positional arguments are now keyword only. + +You are encouraged to look at the specific implementations for each error in the [API documents](https://sanic.readthedocs.io/en/stable/sanic/api/exceptions.html#module-sanic.exceptions). + +### 🚨 *BREAKING CHANGE* - Refresh `Request.accept` functionality to be more performant and spec-compliant + +Parsing od the `Accept` headers into the `Request.accept` accessor has been improved. If you were using this property and relying upon its equality operation, this has changed. You should probably transition to using the `request.accept.match()` method. + +### Access any header as a property + +To simplify access to headers, you can access a raw (unparsed) version of the header as a property. The name of the header is the name of the property in all lowercase letters, and switching any hyphens (`-`) to underscores (`_`). + +For example: + +---:1 +``` +GET /foo/bar HTTP/1.1 +Host: localhost +User-Agent: curl/7.88.1 +X-Request-ID: 123ABC +``` +:--: +```py +request.headers.host +request.headers.user_agent +request.headers.x_request_id +``` +:--- + +### Consume `DELETE` body by default + +By default, the body of a `DELETE` request will now be consumed and read onto the `Request` object. This will make `body` available like on `POST`, `PUT`, and `PATCH` requests without any further action. + +### Custom `CertLoader` for direct control of creating `SSLContext` + +Sometimes you may want to create your own `SSLContext` object. To do this, you can create your own subclass of `CertLoader` that will generate your desired context object. + +```python +from sanic.worker.loader import CertLoader + + +class MyCertLoader(CertLoader): + def load(self, app: Sanic) -> SSLContext: + . . . + + +app = Sanic(. . ., certloader_class=MyCertLoader) +``` + +### Deprecations and Removals + +1. *DEPRECATED* - Dict-style cookie setting +1. *DEPRECATED* - Using existence of JSON data on the request for one factor in using JSON error formatter +1. *REMOVED* - Remove deprecated `__blueprintname__` property +1. *REMOVED* - duplicate route names +1. *REMOVED* - duplicate exception handler definitions +1. *REMOVED* - inspector CLI with flags +1. *REMOVED* - legacy server (including `sanic.server.serve_single` and `sanic.server.serve_multiple`) +1. *REMOVED* - serving directory with bytes string +1. *REMOVED* - `Request.request_middleware_started` +1. *REMOVED* - `Websocket.connection` + + +#### Duplicated route names are no longer allowed + +In version 22.9, Sanic announced that v23.3 would deprecate allowing routes to be registered with duplicate names. If you see the following error, it is because of that change: + +> sanic.exceptions.ServerError: Duplicate route names detected: SomeApp.some_handler. You should rename one or more of them explicitly by using the `name` param, or changing the implicit name derived from the class and function name. For more details, please see https://sanic.dev/en/guide/release-notes/v23.3.html#duplicated-route-names-are-no-longer-allowed + +If you are seeing this, you should opt-in to using explicit names for your routes. + +---:1 +**BAD** +```python +app = Sanic("SomeApp") + +@app.get("/") +@app.get("/foo") +async def handler(request: Request): +``` +:--: +**GOOD** +```python +app = Sanic("SomeApp") + +@app.get("/", name="root") +@app.get("/foo", name="foo") +async def handler(request: Request): +``` +:--- + +#### Response cookies + +Response cookies act as a `dict` for compatibility purposes only. In version 24.3, all `dict` methods will be removed and response cookies will be objects only. + +Therefore, if you are using this pattern to set cookie properties, you will need to upgrade it before version 24.3. + +```python +resp = HTTPResponse() +resp.cookies["foo"] = "bar" +resp.cookies["foo"]["httponly"] = True +``` + +Instead, you should be using the `add_cookie` method: + + +```python +resp = HTTPResponse() +resp.add_cookie("foo", "bar", httponly=True) +``` + +#### Request cookies + +Sanic has added support for reading duplicated cookie keys to be more in compliance with RFC specifications. To retain backwards compatibility, accessing a cookie value using `__getitem__` will continue to work to fetch the first value sent. Therefore, in version 23.3 and prior versions this will be `True`. + +```python +assert request.cookies["foo"] == "bar" +assert request.cookies.get("foo") == "bar" +``` + +Version 23.3 added `getlist` + +```python +assert request.cookies.getlist("foo") == ["bar"] +``` + +As stated above, the `get` and `getlist` methods are available similar to how they exist on other request properties (`request.args`, `request.form`, etc). Starting in v24.3, the `__getitem__` method for cookies will work exactly like those properties. This means that `__getitem__` will return a list of values. + +Therefore, if you are relying upon this functionality to return only one value, you should upgrade to the following pattern before v24.3. + +```python +assert request.cookies["foo"] == ["bar"] +assert request.cookies.get("foo") == "bar" +assert request.cookies.getlist("foo") == ["bar"] +``` + + +## Thank you + +Thank you to everyone that participated in this release: :clap: + +[@ahopkins](https://github.com/ahopkins) +[@ChihweiLHBird](https://github.com/ChihweiLHBird) +[@deounix](https://github.com/deounix) +[@Kludex](https://github.com/Kludex) +[@mbendiksen](https://github.com/mbendiksen) +[@prryplatypus](https://github.com/prryplatypus) +[@r0x0d](https://github.com/r0x0d) +[@SaidBySolo](https://github.com/SaidBySolo) +[@sjsadowski](https://github.com/sjsadowski) +[@stricaud](https://github.com/stricaud) +[@Tracyca209](https://github.com/Tracyca209) +[@Tronic](https://github.com/Tronic) + +--- + +If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: [financial contributions](https://opencollective.com/sanic-org/). diff --git a/src/ja/guide/release-notes/v23.6.md b/src/ja/guide/release-notes/v23.6.md new file mode 100644 index 0000000000..0a5d9dec9e --- /dev/null +++ b/src/ja/guide/release-notes/v23.6.md @@ -0,0 +1,194 @@ +# Version 23.6 + +[[toc]] + +## Introduction + +This is the second release of the version 23 [release cycle](../../org/policies.md#release-schedule). If you run into any issues, please raise a concern on [GitHub](https://github.com/sanic-org/sanic/issues/new/choose). + +## What to know + +More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade... + +### Remove Python 3.7 support + +Python 3.7 is due to reach its scheduled upstream end-of-life on 2023-06-27. Sanic is now dropping support for Python 3.7, and requires Python 3.8 or newer. + +See [#2777](https://github.com/sanic-org/sanic/pull/2777). + +### Resolve pypy compatibility issues + +A small patch was added to the `os` module to once again allow for Sanic to run with PyPy. This workaround replaces the missing `readlink` function (missing in PyPy `os` module) with the function `os.path.realpath`, which serves to the same purpose. + +See [#2782](https://github.com/sanic-org/sanic/pull/2782). + +### Add custom typing to config and ctx objects + +The `sanic.Sanic` and `sanic.Request` object have become generic types that will make it more convenient to have fully typed `config` and `ctx` objects. + +In the most simple form, the `Sanic` object is typed as: + +```python +from sanic import Sanic +app = Sanic("test") +reveal_type(app) # N: Revealed type is "sanic.app.Sanic[sanic.config.Config, types.SimpleNamespace]" +``` + +::: tip Note +It should be noted, there is *no* requirement to use the generic types. The default types are `sanic.config.Config` and `types.SimpleNamespace`. This new feature is just an option for those that want to use it and existing types of `app: Sanic` and `request: Request` should work just fine. +::: + +Now it is possible to have a fully-type `app.config`, `app.ctx`, and `request.ctx` objects though generics. This allows for better integration with auto completion tools in IDEs improving the developer experience. + +```python +from sanic import Request, Sanic +from sanic.config import Config + +class CustomConfig(Config): + pass + +class Foo: + pass + +class RequestContext: + foo: Foo + +class CustomRequest(Request[Sanic[CustomConfig, Foo], RequestContext]): + @staticmethod + def make_context() -> RequestContext: + ctx = RequestContext() + ctx.foo = Foo() + return ctx + +app = Sanic( + "test", config=CustomConfig(), ctx=Foo(), request_class=CustomRequest +) + +@app.get("/") +async def handler(request: CustomRequest): + ... +``` + +As a side effect, now `request.ctx` is lazy initialized, which should reduce some overhead when the `request.ctx` is unused. + +One further change you may have noticed in the above snippet is the `make_context` method. This new method can be used by custom `Request` types to inject an object different from a `SimpleNamespace` similar to how Sanic has allowed custom application context objects for a while. + +For a more thorough discussion, see [custom typed application](../basics/app.md#custom-typed-application) and [custom typed request](../basics/app.md#custom-typed-request). + + +See [#2785](https://github.com/sanic-org/sanic/pull/2785). + +### Universal exception signal + +A new exception signal added for **ALL** exceptions raised while the server is running: `"server.exception.reporting"`. This is a universal signal that will be emitted for any exception raised, and dispatched as its own task. This means that it will *not* block the request handler, and will *not* be affected by any middleware. + +This is useful for catching exceptions that may occur outside of the request handler (for example in signals, or in a background task), and it intended for use to create a consistent error handling experience for the user. + +```python +from sanic.signals import Event + +@app.signal(Event.SERVER_LIFECYCLE_EXCEPTION) +async def catch_any_exception(app: Sanic, exception: Exception): + app.ctx.my_error_reporter_utility.error(exception) +``` + +This pattern can be simplified with a new decorator `@app.report_exception`: + +```python +@app.report_exception +async def catch_any_exception(app: Sanic, exception: Exception): + print("Caught exception:", exception) +``` + +It should be pointed out that this happens in a background task and is **NOT** for manipulation of an error response. It is only for reporting, logging, or other purposes that should be triggered when an application error occurs. + +See [#2724](https://github.com/sanic-org/sanic/pull/2724) and [#2792](https://github.com/sanic-org/sanic/pull/2792). + +### Add name prefixing to BP groups + +Sanic had been raising a warning on duplicate route names for a while, and started to enforce route name uniqueness in [v23.3](https://sanic.dev/en/guide/release-notes/v23.3.html#deprecations-and-removals). This created a complication for blueprint composition. + +New name prefixing parameter for blueprints groups has been added to alleviate this issue. It allows nesting of blueprints and groups to make them composable. + +The addition is the new `name_prefix` parameter as shown in this snippet. + +```python +bp1 = Blueprint("bp1", url_prefix="/bp1") +bp2 = Blueprint("bp2", url_prefix="/bp2") + +bp1.add_route(lambda _: ..., "/", name="route1") +bp2.add_route(lambda _: ..., "/", name="route2") + +group_a = Blueprint.group( + bp1, bp2, url_prefix="/group-a", name_prefix="group-a" +) +group_b = Blueprint.group( + bp1, bp2, url_prefix="/group-b", name_prefix="group-b" +) + +app = Sanic("TestApp") +app.blueprint(group_a) +app.blueprint(group_b) +``` + +The routes built will be named as follows: +- `TestApp.group-a_bp1.route1` +- `TestApp.group-a_bp2.route2` +- `TestApp.group-b_bp1.route1` +- `TestApp.group-b_bp2.route2` + +See [#2727](https://github.com/sanic-org/sanic/pull/2727). + +### Add `request.client_ip` + +Sanic has introduced `request.client_ip`, a new accessor that provides client's IP address from both local and proxy data. It allows running the application directly on Internet or behind a proxy. This is equivalent to `request.remote_addr or request.ip`, providing the client IP regardless of how the application is deployed. + +See [#2790](https://github.com/sanic-org/sanic/pull/2790). + +### Increase of `KEEP_ALIVE_TIMEOUT` default to 120 seconds + +The default `KEEP_ALIVE_TIMEOUT` value changed from 5 seconds to 120 seconds. It is of course still configurable, but this change should improve performance on long latency connections, where reconnecting is expensive, and better fits typical user flow browsing pages with longer-than-5-second intervals. + +Sanic has historically used 5 second timeouts to quickly close idle connections. The chosen value of **120 seconds** is indeed larger than Nginx default of 75, and is the same value that Caddy server has by default. + +Related to [#2531](https://github.com/sanic-org/sanic/issues/2531) and +[#2681](https://github.com/sanic-org/sanic/issues/2681). + +See [#2670](https://github.com/sanic-org/sanic/pull/2670). + +### Set multiprocessing start method early + +Due to how Python handles `multiprocessing`, it may be confusing to some users how to properly create synchronization primitives. This is due to how Sanic creates the `multiprocessing` context. This change sets the start method early so that any primitives created will properly attach to the correct context. + +For most users, this should not be noticeable or impactful. But, it should make creation of something like this easier and work as expected. + +```python +from multiprocessing import Queue + +@app.main_process_start +async def main_process_start(app): + app.shared_ctx.queue = Queue() +``` + +See [#2776](https://github.com/sanic-org/sanic/pull/2776). + +## Thank you + +Thank you to everyone that participated in this release: :clap: + +[@ahopkins](https://github.com/ahopkins) +[@ChihweiLHBird](https://github.com/ChihweiLHBird) +[@chuckds](https://github.com/chuckds) +[@deounix](https://github.com/deounix) +[@guacs](https://github.com/guacs) +[@liamcoatman](https://github.com/liamcoatman) +[@moshe742](https://github.com/moshe742) +[@prryplatypus](https://github.com/prryplatypus) +[@SaidBySolo](https://github.com/SaidBySolo) +[@Thirumalai](https://github.com/Thirumalai) +[@Tronic](https://github.com/Tronic) + + +--- + +If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: [financial contributions](https://opencollective.com/sanic-org/). diff --git a/src/ja/help.md b/src/ja/help.md index 7ac86e30a7..4a4f200879 100644 --- a/src/ja/help.md +++ b/src/ja/help.md @@ -12,7 +12,7 @@ layout: BlankLayout チャットや質問への迅速な回答に最も適した場所です。 -[Discordサーバー](https://discord.gg/FARQzAEMAA)の`#sanic-support`チャンネルへ +[Discordサーバー](https://discord.gg/FARQzAEMAA)の`#sanic-support`チャンネルへ (もしくは、日本人であれば`#general-jp-🇯🇵`チャンネルも使えますよ!) :--:1 diff --git a/src/ja/org/feature_requests.md b/src/ja/org/feature_requests.md new file mode 100644 index 0000000000..5c57ea1f02 --- /dev/null +++ b/src/ja/org/feature_requests.md @@ -0,0 +1,9 @@ +# Feature Requests + +[Create new feature request](https://github.com/sanic-org/sanic/issues/new?assignees=&labels=feature+request&template=feature_request.md) + +To vote on a feature request, visit the [GitHub Issues](https://github.com/sanic-org/sanic/issues?q=is%3Aissue+is%3Aopen+label%3A%22feature+request%22%2CRFC+sort%3Areactions-%2B1-desc) and add a reaction + +--- + + diff --git a/src/ja/plugins/sanic-ext/configuration.md b/src/ja/plugins/sanic-ext/configuration.md index f8719470b9..daf117e279 100644 --- a/src/ja/plugins/sanic-ext/configuration.md +++ b/src/ja/plugins/sanic-ext/configuration.md @@ -1,3 +1,251 @@ # 設定 -_ドキュメンテーションは2022年10月公開予定_ +Sanic Extensions can be configured in all of the same ways that [you can configure Sanic](../../guide/deployment/configuration.md). That makes configuring Sanic Extensions very easy. + +```python +app = Sanic("MyApp") +app.config.OAS_URL_PREFIX = "/apidocs" +``` + +However, there are a few more configuration options that should be considered. + +## Manual `extend` + +---:1 +Even though Sanic Extensions will automatically attach to your application, you can manually choose `extend`. When you do that, you can pass all of the configuration values as a keyword arguments (lowercase). +:--: +```python +app = Sanic("MyApp") +app.extend(oas_url_prefix="/apidocs") +``` +:--- + +---:1 +Or, alternatively they could be passed all at once as a single `dict`. +:--: +```python +app = Sanic("MyApp") +app.extend(config={"oas_url_prefix": "/apidocs"}) +``` +:--- + +---:1 +Both of these solutions suffers from the fact that the names of the configuration settings are not discoverable by an IDE. Therefore, there is also a type annotated object that you can use. This should help the development experience. +:--: +```python +from sanic_ext import Config + +app = Sanic("MyApp") +app.extend(config=Config(oas_url_prefix="/apidocs")) +``` +:--- + +## Settings + +### `cors` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to enable CORS protection + +### `cors_allow_headers` + +- **Type**: `str` +- **Default**: `"*"` +- **Description**: Value of the header: `access-control-allow-headers` + +### `cors_always_send` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to always send the header: `access-control-allow-origin` + +### `cors_automatic_options` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to automatically generate `OPTIONS` endpoints for routes that do *not* already have one defined + +### `cors_expose_headers` + +- **Type**: `str` +- **Default**: `""` +- **Description**: Value of the header: `access-control-expose-headers` + +### `cors_max_age` + +- **Type**: `int` +- **Default**: `5` +- **Description**: Value of the header: `access-control-max-age` + +### `cors_methods` + +- **Type**: `str` +- **Default**: `""` +- **Description**: Value of the header: `access-control-access-control-allow-methods` + +### `cors_origins` + +- **Type**: `str` +- **Default**: `""` +- **Description**: Value of the header: `access-control-allow-origin` + +::: warning +Be very careful if you place `*` here. Do not do this unless you know what you are doing as it can be a security issue. +::: + +### `cors_send_wildcard` + +- **Type**: `bool` +- **Default**: `False` +- **Description**: Whether to send a wildcard origin instead of the incoming request origin + +### `cors_supports_credentials` + +- **Type**: `bool` +- **Default**: `False` +- **Description**: Value of the header: `access-control-allow-credentials` + +### `cors_vary_header` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to add the `vary` header + +### `http_all_methods` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Adds the HTTP `CONNECT` and `TRACE` methods as allowable + +### `http_auto_head` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Automatically adds `HEAD` handlers to any `GET` routes + +### `http_auto_options` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Automatically adds `OPTIONS` handlers to any routes without + +### `http_auto_trace` + +- **Type**: `bool` +- **Default**: `False` +- **Description**: Automatically adds `TRACE` handlers to any routes without + +### `oas` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to enable OpenAPI specification generation + +### `oas_autodoc` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to automatically extract OpenAPI details from the docstring of a route function + +### `oas_ignore_head` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: WHen `True`, it will not add `HEAD` endpoints into the OpenAPI specification + +### `oas_ignore_options` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: WHen `True`, it will not add `OPTIONS` endpoints into the OpenAPI specification + +### `oas_path_to_redoc_html` + +- **Type**: `Optional[str]` +- **Default**: `None` +- **Description**: Path to HTML file to override the existing Redoc HTML + +### `oas_path_to_swagger_html` + +- **Type**: `Optional[str]` +- **Default**: `None` +- **Description**: Path to HTML file to override the existing Swagger HTML + +### `oas_ui_default` + +- **Type**: `Optional[str]` +- **Default**: `"redoc"` +- **Description**: Which OAS documentation to serve on the bare `oas_url_prefix` endpoint; when `None` there will be no documentation at that location + +### `oas_ui_redoc` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to enable the Redoc UI + +### `oas_ui_swagger` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to enable the Swagger UI + +### `oas_ui_swagger_version` + +- **Type**: `str` +- **Default**: `"4.1.0"` +- **Description**: Which Swagger version to use + +### `oas_uri_to_config` + +- **Type**: `str` +- **Default**: `"/swagger-config"` +- **Description**: Path to serve the Swagger configurtaion + +### `oas_uri_to_json` + +- **Type**: `str` +- **Default**: `"/openapi.json"` +- **Description**: Path to serve the OpenAPI JSON + +### `oas_uri_to_redoc` + +- **Type**: `str` +- **Default**: `"/redoc"` +- **Description**: Path to Redoc + +### `oas_uri_to_swagger` + +- **Type**: `str` +- **Default**: `"/swagger"` +- **Description**: Path to Swagger + +### `oas_url_prefix` + +- **Type**: `str` +- **Default**: `"/docs"` +- **Description**: URL prefix for the Blueprint that all of the OAS documentation witll attach to + +### `swagger_ui_configuration` + +- **Type**: `Dict[str, Any]` +- **Default**: `{"apisSorter": "alpha", "operationsSorter": "alpha", "docExpansion": "full"}` +- **Description**: The Swagger documentation to be served to the frontend + +### `templating_enable_async` + +- **Type**: `bool` +- **Default**: `True` +- **Description**: Whether to set `enable_async` on the Jinja `Environment` + +### `templating_path_to_templates` + +- **Type**: `Union[str, os.PathLike, Sequence[Union[str, os.PathLike]]] ` +- **Default**: `templates` +- **Description**: A single path, or multiple paths to where your template files are located + +### `trace_excluded_headers` + +- **Type**: `Sequence[str]` +- **Default**: `("authorization", "cookie")` +- **Description**: Which headers should be suppresed from responses to `TRACE` requests diff --git a/src/ja/plugins/sanic-ext/convenience.md b/src/ja/plugins/sanic-ext/convenience.md index 731343f4fe..99c7408036 100644 --- a/src/ja/plugins/sanic-ext/convenience.md +++ b/src/ja/plugins/sanic-ext/convenience.md @@ -3,11 +3,8 @@ ## シリアライザーの修正 ---:1 - アプリケーションを開発していると、常に同じようなレスポンスを返すルートが存在することがよくあります。このような場合、エンドポイントで返されるシリアライザーをあらかじめ定義しておけば、あとはコンテンツを返すだけでよいのです。 - :--:1 - ```python from sanic_ext import serializer @@ -18,15 +15,11 @@ async def hello_world(request, name: str): return "hello " * int(name) return f"Hello, {name}" ``` - :--- - ---:1 - `@serializer` デコレータは、ステータスコードを追加することもできます。 - :--:1 ```python from sanic_ext import serializer @@ -40,13 +33,9 @@ async def create_something(request): ## カスタムシリアライザー - ---:1 - `@serializer` デコレータを使用すると、有効な型 (`HTTPResonse`) を返す限りにおいて、独自のカスタム関数を渡すことも可能です。 - :--:1 - ```python def message(retval, request, action, status): return json( @@ -64,13 +53,10 @@ def message(retval, request, action, status): async def do_action(request, action: str): return "This is a message" ``` - :--- ---:1 - さて、文字列だけを返すと、素敵なシリアル化された出力が返されるはずです。 - :--:1 ```python @@ -82,5 +68,31 @@ $ curl localhost:8000/eat_cookies -X POST } ``` +:--- + + +## Request counter + +---:1 +Sanic Extensions comes with a subclass of `Request` that can be setup to automatically keep track of the number of requests processed per worker process. To enable this, you should pass the `CountedRequest` class to your application contructor. +:--:1 +```python +from sanic_ext import CountedRequest + +app = Sanic(..., request_class=CountedRequest) +``` +:--- +---:1 +You will now have access to the number of requests served during the lifetime of the worker process. +:--:1 +```python +@app.get("/") +async def handler(request: CountedRequest): + return json({"count": request.count}) +``` :--- + +If possible, the request count will also be added to the [worker state](../../guide/deployment/manager.md#worker-state). + +![](https://user-images.githubusercontent.com/166269/190922460-43bd2cfc-f81a-443b-b84f-07b6ce475cbf.png) diff --git a/src/ja/plugins/sanic-ext/custom.md b/src/ja/plugins/sanic-ext/custom.md new file mode 100644 index 0000000000..ca712f183f --- /dev/null +++ b/src/ja/plugins/sanic-ext/custom.md @@ -0,0 +1,86 @@ +# Custom extensions + +It is possible to create your own custom extensions. + +Version 22.9 added the `Extend.register` [method](#extension-preregistration). This makes it extremely easy to add custom expensions to an application. + +## Anatomy of an extension + +All extensions must subclass `Extension`. + +### Required + +- `name`: By convention, the name is an all-lowercase string +- `startup`: A method that runs when the extension is added + +### Optional + +- `label`: A method that returns additional information about the extension in the MOTD +- `included`: A method that returns a boolean whether the extension should be enabled or not (could be used for example to check config state) + +### Example + +```python +from sanic import Request, Sanic, json +from sanic_ext import Extend, Extension + +app = Sanic(__name__) +app.config.MONITOR = True + + +class AutoMonitor(Extension): + name = "automonitor" + + def startup(self, bootstrap) -> None: + if self.included(): + self.app.before_server_start(self.ensure_monitor_set) + self.app.on_request(self.monitor) + + @staticmethod + async def monitor(request: Request): + if request.route and request.route.ctx.monitor: + print("....") + + @staticmethod + async def ensure_monitor_set(app: Sanic): + for route in app.router.routes: + if not hasattr(route.ctx, "monitor"): + route.ctx.monitor = False + + def label(self): + has_monitor = [ + route + for route in self.app.router.routes + if getattr(route.ctx, "monitor", None) + ] + return f"{len(has_monitor)} endpoint(s)" + + def included(self): + return self.app.config.MONITOR + + +Extend.register(AutoMonitor) + + +@app.get("/", ctx_monitor=True) +async def handler(request: Request): + return json({"foo": "bar"}) +``` + + +## Extension preregistration + +---:1 +`Extend.register` simplifies the addition of custom extensions. +:--:1 +```python +from sanic_ext import Extend, Extension + +class MyCustomExtension(Extension): + ... + +Extend.register(MyCustomExtension()) +``` +:--- + +*Added in v22.9* diff --git a/src/ja/plugins/sanic-ext/getting-started.md b/src/ja/plugins/sanic-ext/getting-started.md index ed42f5cdb3..a749f9d0ab 100644 --- a/src/ja/plugins/sanic-ext/getting-started.md +++ b/src/ja/plugins/sanic-ext/getting-started.md @@ -4,12 +4,13 @@ Sanic Extensionsは、SCOが開発し、保守している*公式サポート* ## 機能 -- 自動で`HEAD`、`OPTIONS`、`TRACE`エンドポイントを作成 - CORSによる保護 -- あらかじめ定義されたエンドポイント固有のレスポンスシリアライザー +- Jinjaによるテンプレートのレンダリング - ルートハンドラへの引数挿入 - RedocやSwaggerを使ったOpenAPIドキュメンテーション +- あらかじめ定義されたエンドポイント固有のレスポンスシリアライザー - リクエストのクエリ引数とボディ入力のバリデーション +- 自動で`HEAD`、`OPTIONS`、`TRACE`エンドポイントを作成 ## 最低要件 @@ -34,11 +35,10 @@ pip install sanic-ext Sanic Extensionsは、特別な操作なしに、たくさんの機能を有効にしてくれます。 -::: new NEW in v21.12 ---:1 Sanic Extensions (v21.12+) をセットアップするために必要なこと: **何もない**。環境にインストールされていれば、セットアップが完了し、すぐに使えるようになっています。 -このコードは、[Sanic Getting Started page](../../guide/getting-started.md) にある Hello, world アプリを変更せずにそのまま使用しています_。 +このコードは、[Sanic Getting Started page](../../guide/getting-started.md) にある Hello, world アプリ_変更せずにそのまま使用していますが_、バックグラウンドに`sanic-ext`をインストールしSanic Extensionsを利用しています。 :--:1 ```python from sanic import Sanic @@ -50,15 +50,15 @@ app = Sanic("MyHelloWorldApp") async def hello_world(request): return text("Hello, world.") ``` + :--- -::: ---:1 **古い非推奨の設定** v21.9 では、`Extend` でインスタンス化するのが最も簡単な方法です。 -Sanic Getting Started page](../../guide/getting-started.md) の Hello, world アプリを見返してみると、ここで追加されているのはハイライトした2行だけであることがわかると思います。 +[Sanicを始めよう](../../guide/getting-started.md) ページの Hello, world アプリを見返してみると、ここで追加されているのはハイライトした2行だけであることがわかると思います。 :--:1 ```python{3,6} diff --git a/src/ja/plugins/sanic-ext/health-monitor.md b/src/ja/plugins/sanic-ext/health-monitor.md new file mode 100644 index 0000000000..f311196884 --- /dev/null +++ b/src/ja/plugins/sanic-ext/health-monitor.md @@ -0,0 +1,65 @@ +# Health monitor + +The health monitor requires both `sanic>=22.9` and `sanic-ext>=22.9`. + +You can setup Sanic Extensions to monitor the health of your worker processes. This requires that you not be in [single process mode](../../guide/deployment/manager.md#single-process-mode). + +## Setup + +---:1 +Out of the box, the health monitor is disabled. You will need to opt-in if you would like to use it. +:--:1 +```python +app.config.HEALTH = True +``` +:--- + +## How does it work + +The monitor sets up a new background process that will periodically receive acknowledgements of liveliness from each worker process. If a worker process misses a report too many times, then the monitor will restart that one worker. + +## Diagnostics endpoint + +---:1 +The health monitor will also enable a diagnostics endpoint that outputs the [worker state](../../guide/deployment/manager.md#worker-state). By default is id disabled. + +::: warning +The diagnostics endpoint is not secured. If you are deploying it in a production environment, you should take steps to protect it with a proxy server if you are using one. If not, you may want to consider disabling this feature in production since it will leak details about your server state. +::: +:--:1 +``` +$ curl http://localhost:8000/__health__ +{ + 'Sanic-Main': {'pid': 99997}, + 'Sanic-Server-0-0': { + 'server': True, + 'state': 'ACKED', + 'pid': 9999, + 'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc), + 'starts': 2, + 'restart_at': datetime.datetime(2022, 10, 1, 0, 0, 12, 861332, tzinfo=datetime.timezone.utc) + }, + 'Sanic-Reloader-0': { + 'server': False, + 'state': 'STARTED', + 'pid': 99998, + 'start_at': datetime.datetime(2022, 10, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc), + 'starts': 1 + } +} +``` +:--- + + +## Configuration + +| Key | Type | Default| Description | +|--|--|--|--| +| HEALTH | `bool` | `False` | Whether to enable this extension. | +| HEALTH_ENDPOINT | `bool` | `False` | Whether to enable the diagnostics endpoint. | +| HEALTH_MAX_MISSES | `int` | `3` | The number of consecutive misses before a worker process is restarted. | +| HEALTH_MISSED_THRESHHOLD | `int` | `10` | The number of seconds the monitor checks for worker process health. | +| HEALTH_MONITOR | `bool` | `True` | Whether to enable the health monitor. | +| HEALTH_REPORT_INTERVAL | `int` | `5` | The number of seconds between reporting each acknowledgement of liveliness. | +| HEALTH_URI_TO_INFO | `str` | `""` | The URI path of the diagnostics endpoint. | +| HEALTH_URL_PREFIX | `str` | `"/__health__"` | The URI prefix of the diagnostics blueprint. | diff --git a/src/ja/plugins/sanic-ext/http/methods.md b/src/ja/plugins/sanic-ext/http/methods.md index f9d246c5e8..2a013715c8 100644 --- a/src/ja/plugins/sanic-ext/http/methods.md +++ b/src/ja/plugins/sanic-ext/http/methods.md @@ -9,7 +9,7 @@ :::tab HEAD -- **Configuration**: `AUTO_HEAD` (default `True`) +- **Configuration**: `AUTO_HEAD` (デフォルトは`True`) - **MDN**: [Read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) `HEAD` リクエストはヘッダーを提供し、それ以外は `GET` リクエストが提供するものと同じレスポンスを提供します。 @@ -36,7 +36,7 @@ content-type: text/plain; charset=utf-8 :::tab OPTIONS -- **Configuration**: `AUTO_OPTIONS` (default `True`) +- **Configuration**: `AUTO_OPTIONS` (デフォルトは`True`) - **MDN**: [Read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS) `OPTIONS` リクエストは、クライアントが与えられたエンドポイントとの通信をどのように許可されるかの詳細を受信者に提供します。 @@ -81,7 +81,7 @@ async def handler(request): ```python from sanic_ext import Extend, Config -Extend(app, config=Config(auto_trace=True)) +app.extend(config=Config(http_auto_trace=True)) ``` さて、いくつかのエンドポイントが設定されていると仮定して、以下のようにトレースすることができます。 diff --git a/src/ja/plugins/sanic-ext/injection.md b/src/ja/plugins/sanic-ext/injection.md index 2de93dd596..5e68c9517c 100644 --- a/src/ja/plugins/sanic-ext/injection.md +++ b/src/ja/plugins/sanic-ext/injection.md @@ -30,11 +30,8 @@ v21.12より前に依存性インジェクションを使用していた場合 最も単純な使用例は、単に値を再キャストすることです。 ---:1 - これは、マッチしたパスパラメータに基づいて生成したいモデルがある場合に便利です。 - :--:1 - ```python @dataclass class IceCream: @@ -69,13 +66,10 @@ flavor = IceCream(flavor="chocolate") ## 追加コンストラクタ ---:1 - 時には、コンストラクタを渡す必要があるかもしれません。これは関数でもいいですし、クラスメソッドでコンストラクタとして動作させることもできます。この例では、最初に `Person.create` を呼び出すインジェクションを作成します。 また、この例で重要なのは、実際に**2個**のオブジェクトをインジェクションしていることです! もちろん、このようにする必要はありませんが、関数のサインに基づいてオブジェクトをインジェクトすることになります。 - :--:1 - ```python @dataclass class PersonID: @@ -113,14 +107,40 @@ Person(person_id=PersonID(person_id=123), name='noname', age=111) この例のように `ext.add_dependency` に `constructor` が渡されると、それが呼び出されます。そうでない場合は、 `type` を呼び出してオブジェクトを生成します。`constructor`を渡す際に注意すべき点がいくつかある。 -1. `request: request` の位置専用引数が期待されます。例として、上記の `Person.create` メソッドを参照してください。 +1. A positional `request: Request` argument is *usually* expected. See the `Person.create` method above as an example using a `request` and [arbitrary constructors](#arbitrary-constructors) for how to use a callable that does not require a `request`. 1. マッチしたすべてのパスパラメータは、キーワード引数として注入されます。 1. 依存関係は、連鎖したり、ネストしたりすることができます。先ほどの例で、`Person`データクラスが`PersonID`を持っていることに注目しましたか?これは、 `PersonID` が最初に呼び出され、その値が `Person.create` を呼び出す際のキーワード引数に追加されることを意味します。 -## `Request`からのオブジェクト +## Arbitrary constructors ---:1 +Sometimes you may want to construct your injectable _without_ the `Request` object. This is useful if you have arbitrary classes or functions that create your objects. If the callable does have any required arguments, then they should themselves be injectable objects. + +This is very useful if you have services or other types of objects that should only exist for the lifetime of a single request. For example, you might use this pattern to pull a single connection from your database pool. +:--:1 +```python +class Alpha: + ... + + +class Beta: + def __init__(self, alpha: Alpha) -> None: + self.alpha = alpha + +app.ext.add_dependency(Alpha) +app.ext.add_dependency(Beta) + +@app.get("/beta") +async def handler(request: Request, beta: Beta): + assert isinstance(beta.alpha, Alpha) +``` +:--- + +*Added in v22.9* +## `Request`からのオブジェクト + +---:1 時には、リクエストから詳細を抽出し、前処理を行いたい場合があります。例えば、リクエストのJSONをPythonのオブジェクトにキャストし、DBクエリに基づいていくつかの追加ロジックを追加することができます。 ::: warning @@ -136,16 +156,15 @@ await request.receive_body() - ミドルウェアを使用して、前処理と `request.ctx` への追加を行う。 - デコレータを使用して、前処理とリクエストハンドラへの引数の注入を行う。 -この例では、`compule_profile` コンストラクタで `Request` オブジェクトを使用して、偽の DB クエリを実行して `UserProfile` オブジェクトを生成し、それを返します。 - :--:1 +この例では、`compile_profile` コンストラクタで `Request` オブジェクトを使用して、偽の DB クエリを実行して `UserProfile` オブジェクトを生成し、それを返します。 +:--:1 +```python +@dataclass +class User: + name: str - ```python - @dataclass - class User: - name: str - - @dataclass +@dataclass class UserProfile: user: User age: int = field(default=0) @@ -202,13 +221,10 @@ $ curl localhost:8000/profile -X PATCH -d '{"name": "Alice", "birthday": "2000-0 データベースのコネクションプールのようなものを作成して、それを `app.ctx` オブジェクトに格納するのはよくあるパターンです。これにより、アプリケーション全体でそれらを利用できるようになり、確かに便利です。しかし、1つの欠点は、型付けされたオブジェクトを扱うことができなくなることです。これを解決するために、依存性注入を使用することができます。まず、これまでの例で使ってきたような低レベルの `add_dependency` を使って、そのコンセプトを紹介します。しかし、より高いレベルの `dependency` メソッドを使用することで、より良い方法があります。 ---:1 - ### `add_dependency` を使った低レベル API これは [最後の例](#objects-from-the-request) と非常によく似た動作で、ゴールは `Request` オブジェクトから何かを抽出することです。この例では、データベースオブジェクトが `app.ctx` インスタンスに作成され、依存性注入のコンストラクタで返されています。 - :--:1 - ```python class FakeConnection: async def execute(self, query: str, **arguments): @@ -236,19 +252,15 @@ async def handler(request, conn: FakeConnection): $ curl localhost:8000/ result ``` - :--- ---:1 - ### 上位APIを使った`dependency` 依存性インジェクションを追加する際に利用できる実際の *オブジェクト* があるので、より高レベルの `dependency` メソッドを使用することができます。これにより、パターンを書くのがより簡単になります。 このメソッドは、アプリケーションインスタンスのライフタイムを通じて存在し、リクエストに依存しないものをインジェクションしたい場合に常に使用する必要があります。サービスやサードパーティークライアント、コネクションプールなどはリクエストに依存しないので、非常に便利です。 - :--:1 - ```python class FakeConnection: async def execute(self, query: str, **arguments): @@ -270,5 +282,69 @@ async def handler(request, conn: FakeConnection): $ curl localhost:8000/ result ``` +:--- + +## Generic types +Be carefule when using a [generic type](https://docs.python.org/3/library/typing.html#typing.Generic). The way that Sanic's dependency injection works is by matching the entire type definition. Therefore, `Foo` is not the same as `Foo[str]`. This can be particularly tricky when trying to use the [higher-level `dependency` method](#the-higher-level-api-using-dependency) since the type is inferred. + +---:1 +For example, this will **NOT** work as expected since there is no definition for `Test[str]`. +:--:1 +```python{12,16} +import typing +from sanic import Sanic, text + +T = typing.TypeVar("T") + + +class Test(typing.Generic[T]): + test: T + + +app = Sanic("testapp") +app.ext.dependency(Test()) + + +@app.get("/") +def test(request, test: Test[str]): + ... +``` :--- + +---:1 +To get this example to work, you will need to add an explicit definition for the type you intend to be injected. +:--:1 +```python{13} +import typing +from sanic import Sanic, text + +T = typing.TypeVar("T") + + +class Test(typing.Generic[T]): + test: T + + +app = Sanic("testapp") +_singleton = Test() +app.ext.add_dependency(Test[str], lambda: _singleton) + + +@app.get("/") +def test(request, test: Test[str]): + ... +``` +:--- + +## Configuration + +---:1 +By default, dependencies will be injected after the `http.routing.after` [signal](../../guide/advanced/signals.md#built-in-signals). Starting in v22.9, you can change this to the `http.handler.before` signal. +:--:1 +```python +app.config.INJECTION_SIGNAL = "http.handler.before" +``` +:--- + +*Added in v22.9* diff --git a/src/ja/plugins/sanic-ext/logger.md b/src/ja/plugins/sanic-ext/logger.md new file mode 100644 index 0000000000..13536d80d5 --- /dev/null +++ b/src/ja/plugins/sanic-ext/logger.md @@ -0,0 +1,28 @@ +# Background logger + +The background logger requires both `sanic>=22.9` and `sanic-ext>=22.9`. + +You can setup Sanic Extensions to log all of your messages from a background process. This requires that you not be in [single process mode](../../guide/deployment/manager.md#single-process-mode). + +Logging can sometimes be an expensive operation. By pushing all logging off to a background process, you can potentially gain some performance benefits. + +## Setup + +---:1 +Out of the box, the background logger is disabled. You will need to opt-in if you would like to use it. +:--:1 +```python +app.config.LOGGING = True +``` +:--- + +## How does it work + +When enabled, the extension will create a `multoprocessing.Queue`. It will remove all handlers on the [default Sanic loggers](../../guide/best-practices/logging.md) and replace them with a [`QueueHandler`](https://docs.python.org/3/library/logging.handlers.html#queuehandler). When a message is logged, it will be pushed into the queue by the handler, and read by the background process to the log handlers that were originally in place. This means you can still configure logging as normal and it should "just work." + +## Configuration + +| Key | Type | Default| Description | +|--|--|--|--| +| LOGGING | `bool` | `False` | Whether to enable this extension. | +| LOGGING_QUEUE_MAX_SIZE | `int` | `4096` | The max size of the queue before messages are rejected. | diff --git a/src/ja/plugins/sanic-ext/openapi/advanced.md b/src/ja/plugins/sanic-ext/openapi/advanced.md index 23969ec2e3..46ebf6a139 100644 --- a/src/ja/plugins/sanic-ext/openapi/advanced.md +++ b/src/ja/plugins/sanic-ext/openapi/advanced.md @@ -1,6 +1,6 @@ # 高機能 -_ドキュメンテーションは2021年10月に追加予定_ +_ドキュメンテーションは2023年第1期に追加予定_ ## CBV diff --git a/src/ja/plugins/sanic-ext/openapi/basic.md b/src/ja/plugins/sanic-ext/openapi/basic.md index 6672702ff3..34cb8666c2 100644 --- a/src/ja/plugins/sanic-ext/openapi/basic.md +++ b/src/ja/plugins/sanic-ext/openapi/basic.md @@ -6,24 +6,27 @@ Sanic ExtensionsのOpenAPI実装は、[`sanic-openapi`](https://github.com/sanic ---:1 -Sanic Extensionsは、[v3.0 OpenAPI仕様](https://swagger.io/specification/)を用いて自動生成されたAPIドキュメントをそのまま提供します。必要なのは、Sanic Extensionsをインスタンス化することによって、アプリケーションを`拡張`することだけです。 +Sanic Extensionsは、[v3.0 OpenAPI仕様](https://swagger.io/specification/)を用いて自動生成されたAPIドキュメントをそのまま提供します。あなたがする必要のあることはありません。 :--:1 ```python from sanic import Sanic -from sanic_ext import Extend app = Sanic("MyApp") -Extend(app) + +# すべてのviewを追加する ``` :--- これで、既存のアプリケーションに基づいた美しいドキュメントがすでに生成されていることになります: -[http://localhost:8000/docs](http://localhost:8000/docs) + [http://localhost:8000/docs](http://localhost:8000/docs) +- [http://localhost:8000/docs/redoc](http://localhost:8000/docs/redoc) +- [http://localhost:8000/docs/swagger](http://localhost:8000/docs/swagger) +Checkout the [section on configuration](../configuration.md) to learn about changing the routes for the docs. You can also turn off one of the two UIs, and customize which UI will be available on the `/docs` route. ---:1 @@ -38,4 +41,30 @@ Extend(app) ![Swagger UI](~@assets/images/sanic-ext-swagger.png) + +:--- + +## Changing specification metadata + +---:1 +If you want to change any of the metada, you should use the `describe` method. + +In this example `dedent` is being used with the `description` argument to make multi-line strings a little cleaner. This is not necessary, you can pass any string value here. +:--:1 +```python +from textwrap import dedent + +app.ext.openapi.describe( + "Testing API", + version="1.2.3", + description=dedent( + """ + # Info + This is a description. It is a good place to add some _extra_ doccumentation. + + **MARKDOWN** is supported. + """ + ), +) +``` :--- diff --git a/src/ja/plugins/sanic-ext/openapi/decorators.md b/src/ja/plugins/sanic-ext/openapi/decorators.md index f0fb37ac54..a6d8173d8d 100644 --- a/src/ja/plugins/sanic-ext/openapi/decorators.md +++ b/src/ja/plugins/sanic-ext/openapi/decorators.md @@ -38,7 +38,7 @@ class UserProfile: ## デコレーターの定義 -### `@opanepi.definition` +### `@openapi.definition` `@openapi.definition`デコレーターを使用すると、パス上の操作のすべての部分を一度に定義することができます。これは、他のデコレーターと同じように操作の定義を作成できるオムニバムデコレーターです。複数のフィールド固有のデコレータを使うか、あるいは単一のデコレータを使うかは、 開発者のスタイルによります。 @@ -54,10 +54,11 @@ class UserProfile: | `document` | **str, ExternalDocumentation** | | `exclude` | **bool** | | `operation` | **str** | -| `parameter` | **dict, Parameter, *ユーザー定義モデル*, [dict], [Parameter], [*ユーザー定義モデル*]** | -| `response` | **dict, Response, *ユーザー定義モデル*, [dict], [Response], [*ユーザー定義モデル*]** | +| `parameter` | **str, dict, Parameter, [str], [dict], [Parameter]** | +| `response` | **dict, Response, *ユーザー定義モデル*, [dict], [Response]** | | `summary` | **str** | | `tag` | **str, Tag, [str], [Tag]** | +| `secured` | **Dict[str, Any]** | **Examples** @@ -118,6 +119,10 @@ class UserProfile: @openapi.body(RequestBody(UserProfile)) ``` +```python +@openapi.body({"application/json": {"description": ...}}) +``` + :--- ::: @@ -400,4 +405,79 @@ openapi.exclude(bp=some_blueprint) :--- +::: + +:::tab secured + +**Arguments** + +| Field | Type | +| ----------------- | ----------------------- | +| `*args, **kwargs` | **str, Dict[str, Any]** | + +**Examples** + +---:1 +```python +@openapi.secured() +``` +:--:1 +:--- + +---:1 +```python +@openapi.tag("foo") +``` +:--:1 +```python +@openapi.secured("token1", "token2") +``` +:--- + +---:1 +```python +@openapi.tag({"my_api_key": []}) +``` +:--:1 +```python +@openapi.secured(my_api_key=[]) +``` +:--- + +Do not forget to use `add_security_scheme`. See [security](./security.md) for more details. + +::: + :::: + + +## Integration with Pydantic + +Pydantic models have the ability to [generate OpenAPI schema](https://pydantic-docs.helpmanual.io/usage/schema/). + +---:1 +To take advantage of Pydantic model schema generation, pass the output in place of the schema. +:--:1 +```python +from sanic import Sanic, json +from sanic_ext import validate, openapi +from pydantic import BaseModel, Field + +class Test(BaseModel): + foo: str = Field(description="Foo Description", example="FOOO") + bar: str = "test" + + +app = Sanic("test") + +@app.get("/") +@openapi.definition( + body={'application/json': Test.schema()}, +) +@validate(json=Test) +async def get(request): + return json({}) +``` +:--- + +*Added in v22.9* diff --git a/src/ja/plugins/sanic-ext/templating.md b/src/ja/plugins/sanic-ext/templating.md new file mode 100644 index 0000000000..d973f093f2 --- /dev/null +++ b/src/ja/plugins/sanic-ext/templating.md @@ -0,0 +1,142 @@ +# Templating + +Sanic Extensions can easily help you integrate templates into your route handlers. + + +## Dependencies + +**Currently, we only support [Jinja](https://github.com/pallets/jinja/).** + +[Read the Jinja docs first](https://jinja.palletsprojects.com/en/3.1.x/) if you are unfamiliar with how to create templates. + +Sanic Extensions will automatically setup and load Jinja for you if it is installed in your environment. Therefore, the only setup that you need to do is install Jinja: + +``` +pip install Jinja2 +``` + +## Rendering a template from a file + +There are three (3) ways for you: + +1. Using a decorator to pre-load the template file +1. Returning a rendered `HTTPResponse` object +1. Hybrid pattern that creates a `LazyResponse` + +Let's imagine you have a file called `./templates/foo.html`: + +```html + + + + + My Webpage + + + +

Hello, world!!!!

+
    + {% for item in seq %} +
  • {{ item }}
  • + {% endfor %} +
+ + + +``` + +Let's see how you could render it with Sanic + Jinja. + +### Option 1 - as a decorator + +---:1 +The benefit of this approach is that the templates can be predefined at startup time. This will mean that less fetching needs to happen in the handler, and should therefore be the fastest option. +:--:1 +```python +@app.get("/") +@app.ext.template("foo.html") +async def handler(request: Request): + return {"seq": ["one", "two"]} +``` +:--- + +### Option 2 - as a return object + +---:1 +This is meant to mimic the `text`, `json`, `html`, `file`, etc pattern of core Sanic. It will allow the most customization to the response object since it has direct control of it. Just like in other `HTTPResponse` objects, you can control headers, cookies, etc. +:--:1 +```python +from sanic_ext import render + +@app.get("/alt") +async def handler(request: Request): + return await render( + "foo.html", context={"seq": ["three", "four"]}, status=400 + ) +``` +:--- + +### Option 3 - hybrid/lazy + +---:1 +In this approach, the template is defined up front and not inside the handler (for performance). Then, the `render` function returns a `LazyResponse` that can be used to build a proper `HTTPResponse` inside the decorator. +:--:1 +```python +from sanic_ext import render + +@app.get("/") +@app.ext.template("foo.html") +async def handler(request: Request): + return await render(context={"seq": ["five", "six"]}, status=400) +``` +:--- + +## Rendering a template from a string + +---:1 +Sometimes you may want to write (or generate) your template inside of Python code and _not_ read it from an HTML file. In this case, you can still use the `render` function we saw above. Just use `template_source`. +:--:1 +```python +from sanic_ext import render +from textwrap import dedent + +@app.get("/") +async def handler(request): + template = dedent(""" + + + + + My Webpage + + + +

Hello, world!!!!

+
    + {% for item in seq %} +
  • {{ item }}
  • + {% endfor %} +
+ + + + """) + return await render( + template_source=template, + context={"seq": ["three", "four"]}, + app=app, + ) +``` +:--- + +::: tip +In this example, we use `textwrap.dedent` to remove the whitespace in the beginning of each line of the multi-line string. It is not necessary, but just a nice touch to keep both the code and the generated source clean. +::: + +## Development and auto-reload + +If auto-reload is turned on, then changes to your template files should trigger a reload of the server. + +## Configuration + +See `templating_enable_async` and `templating_path_to_templates` in [settings](./configuration.md#settings). diff --git a/src/ja/plugins/sanic-ext/validation.md b/src/ja/plugins/sanic-ext/validation.md index 0e8eb44554..2925400d26 100644 --- a/src/ja/plugins/sanic-ext/validation.md +++ b/src/ja/plugins/sanic-ext/validation.md @@ -6,7 +6,7 @@ Webアプリケーションで最もよく実装される機能の1つが、ユ ### データクラスによる検証 -[データクラス](https://docs.python.org/3/library/dataclasses.html) の導入により、Pythonは定義されたスキーマを満たすオブジェクトをとても簡単に作成することができるようになりました。しかし、標準ライブラリは型チェックの検証のみをサポートし、実行時の検証はサポート**していません**。Sanic Extensionsは`dataclasses`を使って、入力されたリクエストに対して実行時の検証を行う機能を追加します。 +With the introduction of [Data Classes](https://docs.python.org/3/library/dataclasses.html), Python made it super simple to create objects that meet a defined schema. However, the standard library only supports type checking validation, **not** runtime validation. Sanic Extensions adds the ability to do runtime validations on incoming requests using `dataclasses` out of the box. If you also have either `pydantic` or `attrs` installed, you can alternatively use one of those libraries. ---:1 @@ -60,9 +60,6 @@ $ curl localhost:8000/search\?q=python ### Pydanticを使ったバリデーション -::: warning -現在、PydanticモデルをサポートしているのはJSONボディの検証のみです。 -::: Pydanticモデルの使用もできます。 @@ -109,6 +106,56 @@ $ curl localhost:8000/person -d '{"name": "Alice", "age": 21}' -X POST :--- +### Validation with Attrs + + +You can use Attrs also. + +---:1 + +First, define a model. + +:--:1 + +```python +@attrs.define +class Person: + name: str + age: int + +``` + +:--- + +---:1 + +Then, attach it to your route + +:--:1 + +```python +from sanic_ext import validate + +@app.post("/person") +@validate(json=Person) +async def handler(request, body: Person): + return json(attrs.asdict(body)) +``` +:--- + +---:1 + +You should now have validation on the incoming request. + +:--:1 + +``` +$ curl localhost:8000/person -d '{"name": "Alice", "age": 21}' -X POST +{"name":"Alice","age":21} +``` + +:--- + ## 何が検証できるのか? `validate` デコレータを使用すると、3つの場所から入力されたユーザーデータを検証することができます。JSON の本文(`request.json`)、フォームの本文(`request.form`)、そしてクエリパラメータ(`request.args`) です。 diff --git a/src/ja/plugins/sanic-testing/clients.md b/src/ja/plugins/sanic-testing/clients.md index 40912aa10d..0bcbb4af78 100644 --- a/src/ja/plugins/sanic-testing/clients.md +++ b/src/ja/plugins/sanic-testing/clients.md @@ -65,7 +65,7 @@ test_client.request("/path/to/endpoint", http_method="get") このテストクライアントは、`SanicTestClient` と同じメソッドを提供し、一般的に動作します。唯一の違いは、各コールに `await` を追加する必要があることです。 :--: ```python -await app.test_client.get("/path/to/endpoint") +await app.asgi_client.get("/path/to/endpoint") ``` :---