1
0
mirror of https://github.com/actix/actix-website synced 2024-11-24 00:41:07 +01:00
This commit is contained in:
Rob Ede 2020-09-12 16:21:54 +01:00 committed by GitHub
parent a0ce9f28e2
commit 4d8d53cea5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
145 changed files with 1011 additions and 1461 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ _site
Cargo.lock
build/
target/
.DS_Store

13
.prettierrc.json Normal file
View File

@ -0,0 +1,13 @@
{
"singleQuote": true,
"tabWidth": 2,
"overrides": [
{
"files": ["*.md"],
"options": {
"proseWrap": "always",
"printWidth": 100
}
}
]
}

View File

@ -4,11 +4,12 @@ The work in progress website for the actix project based on tokio's website.
## Getting Started
Building the website depends on [Hugo](http://gohugo.io). So, first make sure
that you have it installed. If on OS X and using Homebrew, run the following:
Building the website depends on [Hugo]. So, first make sure
that you have it installed. If on macOS and using [Homebrew], run the following:
```sh
brew update && brew install hugo
brew update
brew install hugo
```
Then, get the website running locally:
@ -16,16 +17,18 @@ Then, get the website running locally:
```sh
git clone https://github.com/actix/actix-website.git
cd actix-website
hugo server
```
Then visit [http://localhost:1313](http://localhost:1313).
Then visit http://localhost:1313.
## Updating diagrams
Diagrams are located under [/static/css/img/diagrams/](https://github.com/actix/actix-website/tree/master/static/img/diagrams) and built with [Mermaid CLI](https://github.com/mermaidjs/mermaid.cli).
Diagrams are located under [/static/css/img/diagrams/](https://github.com/actix/actix-website/tree/master/static/img/diagrams) and built with [Mermaid CLI].
For instance to edit `connection_overview` diagram:
```sh
cd static/css/img/diagrams
vi connection_overview.mmd
@ -35,5 +38,11 @@ mmdc -i connection_overview.mmd -o connection_overview.svg
# License
Pretty murky. Right now a massive clone of the tokio website. Will get this
Pretty murky. Right now a massive clone of the tokio website. Will get this
figured out as we go along.
<!-- LINKS -->
[Hugo]: https://gohugo.io
[Homebrew]: https://brew.sh
[Mermaid CLI]: https://github.com/mermaidjs/mermaid.cli

View File

@ -10,13 +10,13 @@ DefaultContentLanguage = "en"
baseURL = "https://actix.rs"
[languages.en]
languageCode = "en-US"
languageName = "English"
weight = 1
languageCode = "en-US"
languageName = "English"
weight = 1
[params]
actixVersion = "0.9"
actixWebVersion = "2.0"
actixRtVersion = "1.0"
actixWebMinRustVersion = "1.39"
actixMinRustVersion = "1.39"
actixVersion = "0.10"
actixWebVersion = "3"
actixRtVersion = "1.1"
actixWebMinRustVersion = "1.42"
actixMinRustVersion = "1.42"

View File

@ -1,3 +1,3 @@
---
title: Rust's powerful actor system and most fun web framework
title: Actix Web | A powerful, pragmatic, and extremely fast web framework for Rust.
---

View File

@ -5,15 +5,19 @@ description: Browse and download the sources
# Browse the Code
All of actix is open source and can be found on our github organization: [actix
on github](https://github.com/actix)
The Actix ecosystem is fully open source on our GitHub organization [@actix](https://github.com/actix).
Here are the most important projects and the link to their github repositories
and related resources:
* [actix](https://github.com/actix/actix) ([issues](https://github.com/actix/actix/issues), [ci](https://travis-ci.org/actix/actix), [crate](https://crates.io/crates/actix), [api docs](https://docs.rs/actix))
* [actix-web](https://github.com/actix/actix-web) ([issues](https://github.com/actix/actix-web/issues), [ci](https://travis-ci.org/actix/actix-web), [crate](https://crates.io/crates/actix-web), [api docs](https://docs.rs/actix-web))
* [example code](https://github.com/actix/examples)
* [this website](https://github.com/actix/actix-website)
- [actix-web](https://github.com/actix/actix-web), ([API docs](https://docs.rs/actix-web))
- [actix-extras crates](https://github.com/actix/actix-extras)
- [actix-net crates](https://github.com/actix/actix-net)
- [actix](https://github.com/actix/actix), ([API docs](https://docs.rs/actix))
- [examples repo](https://github.com/actix/examples)
- [this website](https://github.com/actix/actix-website)
Actix is dual licensed under the MIT and Apache 2 licenses. [Read license text](license/).
Actix is dual licensed under the [MIT] and [Apache 2] licenses.
[mit]: https://github.com/actix/actix-web/blob/master/LICENSE-MIT
[apache 2]: https://github.com/actix/actix-web/blob/master/LICENSE-APACHE

View File

@ -1,201 +0,0 @@
---
title: License
---
Actix is dual licensed under MIT and Apache licenses.
# MIT License
Copyright (c) 2017 Nikolay Kim
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
# Apache License
_Version 2.0, January 2004_
http://www.apache.org/licenses/
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

View File

@ -5,16 +5,13 @@ description: The best things in life are to be shared
# Join us
Want to talk to others about questions? The [actix gitter
channel](https://gitter.im/actix/actix) or
[reddit community](https://www.reddit.com/r/actix/)
are your best starting point.
Want to talk to others about questions? The Actix [Gitter channel](https://gitter.im/actix/actix) or
[reddit community](https://www.reddit.com/r/actix/) are your best starting point.
If you think you found a bug it's best to go to the
[github](https://github.com/actix) directly. There are two repositories
that you might want to report against. [actix](https://github.com/actix/actix)
for issues with the actor framework or [actix-web](https://github.com/actix/actix-web)
for the high level web framework.
If you think you found a bug it's best to go to the [github](https://github.com/actix) directly.
There are two repositories that you might want to report against.
[actix](https://github.com/actix/actix) for issues with the actor framework or
[actix-web](https://github.com/actix/actix-web) for the web framework.
We're a welcoming community so don't be afraid to engage. Interactions
are [governed by our code of conduct](coc/).
We're a welcoming community so don't be afraid to engage. Interactions are
[governed by our code of conduct](coc/).

View File

@ -1,6 +1,6 @@
---
title: Documentation
description: Guiding you through building apps with actix
description: Guiding you through building web apps with Actix
menu:
docs_intro:
name: Welcome
@ -9,19 +9,16 @@ weight: 10
# Welcome to Actix
Actix is your door to developing web services with Rust and this documentation
is going to guide you.
Actix Web lets you quickly and confidently develop web services in Rust and this guide get you going
in no time.
This documentation currently covers mostly the `actix-web` part which is the high level
web framework previously built on top of the `actix` actor framework and the [Tokio][tokio]
async IO system. This is the part that is from an API stability point of view the most stable.
The documentation on this website focusses primarily on the Actix Web framework. For information
about the actor framework called Actix, check out the [Actix book][actix-book] (or the lower level
[actix API docs][actix-docs]). Otherwise, head on to the [getting started guide][getting-started].
If you already know your ways around and you need specific information you might want to read the
[actix-web API docs][actix-web-docs].
If you haven't used `actix-web` yet it's best to start with the [getting started
guide][gettingstarted]. If you already know your ways around and you need
specific information you might want to read the [actix-web API docs][actixwebdocs]
(or the lower level [actix API docs][actixdocs]).
[gettingstarted]: ./getting-started
[actixwebdocs]: https://docs.rs/actix-web
[actixdocs]: https://docs.rs/actix
[tokio]: https://tokio.rs
[getting-started]: ./getting-started
[actix-web-docs]: https://docs.rs/actix-web
[actix-docs]: https://docs.rs/actix
[actix-book]: https://actix.rs/book/actix

View File

@ -6,35 +6,33 @@ weight: 140
# Writing an Application
`actix-web` provides various primitives to build web servers and applications with Rust.
It provides routing, middlewares, pre-processing of requests, post-processing of
responses, etc.
`actix-web` provides various primitives to build web servers and applications with Rust. It provides
routing, middleware, pre-processing of requests, post-processing of responses, etc.
All `actix-web` servers are built around the [`App`][app] instance. It is used for
registering routes for resources and middlewares. It also stores application
state shared across all handlers within the same scope.
All `actix-web` servers are built around the [`App`][app] instance. It is used for registering
routes for resources and middleware. It also stores application state shared across all handlers
within the same scope.
An application's [`scope`][scope] acts as a namespace for all routes, i.e. all routes for a
specific application scope have the same url path prefix. The application prefix always
contains a leading "/" slash. If a supplied prefix does not contain leading slash,
it is automatically inserted. The prefix should consist of value path segments.
An application's [`scope`][scope] acts as a namespace for all routes, i.e. all routes for a specific
application scope have the same url path prefix. The application prefix always contains a leading
"/" slash. If a supplied prefix does not contain leading slash, it is automatically inserted. The
prefix should consist of value path segments.
> For an application with scope `/app`,
> any request with the paths `/app`, `/app/`, or `/app/test` would match;
> however, the path `/application` would not match.
> For an application with scope `/app`, any request with the paths `/app`, `/app/`, or `/app/test`
> would match; however, the path `/application` would not match.
{{< include-example example="application" file="app.rs" section="setup" >}}
In this example, an application with the `/app` prefix and a `index.html` resource
are created. This resource is available through the `/app/index.html` url.
In this example, an application with the `/app` prefix and a `index.html` resource are created. This
resource is available through the `/app/index.html` url.
> For more information, check the [URL Dispatch][usingappprefix] section.
## State
Application state is shared with all routes and resources within the same scope. State
can be accessed with the [`web::Data<T>`][data] extractor where `T` is the type of the state. State is
also available for middlewares.
Application state is shared with all routes and resources within the same scope. State can be
accessed with the [`web::Data<T>`][data] extractor where `T` is the type of the state. State is also
accessible for middleware.
Let's write a simple application and store the application name in the state:
@ -48,14 +46,16 @@ Any number of state types could be registered within the application.
## Shared Mutable State
`HttpServer` accepts an application factory rather than an application instance.
An `HttpServer` constructs an application instance for each thread. Therefore, application data must be
constructed multiple times. If you want to share data between different threads, a shareable
object should be used, e.g. `Send` + `Sync`.
`HttpServer` accepts an application factory rather than an application instance. An `HttpServer`
constructs an application instance for each thread. Therefore, application data must be constructed
multiple times. If you want to share data between different threads, a shareable object should be
used, e.g. `Send` + `Sync`.
Internally, [`web::Data`][data] uses `Arc`. Thus, in order to avoid creating two `Arc`s, we should create our Data before registering it using [`App::app_data()`][appdata].
Internally, [`web::Data`][data] uses `Arc`. Thus, in order to avoid creating two `Arc`s, we should
create our Data before registering it using [`App::app_data()`][appdata].
In the following example, we will write an application with mutable, shared state. First, we define our state and create our handler:
In the following example, we will write an application with mutable, shared state. First, we define
our state and create our handler:
{{< include-example example="application" file="mutable_state.rs" section="setup_mutable" >}}
@ -67,37 +67,37 @@ and register the data in an `App`:
The [`web::scope()`][webscope] method allows setting a resource group prefix. This scope represents
a resource prefix that will be prepended to all resource patterns added by the resource
configuration. This can be used to help mount a set of routes at a different location
than the original author intended while still maintaining the same resource names.
configuration. This can be used to help mount a set of routes at a different location than the
original author intended while still maintaining the same resource names.
For example:
{{< include-example example="application" file="scope.rs" section="scope" >}}
In the above example, the `show_users` route will have an effective route pattern of
`/users/show` instead of `/show` because the application's scope argument will be prepended
to the pattern. The route will then only match if the URL path is `/users/show`,
and when the [`HttpRequest.url_for()`][urlfor] function is called with the route name `show_users`,
it will generate a URL with that same path.
In the above example, the `show_users` route will have an effective route pattern of `/users/show`
instead of `/show` because the application's scope argument will be prepended to the pattern. The
route will then only match if the URL path is `/users/show`, and when the
[`HttpRequest.url_for()`][urlfor] function is called with the route name `show_users`, it will
generate a URL with that same path.
## Application guards and virtual hosting
You can think of a guard as a simple function that accepts a *request* object reference
and returns *true* or *false*. Formally, a guard is any object that implements the
[`Guard`][guardtrait] trait. Actix-web provides several guards. You can check the
[functions section][guardfuncs] of the API docs.
You can think of a guard as a simple function that accepts a _request_ object reference and returns
_true_ or _false_. Formally, a guard is any object that implements the [`Guard`][guardtrait] trait.
Actix-web provides several guards. You can check the [functions section][guardfuncs] of the API
docs.
One of the provided guards is [`Header`][guardheader]. It can be used as a
filter based on request header information.
One of the provided guards is [`Header`][guardheader]. It can be used as a filter based on request
header information.
{{< include-example example="application" file="vh.rs" section="vh" >}}
# Configure
For simplicity and reusability both [`App`][appconfig] and [`web::Scope`][webscopeconfig] provide the `configure` method.
This function is useful for moving parts of the configuration to a different module or even
library. For example, some of the resource's configuration could be moved to a different
module.
For simplicity and reusability both [`App`][appconfig] and [`web::Scope`][webscopeconfig] provide
the `configure` method. This function is useful for moving parts of the configuration to a different
module or even library. For example, some of the resource's configuration could be moved to a
different module.
{{< include-example example="application" file="config.rs" section="config" >}}
@ -108,19 +108,22 @@ The result of the above example would be:
/app -> "app"
/api/test -> "test"
```
Each [`ServiceConfig`][serviceconfig] can have its own `data`, `routes`, and `services`.
<!-- LINKS -->
[usingappprefix]: /docs/url-dispatch/index.html#using-an-application-prefix-to-compose-applications
[stateexample]: https://github.com/actix/examples/blob/master/state/src/main.rs
[guardtrait]: https://docs.rs/actix-web/2/actix_web/guard/trait.Guard.html
[guardfuncs]: https://docs.rs/actix-web/2/actix_web/guard/index.html#functions
[guardheader]: https://docs.rs/actix-web/2/actix_web/guard/fn.Header.html
[data]: https://docs.rs/actix-web/2/actix_web/web/struct.Data.html
[app]: https://docs.rs/actix-web/2/actix_web/struct.App.html
[appconfig]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.configure
[appdata]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.app_data
[scope]: https://docs.rs/actix-web/2/actix_web/struct.Scope.html
[webscopeconfig]: https://docs.rs/actix-web/2/actix_web/struct.Scope.html#method.configure
[webscope]: https://docs.rs/actix-web/2/actix_web/web/fn.scope.html
[urlfor]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.url_for
[serviceconfig]: https://docs.rs/actix-web/2/actix_web/web/struct.ServiceConfig.html
[guardtrait]: https://docs.rs/actix-web/3/actix_web/guard/trait.Guard.html
[guardfuncs]: https://docs.rs/actix-web/3/actix_web/guard/index.html#functions
[guardheader]: https://docs.rs/actix-web/3/actix_web/guard/fn.Header.html
[data]: https://docs.rs/actix-web/3/actix_web/web/struct.Data.html
[app]: https://docs.rs/actix-web/3/actix_web/struct.App.html
[appconfig]: https://docs.rs/actix-web/3/actix_web/struct.App.html#method.configure
[appdata]: https://docs.rs/actix-web/3/actix_web/struct.App.html#method.app_data
[scope]: https://docs.rs/actix-web/3/actix_web/struct.Scope.html
[webscopeconfig]: https://docs.rs/actix-web/3/actix_web/struct.Scope.html#method.configure
[webscope]: https://docs.rs/actix-web/3/actix_web/web/fn.scope.html
[urlfor]: https://docs.rs/actix-web/3/actix_web/struct.HttpRequest.html#method.url_for
[serviceconfig]: https://docs.rs/actix-web/3/actix_web/web/struct.ServiceConfig.html

View File

@ -1,52 +0,0 @@
---
title: Autoreloading
menu: docs_patterns
weight: 1000
---
# Auto-Reloading Development Server
During development it can be very handy to have cargo automatically recompile the code
on change. This can be accomplished by using [cargo-watch][cargowatch]. Because an
actix app will typically bind to a port for listening for incoming HTTP requests it makes
sense to combine this with the [listenfd][listenfd] crate and the [systemfd][systemfd]
utility to ensure the socket is kept open while the app is compiling and reloading.
`systemfd` will open a socket and pass it to `cargo-watch` which will watch for
changes and then invoke the compiler and run your actix app. The actix app
will then use `listenfd` to pick up the socket that `systemfd` opened.
## Binaries Necessary
For an automatic reloading experience you need to install `cargo-watch` and
`systemfd`. Both are written in Rust and can be installed with `cargo install`:
```
cargo install systemfd cargo-watch
```
## Code Changes
Additionally you need to slightly modify your actix app so that it can pick up
an external socket opened by `systemfd`. Add the listenfd dependency to your app:
```ini
[dependencies]
listenfd = "0.3"
```
Then modify your server code to only invoke `bind` as a fallback:
{{< include-example example="autoreload" file="main.rs" section="autoreload" >}}
## Running the Server
To now run the development server invoke this command:
```
systemfd --no-pid -s http::3000 -- cargo watch -x run
```
[cargowatch]: https://github.com/passcod/cargo-watch
[listenfd]: https://crates.io/crates/listenfd
[systemfd]: https://github.com/mitsuhiko/systemfd

View File

@ -4,51 +4,43 @@ menu: docs_patterns
weight: 1010
---
# Async Options
We have several example projects showing use of async database adapters:
- SQLx: https://github.com/actix/examples/tree/master/sqlx_todo
- Postgres: https://github.com/actix/examples/tree/master/async_pg
- SQLite: https://github.com/actix/examples/tree/master/async_db
# Diesel
{{% alert %}}
NOTE: The `actix-web` 1.0 version of this section is still
[being updated](https://github.com/cldershem/actix-website/tree/update1.0-db). Checkout
this [example](https://github.com/actix/examples/tree/master/async_db) until then.
{{% /alert %}}
The current version of Diesel (v1) does not support asynchronous operations, so it is important to
use the [`web::block`][web-block] function to offload your database operations to the Actix runtime
thread-pool.
At the moment, Diesel 1.0 does not support asynchronous operations,
but it's possible to use the `actix` synchronous actor system as a database interface api.
You can create action functions that correspond to all the operations your app will perform on the
database.
Technically, sync actors are worker style actors. Multiple sync actors
can be run in parallel and process messages from same queue. Sync actors work in mpsc mode.
{{< include-example example="databases" file="main.rs" section="handler" >}}
Let's create a simple database api that can insert a new user row into a SQLite table.
We must define a sync actor and a connection that this actor will use. The same approach
can be used for other databases.
Now you should set up the database pool using a crate such as `r2d2`, which makes many DB
connections available to your app. This means that multiple handlers can manipulate the DB at the
same time, and still accept new connections. Simply, the pool in your app state. (In this case, it's
beneficial not to use a state wrapper struct because the pool handles shared access for you.)
{{< include-example example="og_databases" file="main.rs" section="actor" >}}
{{< include-example example="databases" file="main.rs" section="main" >}}
This is the definition of our actor. Now, we must define the *create user* message and response.
Now, in a request handler, use the `Data<T>` extractor to get the pool from app state and get a
connection from it. This provides an owned database connection that can be passed into a
[`web::block`][web-block] closure. Then just call the action function with the necessary arguments
and `.await` the result.
{{< include-example example="og_databases" file="main.rs" section="message" >}}
This example also maps the error to an `HttpResponse` before using the `?` operator but this is not
necessary if your return error type implements [`ResponseError`][response-error].
We can send a `CreateUser` message to the `DbExecutor` actor, and as a result, we will receive a
`User` model instance. Next, we must define the handler implementation for this message.
{{< include-example example="databases" file="main.rs" section="index" >}}
{{< include-example example="og_databases" file="main.rs" section="handler" >}}
That's it! See the full example here: https://github.com/actix/examples/tree/master/diesel
That's it! Now, we can use the *DbExecutor* actor from any http handler or middleware.
All we need is to start *DbExecutor* actors and store the address in a state where http handler
can access it.
{{< include-example example="og_databases" file="main.rs" section="main" >}}
We will use the address in a request handler. The handle returns a future object;
thus, we receive the message response asynchronously.
`Route::a()` must be used for async handler registration.
{{< include-example example="og_databases" file="main.rs" section="index" >}}
> A full example is available in the [examples directory][examples].
> More information on sync actors can be found in the
> [actix documentation][actixdocs].
[examples]: https://github.com/actix/examples/tree/master/diesel/
[actixdocs]: https://docs.rs/actix/0.7.0/actix/sync/index.html
[web-block]: https://docs.rs/actix-web/3/actix_web/web/fn.block.html
[response-error]: https://docs.rs/actix-web/3/actix_web/trait.ResponseError.html

View File

@ -7,12 +7,12 @@ weight: 180
# Errors
Actix-web uses its own [`actix_web::error::Error`][actixerror] type and
[`actix_web::error::ResponseError`][responseerror] trait for error handling
from web handlers.
[`actix_web::error::ResponseError`][responseerror] trait for error handling from web handlers.
If a handler returns an `Error` (referring to the [general Rust trait
`std::error::Error`][stderror]) in a `Result` that also implements the
`ResponseError` trait, actix-web will render that error as an HTTP response with it's corresponding [`actix_web::http::StatusCode`][status_code]. Internal server error is generated by default:
`std::error::Error`][stderror]) in a `Result` that also implements the `ResponseError` trait,
actix-web will render that error as an HTTP response with it's corresponding
[`actix_web::http::StatusCode`][status_code]. Internal server error is generated by default:
```rust
pub trait ResponseError {
@ -27,12 +27,11 @@ A `Responder` coerces compatible `Result`s into HTTP responses:
impl<T: Responder, E: Into<Error>> Responder for Result<T, E>
```
`Error` in the code above is actix-web's error definition, and any errors that
implement `ResponseError` can be converted to one automatically.
`Error` in the code above is actix-web's error definition, and any errors that implement
`ResponseError` can be converted to one automatically.
Actix-web provides `ResponseError` implementations for some common non-actix
errors. For example, if a handler responds with an `io::Error`, that error is
converted into an `HttpInternalServerError`:
Actix-web provides `ResponseError` implementations for some common non-actix errors. For example, if
a handler responds with an `io::Error`, that error is converted into an `HttpInternalServerError`:
```rust
use std::io;
@ -43,18 +42,18 @@ fn index(_req: HttpRequest) -> io::Result<NamedFile> {
}
```
See [the actix-web API documentation][responseerrorimpls] for a full list of foreign
implementations for `ResponseError`.
See [the actix-web API documentation][responseerrorimpls] for a full list of foreign implementations
for `ResponseError`.
## An example of a custom error response
Here's an example implementation for `ResponseError`:
Here's an example implementation for `ResponseError`, using the [derive_more] crate
for declarative error enums.
{{< include-example example="errors" file="main.rs" section="response-error" >}}
`ResponseError` has a default implementation for `error_response()` that will
render a _500_ (internal server error), and that's what will happen when the
`index` handler executes above.
`ResponseError` has a default implementation for `error_response()` that will render a _500_
(internal server error), and that's what will happen when the `index` handler executes above.
Override `error_response()` to produce more useful results:
@ -62,69 +61,56 @@ Override `error_response()` to produce more useful results:
# Error helpers
Actix-web provides a set of error helper functions that are useful for generating
specific HTTP error codes from other errors. Here we convert `MyError`, which
doesn't implement the `ResponseError` trait, to a _400_ (bad request) using
`map_err`:
Actix-web provides a set of error helper functions that are useful for generating specific HTTP
error codes from other errors. Here we convert `MyError`, which doesn't implement the
`ResponseError` trait, to a _400_ (bad request) using `map_err`:
{{< include-example example="errors" file="helpers.rs" section="helpers" >}}
See the [API documentation for actix-web's `error` module][actixerror]
for a full list of available error helpers.
# Compatibility with failure
Actix-web provides automatic compatibility with the [failure] library so that
errors deriving `fail` will be converted automatically to an actix error. Keep
in mind that those errors will render with the default _500_ status code unless you
also provide your own `error_response()` implementation for them.
See the [API documentation for actix-web's `error` module][actixerror] for a full list of available
error helpers.
# Error logging
Actix logs all errors at the `WARN` log level. If an application's log level is
set to `DEBUG` and `RUST_BACKTRACE` is enabled, the backtrace is also logged.
These are configurable with environmental variables:
Actix logs all errors at the `WARN` log level. If an application's log level is set to `DEBUG` and
`RUST_BACKTRACE` is enabled, the backtrace is also logged. These are configurable with environmental
variables:
```
>> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run
```
The `Error` type uses the cause's error backtrace if available. If the
underlying failure does not provide a backtrace, a new backtrace is constructed
pointing to the point where the conversion occurred (rather than the origin of
the error).
The `Error` type uses the cause's error backtrace if available. If the underlying failure does not
provide a backtrace, a new backtrace is constructed pointing to the point where the conversion
occurred (rather than the origin of the error).
# Recommended practices in error handling
It might be useful to think about dividing the errors an application produces
into two broad groups: those which are intended to be be user-facing, and those
which are not.
It might be useful to think about dividing the errors an application produces into two broad groups:
those which are intended to be be user-facing, and those which are not.
An example of the former is that I might use failure to specify a `UserError`
enum which encapsulates a `ValidationError` to return whenever a user sends bad
input:
An example of the former is that I might use failure to specify a `UserError` enum which
encapsulates a `ValidationError` to return whenever a user sends bad input:
{{< include-example example="errors" file="recommend_one.rs" section="recommend-one" >}}
This will behave exactly as intended because the error message defined with
`display` is written with the explicit intent to be read by a user.
This will behave exactly as intended because the error message defined with `display` is written
with the explicit intent to be read by a user.
However, sending back an error's message isn't desirable for all errors --
there are many failures that occur in a server environment where we'd probably
want the specifics to be hidden from the user. For example, if a database goes
down and client libraries start producing connect timeout errors, or if an HTML
template was improperly formatted and errors when rendered. In these cases, it
might be preferable to map the errors to a generic error suitable for user
consumption.
However, sending back an error's message isn't desirable for all errors -- there are many failures
that occur in a server environment where we'd probably want the specifics to be hidden from the
user. For example, if a database goes down and client libraries start producing connect timeout
errors, or if an HTML template was improperly formatted and errors when rendered. In these cases, it
might be preferable to map the errors to a generic error suitable for user consumption.
Here's an example that maps an internal error to a user-facing `InternalError`
with a custom message:
Here's an example that maps an internal error to a user-facing `InternalError` with a custom
message:
{{< include-example example="errors" file="recommend_two.rs" section="recommend-two" >}}
By dividing errors into those which are user facing and those which are not, we
can ensure that we don't accidentally expose users to errors thrown by
application internals which they weren't meant to see.
By dividing errors into those which are user facing and those which are not, we can ensure that we
don't accidentally expose users to errors thrown by application internals which they weren't meant
to see.
# Error Logging
@ -132,10 +118,11 @@ This is a basic example using `middleware::Logger`:
{{< include-example example="errors" file="logging.rs" section="logging" >}}
[actixerror]: https://docs.rs/actix-web/2/actix_web/error/struct.Error.html
[errorhelpers]: https://docs.rs/actix-web/2/actix_web/trait.ResponseError.html
[failure]: https://github.com/rust-lang-nursery/failure
[responseerror]: https://docs.rs/actix-web/2/actix_web/error/trait.ResponseError.html
[responseerrorimpls]: https://docs.rs/actix-web/2/actix_web/error/trait.ResponseError.html#foreign-impls
[actixerror]: https://docs.rs/actix-web/3/actix_web/error/struct.Error.html
[errorhelpers]: https://docs.rs/actix-web/3/actix_web/trait.ResponseError.html
[derive_more]: https://crates.io/crates/derive_more
[responseerror]: https://docs.rs/actix-web/3/actix_web/error/trait.ResponseError.html
[responseerrorimpls]:
https://docs.rs/actix-web/3/actix_web/error/trait.ResponseError.html#foreign-impls
[stderror]: https://doc.rust-lang.org/std/error/trait.Error.html
[status_code]: https://docs.rs/actix-web/2.0.0/actix_web/http/struct.StatusCode.html
[status_code]: https://docs.rs/actix-web/3.0.0/actix_web/http/struct.StatusCode.html

View File

@ -19,8 +19,8 @@ up to 10 extractors per handler function. Argument position does not matter.
[*Path*][pathstruct] provides information that can be extracted from the Request's
path. You can deserialize any variable segment from the path.
For instance, for resource that registered for the `/users/{userid}/{friend}` path,
two segments could be deserialized, `userid` and `friend`. These segments could be
For instance, for resource that registered for the `/users/{user_id}/{friend}` path,
two segments could be deserialized, `user_id` and `friend`. These segments could be
extracted into a `tuple`, i.e. `Path<(u32, String)>` or any structure that implements
the `Deserialize` trait from the *serde* crate.
@ -109,13 +109,13 @@ number of requests processed per thread. A proper implementation would use `Arc`
> request handling processes would block. If you need to share or update some state
> from multiple threads, consider using the tokio synchronization primitives.
[pathstruct]: https://docs.rs/actix-web/2/actix_web/dev/struct.Path.html
[querystruct]: https://docs.rs/actix-web/2/actix_web/web/struct.Query.html
[jsonstruct]: https://docs.rs/actix-web/2/actix_web/web/struct.Json.html
[jsonconfig]: https://docs.rs/actix-web/2/actix_web/web/struct.JsonConfig.html
[formconfig]: https://docs.rs/actix-web/2/actix_web/web/struct.FormConfig.html
[datastruct]: https://docs.rs/actix-web/2/actix_web/web/struct.Data.html
[stringexample]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html#example-2
[bytesexample]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html#example-4
[payloadexample]: https://docs.rs/actix-web/2/actix_web/web/struct.Payload.html
[pathstruct]: https://docs.rs/actix-web/3/actix_web/dev/struct.Path.html
[querystruct]: https://docs.rs/actix-web/3/actix_web/web/struct.Query.html
[jsonstruct]: https://docs.rs/actix-web/3/actix_web/web/struct.Json.html
[jsonconfig]: https://docs.rs/actix-web/3/actix_web/web/struct.JsonConfig.html
[formconfig]: https://docs.rs/actix-web/3/actix_web/web/struct.FormConfig.html
[datastruct]: https://docs.rs/actix-web/3/actix_web/web/struct.Data.html
[stringexample]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html#example-2
[bytesexample]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html#example-4
[payloadexample]: https://docs.rs/actix-web/3/actix_web/web/struct.Payload.html
[actix]: https://actix.github.io/actix/actix/

View File

@ -4,9 +4,14 @@ menu: docs_basics
weight: 130
---
# Getting Started
## Installing Rust
Lets write our first `actix-web` application!
If you don't have Rust yet, we recommend you use `rustup` to manage your Rust installation. The
[official rust guide][rustguide] has a wonderful section on getting started.
Actix Web currently has a minimum supported Rust version (MSRV) of {{< rust-version "actix-web" >}}.
Running `rustup update` will ensure you have the latest and greatest Rust version available. As
such, this guide assumes you are running Rust {{< rust-version "actix-web" >}} or later.
## Hello, world!
@ -17,71 +22,35 @@ cargo new hello-world
cd hello-world
```
Now, add `actix-web` as a dependency of your project by ensuring your `Cargo.toml`
contains the following:
Add `actix-web` as a dependency of your project by adding the following to your `Cargo.toml` file.
```ini
```toml
[dependencies]
actix-web = "{{< actix-version "actix-web" >}}"
```
If you want to use the `#[actix_rt::main]` macro, you have to add `actix-rt` to your dependency.
Now your `Cargo.toml` should look like following:
Request handlers use an async functions that accept zero or more parameters. These parameters can be
extracted from a request (see `FromRequest` trait) and returns a type that can be converted into an
`HttpResponse` (see `Responder` trait):
```ini
[dependencies]
actix-web = "{{< actix-version "actix-web" >}}"
actix-rt = "{{< actix-version "actix-rt" >}}"
```
{{< include-example example="getting-started" section="handlers" >}}
In order to implement a web server, we first need to create a request handler.
Notice that some of these handlers have routing information attached directly using the built-in
macros. These allow you to specify the method and path that the handler should respond to. You will
see below how to register the other route that does not use a routing macro.
A request handler is an async function that accepts zero or more parameters that can be
extracted from a request (ie, `impl FromRequest`) and returns a type that can be
converted into an `HttpResponse` (ie, `impl Responder`):
{{< include-example example="getting-started" section="setup" >}}
Next, create an `App` instance and register the request handler with the application's
`route` on a _path_ and with a particular _HTTP method_. After that, the application
instance can be used with `HttpServer` to listen for incoming connections. The server
accepts a function that should return an application factory.
Next, create an `App` instance and register the request handlers. Use `App::service` for the
handlers using routing macros and `App::route` for manually routed handlers, declaring the a path
and method. Finally, the app is started inside an `HttpServer` which will serve incoming requests
using your `App` as an "application factory".
{{< include-example example="getting-started" section="main" >}}
That's it! Now, compile and run the program with `cargo run`.
Head over to `http://localhost:8088/` to see the results.
That's it! Compile and run the program with `cargo run`. The `#[actix_web::main]` macro executes the
async main function within the actix runtime. Now you can go to `http://localhost:8080/` or any of
the other routes you defined to see the results.
**Note**: You may have noticed the `#[actix_rt::main]` attribute macro. This
macro executes the associated async function within the actix runtime.
Any async function could be marked and executed by this macro.
### Using Attribute Macros to Define Routes
Alternatively, you can define routes using macro attributes which
allow you to specify the routes above your functions like so:
{{< include-example example="getting-started" section="macro-attributes">}}
You can then register the route using `service()`:
```rust
App::new()
.service(index3)
```
For consistency reasons, this documentation only uses the explicit syntax shown at the
beginning of this page. However, if you prefer this syntax you should feel free to
use it any time you declare a route as it's only syntactic sugar.
To learn more, see [actix-web-codegen].
### Auto-reloading
If you want, you can have an automatically reloading server during development
that recompiles on demand. This isn't necessary, but it makes rapid prototyping
more convenient as you can see changes instantly upon saving.
To see how this can be accomplished, have a look at the [autoreload pattern][autoload].
<!-- LINKS -->
[rustguide]: https://doc.rust-lang.org/book/ch01-01-installation.html
[actix-web-codegen]: https://docs.rs/actix-web-codegen/
[autoload]: ../autoreload/

View File

@ -68,12 +68,12 @@ the stream trait `Stream<Item=Bytes, Error=Error>`, i.e:
Sometimes, you need to return different types of responses. For example, you can error
check and return errors, return async responses, or any result that requires two different types.
For this case, the [*Either*][either] type can be used. `Either` allows combining two
For this case, the [Either][either] type can be used. `Either` allows combining two
different responder types into a single type.
{{< include-example example="either" file="main.rs" section="either" >}}
[implfromrequest]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html
[respondertrait]: https://docs.rs/actix-web/2/actix_web/trait.Responder.html
[responderimpls]: https://docs.rs/actix-web/2/actix_web/trait.Responder.html#foreign-impls
[either]: https://docs.rs/actix-web/2/actix_web/enum.Either.html
[implfromrequest]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html
[respondertrait]: https://docs.rs/actix-web/3/actix_web/trait.Responder.html
[responderimpls]: https://docs.rs/actix-web/3/actix_web/trait.Responder.html#foreign-impls
[either]: https://docs.rs/actix-web/3/actix_web/enum.Either.html

View File

@ -1,15 +1,16 @@
---
title: HTTP/2.0
menu: docs_proto
title: HTTP/2
menu: docs_protocols
weight: 250
---
`actix-web` automatically upgrades connections to *HTTP/2.0* if possible.
`actix-web` automatically upgrades connections to *HTTP/2* if possible.
# Negotiation
*HTTP/2.0* protocol over tls without prior knowledge requires [tls alpn][tlsalpn].
*HTTP/2* protocol over TLS without prior knowledge requires [TLS ALPN][tlsalpn].
<!-- TODO: use rustls example -->
> Currently, only `rust-openssl` has support.
`alpn` negotiation requires enabling the feature. When enabled, `HttpServer` provides the
@ -18,7 +19,6 @@ weight: 250
```toml
[dependencies]
actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["openssl"] }
actix-rt = "1.0.0"
openssl = { version = "0.10", features = ["v110"] }
```
{{< include-example example="http2" file="main.rs" section="main" >}}
@ -31,6 +31,6 @@ connection and tls connection. [rfc section 3.4][rfcsection34].
[rfcsection32]: https://http2.github.io/http2-spec/#rfc.section.3.2
[rfcsection34]: https://http2.github.io/http2-spec/#rfc.section.3.4
[bindopenssl]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.bind_openssl
[bindopenssl]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.bind_openssl
[tlsalpn]: https://tools.ietf.org/html/rfc7301
[examples]: https://github.com/actix/examples/tree/master/rustls

View File

@ -1,20 +1,21 @@
---
title: Http Server Initialization
title: HTTP Server Initialization
menu: docs_architecture
weight: 1020
---
## Architecture overview
Below is a diagram of HttpServer initalization, which happens on the following code
Below is a diagram of HttpServer initialization, which happens on the following code
```rust
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::to(|| HttpResponse::Ok()))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,52 +0,0 @@
---
title: Installation
menu: docs_intro
weight: 110
---
# Installing Rust
Since `actix-web` is a Rust framework you will need Rust to get started with it. If you
don't have it yet we recommend you use `rustup` to manage your Rust installation. The
[official rust guide][rustguide] has a wonderful section on getting started.
We currently require at least Rust {{< rust-version "actix-web" >}} so make sure you run
`rustup update` to have the latest and greatest Rust version available. In particular
this guide will assume that you actually run Rust {{< rust-version "actix-web" >}} or later.
# Installing `actix-web`
Thanks to Rust's `cargo` package manager you won't need to explicitly install
`actix-web`. Just depend on it and you're ready to go. For the unlikely
case that you want to use the development version of `actix-web` you can
depend on the git repository directly.
Release version:
```ini
[dependencies]
actix-web = "{{< actix-version "actix-web" >}}"
```
Development version:
```ini
[dependencies]
actix-web = { git = "https://github.com/actix/actix-web" }
```
# Diving In
There are two paths you can take here. You can follow the guide along or if you are very
impatient you might want to have a look at our [extensive example repository][examples]
and run the included examples. Here for instance is how you run the included `basics`
example:
```
git clone https://github.com/actix/examples
cd examples/basics
cargo run
```
[rustguide]: https://doc.rust-lang.org/book/ch01-01-installation.html
[examples]: https://github.com/actix/examples

View File

@ -1,5 +1,5 @@
---
title: Middlewares
title: Middleware
menu: docs_advanced
weight: 220
---
@ -29,11 +29,11 @@ The following demonstrates creating a simple middleware:
{{< include-example example="middleware" file="main.rs" section="simple" >}}
Alternatively, for simple use cases, you can use [*wrap_fn*][wrap_fn] to create small, ad-hoc middlewares:
Alternatively, for simple use cases, you can use [*wrap_fn*][wrap_fn] to create small, ad-hoc middleware:
{{< include-example example="middleware" file="wrap_fn.rs" section="wrap-fn" >}}
> Actix-web provides several useful middlewares, such as *logging*, *user sessions*,
> Actix-web provides several useful middleware, such as *logging*, *user sessions*,
> *compress*, etc.
# Logging
@ -89,8 +89,7 @@ a specified header.
## User sessions
Actix-web provides a general solution for session management. The
[**actix-session**][actixsession] middleware can be used with different backend types
to store session data in different backends.
[**actix-session**][actixsession] middleware can use multiple backend types to store session data.
> By default, only cookie session backend is implemented. Other backend implementations
> can be added.
@ -132,6 +131,6 @@ into a response.
[cookiesession]: https://docs.rs/actix-session/0.3.0/actix_session/struct.CookieSession.html
[actixsession]: https://docs.rs/actix-session/0.3.0/actix_session/
[envlogger]: https://docs.rs/env_logger/*/env_logger/
[servicetrait]: https://docs.rs/actix-web/2/actix_web/dev/trait.Service.html
[transformtrait]: https://docs.rs/actix-web/2/actix_web/dev/trait.Transform.html
[wrap_fn]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.wrap_fn
[servicetrait]: https://docs.rs/actix-web/3/actix_web/dev/trait.Service.html
[transformtrait]: https://docs.rs/actix-web/3/actix_web/dev/trait.Transform.html
[wrap_fn]: https://docs.rs/actix-web/3/actix_web/struct.App.html#method.wrap_fn

View File

@ -81,7 +81,7 @@ In the following example, we read and print the request payload chunk by chunk:
[multipartstruct]: https://docs.rs/actix-multipart/0.2/actix_multipart/struct.Multipart.html
[fieldstruct]: https://docs.rs/actix-multipart/0.2/actix_multipart/struct.Field.html
[multipartexample]: https://github.com/actix/examples/tree/master/multipart/
[urlencoded]: https://docs.rs/actix-web/2/actix_web/dev/struct.UrlEncoded.html
[payloadextractor]: https://docs.rs/actix-web/2/actix_web/web/struct.Payload.html
[urlencoded]: https://docs.rs/actix-web/3/actix_web/dev/struct.UrlEncoded.html
[payloadextractor]: https://docs.rs/actix-web/3/actix_web/web/struct.Payload.html
[multipartcrate]: https://crates.io/crates/actix-multipart
[formencoded]:Jhttps://docs.rs/actix-web/2/actix_web/web/struct.Form.html
[formencoded]:Jhttps://docs.rs/actix-web/3/actix_web/web/struct.Form.html

View File

@ -71,5 +71,5 @@ The type `T` must implement the `Serialize` trait from *serde*.
{{< include-example example="responses" file="json_resp.rs" section="json-resp" >}}
[responsebuilder]: https://docs.rs/actix-web/2/actix_web/dev/struct.HttpResponseBuilder.html
[compressmidddleware]: https://docs.rs/actix-web/2/actix_web/middleware/struct.Compress.html
[responsebuilder]: https://docs.rs/actix-web/3/actix_web/dev/struct.HttpResponseBuilder.html
[compressmidddleware]: https://docs.rs/actix-web/3/actix_web/middleware/struct.Compress.html

View File

@ -6,32 +6,32 @@ weight: 150
# The HTTP Server
The [**HttpServer**][httpserverstruct] type is responsible for serving http requests.
The [**HttpServer**][httpserverstruct] type is responsible for serving HTTP requests.
`HttpServer` accepts an application factory as a parameter, and the application factory
must have `Send` + `Sync` boundaries. More about that in the *multi-threading* section.
To bind to a specific socket address, [`bind()`][bindmethod] must be used, and it may be
called multiple times. To bind ssl socket, [`bind_openssl()`][bindopensslmethod] or
[`bind_rustls()`][bindrusttls] should be used. To run the http server, use the `HttpServer::run()`
[`bind_rustls()`][bindrusttls] should be used. To run the HTTP server, use the `HttpServer::run()`
method.
{{< include-example example="server" section="main" >}}
The `run()` method returns an instance of the [`Server`][server] type. Methods of server type
could be used for managing the http server
could be used for managing the HTTP server
- `pause()` - Pause accepting incoming connections
- `resume()` - Resume accepting incoming connections
- `stop()` - Stop incoming connection processing, stop all workers and exit
The following example shows how to start the http server in a separate thread.
The following example shows how to start the HTTP server in a separate thread.
{{< include-example example="server" file="signals.rs" section="signals" >}}
## Multi-threading
`HttpServer` automatically starts a number of http *workers*, by default this number is
`HttpServer` automatically starts a number of HTTP *workers*, by default this number is
equal to the number of logical CPUs in the system. This number can be overridden with the
[`HttpServer::workers()`][workers] method.
@ -120,7 +120,7 @@ Actix can wait for requests on a keep-alive connection.
If the first option above is selected, then *keep alive* state is calculated based on the
response's *connection-type*. By default `HttpResponse::connection_type` is not
defined. In that case *keep alive* is defined by the request's http version.
defined. In that case *keep alive* is defined by the request's HTTP version.
> *keep alive* is **off** for *HTTP/1.0* and is **on** for *HTTP/1.1* and *HTTP/2.0*.
@ -149,14 +149,14 @@ are available on unix systems.
> It is possible to disable signal handling with
[`HttpServer::disable_signals()`][disablesignals] method.
[server]: https://docs.rs/actix-web/2/actix_web/dev/struct.Server.html
[httpserverstruct]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html
[bindmethod]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.bind
[bindopensslmethod]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.bind_openssl
[bindrusttls]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.bind_rustls
[startmethod]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.start
[workers]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.workers
[server]: https://docs.rs/actix-web/3/actix_web/dev/struct.Server.html
[httpserverstruct]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html
[bindmethod]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.bind
[bindopensslmethod]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.bind_openssl
[bindrusttls]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.bind_rustls
[startmethod]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.start
[workers]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.workers
[tlsalpn]: https://tools.ietf.org/html/rfc7301
[exampleopenssl]: https://github.com/actix/examples/blob/master/openssl
[shutdowntimeout]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.shutdown_timeout
[disablesignals]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.disable_signals
[shutdowntimeout]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.shutdown_timeout
[disablesignals]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.disable_signals

View File

@ -20,7 +20,7 @@ For unit testing, actix-web provides a request builder type.
# Integration tests
There are a few methods for testing your application. Actix-web can be used
to run the application with specific handlers in a real http server.
to run the application with specific handlers in a real HTTP server.
`TestRequest::get()`, `TestRequest::post()` and other
methods can be used to send requests to the test server.
@ -28,7 +28,7 @@ methods can be used to send requests to the test server.
To create a `Service` for testing, use the `test::init_service` method which accepts a
regular `App` builder.
> Check the [api documentation][actixdocs] for more information.
> Check the [API documentation][actixdocs] for more information.
{{< include-example example="testing" file="integration_one.rs" section="integration-one" >}}
@ -47,6 +47,6 @@ resulting [*ResponseBody*][responsebody] into a future and execute it, for examp
{{< include-example example="testing" file="stream_response.rs" section="stream-response" >}}
[serversentevents]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
[responsebody]: https://docs.rs/actix-web/2/actix_web/body/enum.ResponseBody.html
[actixdocs]: https://docs.rs/actix-web/2/actix_web/test/index.html
[testrequest]: https://docs.rs/actix-web/2/actix_web/test/struct.TestRequest.html
[responsebody]: https://docs.rs/actix-web/3/actix_web/body/enum.ResponseBody.html
[actixdocs]: https://docs.rs/actix-web/3/actix_web/test/index.html
[testrequest]: https://docs.rs/actix-web/3/actix_web/test/struct.TestRequest.html

View File

@ -27,7 +27,7 @@ in *http://localhost:8080/foo/bar?q=value*).
The [*App::route()*][approute] method provides simple way of registering routes. This
method adds a single route to application routing table. This method accepts a *path pattern*,
*http method* and a handler function. `route()` method could be called multiple times
*HTTP method* and a handler function. `route()` method could be called multiple times
for the same path, in that case, multiple routes register for the same resource path.
{{< include-example example="url-dispatch" section="main" >}}
@ -40,7 +40,7 @@ adds a single [resource][webresource] to application routing table. This method
{{< include-example example="url-dispatch" file="resource.rs" section="resource" >}}
If a resource does not contain any route or does not have any matching routes, it
returns *NOT FOUND* http response.
returns *NOT FOUND* HTTP response.
## Configuring a Route
@ -197,7 +197,7 @@ When matching the following URL:
http://example.com/foo/La%20Pe%C3%B1a
```
The matchdict will look like so (the value is URL-decoded):
The match dictionary will look like so (the value is URL-decoded):
```
Params{'bar': 'La Pe\xf1a'}
@ -247,7 +247,7 @@ A scoped layout of these paths would appear as follows
{{< include-example example="url-dispatch" file="scope.rs" section="scope" >}}
A *scoped* path can contain variable path segments as resources. Consistent with
unscoped paths.
un-scoped paths.
You can get variable path segments from `HttpRequest::match_info()`.
[`Path` extractor][pathextractor] also is able to extract scope level variable segments.
@ -283,7 +283,7 @@ safe to interpolate within, or use as a suffix of, a path without additional che
Actix provides functionality for type safe path information extraction. [*Path*][pathstruct]
extracts information, destination type could be defined in several different forms. Simplest
approach is to use `tuple` type. Each element in tuple must correpond to one element from
approach is to use `tuple` type. Each element in tuple must correspond to one element from
path pattern. i.e. you can match path pattern `/{id}/{username}/` against
`Path<(u32, String)>` type, but `Path<(String, String, String)>` type will always fail.
@ -363,7 +363,7 @@ it will generate a URL with that same path.
You can think of a guard as a simple function that accepts a *request* object reference
and returns *true* or *false*. Formally, a guard is any object that implements the
[`Guard`][guardtrait] trait. Actix provides several predicates, you can check
[functions section][guardfuncs] of api docs.
[functions section][guardfuncs] of API docs.
Here is a simple guard that check that a request contains a specific *header*:
@ -407,24 +407,24 @@ with `App::service()` method.
{{< include-example example="url-dispatch" file="dhandler.rs" section="default" >}}
[handlersection]: ../handlers/
[approute]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.route
[appservice]: https://docs.rs/actix-web/2/actix_web/struct.App.html?search=#method.service
[webresource]: https://docs.rs/actix-web/2/actix_web/struct.Resource.html
[resourcehandler]: https://docs.rs/actix-web/2/actix_web/struct.Resource.html#method.route
[route]: https://docs.rs/actix-web/2/actix_web/struct.Route.html
[routeguard]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.guard
[routemethod]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.method
[routeto]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.to
[routetoasync]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.to_async
[matchinfo]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.match_info
[pathget]: https://docs.rs/actix-web/2/actix_web/dev/struct.Path.html#method.get
[pathstruct]: https://docs.rs/actix-web/2/actix_web/dev/struct.Path.html
[query]: https://docs.rs/actix-web/2/actix_web/web/struct.Query.html
[urlfor]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.url_for
[approute]: https://docs.rs/actix-web/3/actix_web/struct.App.html#method.route
[appservice]: https://docs.rs/actix-web/3/actix_web/struct.App.html?search=#method.service
[webresource]: https://docs.rs/actix-web/3/actix_web/struct.Resource.html
[resourcehandler]: https://docs.rs/actix-web/3/actix_web/struct.Resource.html#method.route
[route]: https://docs.rs/actix-web/3/actix_web/struct.Route.html
[routeguard]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.guard
[routemethod]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.method
[routeto]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.to
[routetoasync]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.to_async
[matchinfo]: https://docs.rs/actix-web/3/actix_web/struct.HttpRequest.html#method.match_info
[pathget]: https://docs.rs/actix-web/3/actix_web/dev/struct.Path.html#method.get
[pathstruct]: https://docs.rs/actix-web/3/actix_web/dev/struct.Path.html
[query]: https://docs.rs/actix-web/3/actix_web/web/struct.Query.html
[urlfor]: https://docs.rs/actix-web/3/actix_web/struct.HttpRequest.html#method.url_for
[urlobj]: https://docs.rs/url/1.7.2/url/struct.Url.html
[guardtrait]: https://docs.rs/actix-web/2/actix_web/guard/trait.Guard.html
[guardfuncs]: https://docs.rs/actix-web/2/actix_web/guard/index.html#functions
[requestextensions]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.extensions
[implfromrequest]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html
[implresponder]: https://docs.rs/actix-web/2/actix_web/trait.Responder.html
[guardtrait]: https://docs.rs/actix-web/3/actix_web/guard/trait.Guard.html
[guardfuncs]: https://docs.rs/actix-web/3/actix_web/guard/index.html#functions
[requestextensions]: https://docs.rs/actix-web/3/actix_web/struct.HttpRequest.html#method.extensions
[implfromrequest]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html
[implresponder]: https://docs.rs/actix-web/3/actix_web/trait.Responder.html
[pathextractor]: ../extractors

View File

@ -1,6 +1,6 @@
---
title: Websockets
menu: docs_proto
menu: docs_protocols
weight: 240
---
@ -15,10 +15,10 @@ The following is an example of a simple websocket echo server:
> A simple websocket echo server example is available in the [examples directory][examples].
> An example chat server with the ability to chat over a websocket or tcp connection
> An example chat server with the ability to chat over a websocket or TCP connection
> is available in [websocket-chat directory][chat]
[message]: https://docs.rs/actix-web-actors/2/actix_web_actors/ws/enum.Message.html
[payload]: https://docs.rs/actix-web/2/actix_web/web/struct.Payload.html
[payload]: https://docs.rs/actix-web/3/actix_web/web/struct.Payload.html
[examples]: https://github.com/actix/examples/tree/master/websocket/
[chat]: https://github.com/actix/examples/tree/master/websocket-chat/

View File

@ -4,24 +4,29 @@ menu: docs_intro
weight: 100
---
# Actix is Multiple Things
# Actix is an ecosystem of crates
Actix is a few things. The base of it is a powerful actor system for Rust on
top of which the `actix-web` system was originally built. This is what you are most
likely going to work with. What `actix-web` gives you is a fun and very fast web
development framework.
Actix is a few things. The base of it is a powerful actor system for Rust on top of which the
`actix-web` system was originally built. This is what you are most likely going to work with. What
`actix-web` gives you is a powerful and very fast web development framework.
We call `actix-web` a small and pragmatic framework. For all intents and purposes
it's a microframework with a few twists. If you are already a Rust programmer
you will probably find yourself at home quickly, but even if you are coming from
another programming language you should find `actix-web` easy to pick up.
We call `actix-web` a small and pragmatic framework. For all intents and purposes it's a
micro-framework with a few twists. If you are already a Rust programmer you will probably find
yourself at home quickly, but even if you are coming from another programming language you should
find `actix-web` easy to pick up.
An application developed with `actix-web` will expose an HTTP server contained
within a native executable. You can either put this behind another HTTP server like
nginx or serve it up as-is. Even in the complete absence of another HTTP
server `actix-web` is powerful enough to provide HTTP 1 and HTTP 2 support as
well as SSL/TLS. This makes it useful for building small services ready for
An application developed with `actix-web` will expose an HTTP server contained within a native
executable. You can either put this behind another HTTP server like nginx or serve it up as-is. Even
in the complete absence of another HTTP server `actix-web` is powerful enough to provide HTTP/1 and
HTTP/2 support as well as TLS (HTTPS). This makes it useful for building small services ready for
distribution.
Most importantly: `actix-web` runs on Rust {{< rust-version "actix-web" >}} or later
and it works with stable releases.
Most importantly: `actix-web` runs on Rust {{< rust-version "actix-web" >}} or later and it works
with stable releases.
<!-- TODO -->
<!-- which is built upon the fantastic [Tokio][tokio] asynchronous I/O system -->
<!-- LINKS -->
[tokio]: https://tokio.rs

View File

@ -1,30 +1,26 @@
[workspace]
members = [
"application",
"async-handlers",
"easy-form-handling",
"either",
"errors",
"extractors",
"flexible-responders",
"getting-started",
"main-example",
"powerful-extractors",
"request-routing",
"server",
"url-dispatch",
"responder-trait",
"either",
"extractors",
"autoreload",
"errors",
"requests",
"responses",
"middleware",
"static-files",
"http2",
"testing",
"async-handlers",
"websockets",
"main-example",
"middleware",
"powerful-extractors",
"request-handlers",
"request-routing",
"requests",
"responder-trait",
"responses",
"server",
"static-files",
"testing",
"url-dispatch",
"websockets",
]
exclude = [
"og_databases",
"sentry",
]
exclude = ["databases", "sentry"]

View File

@ -5,6 +5,5 @@ edition = "2018"
workspace = "../"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-service = "1.0"
actix-web = "3"
actix-service = "1"

View File

@ -1,18 +1,23 @@
#![allow(dead_code)]
// <setup>
use actix_web::{web, App, Responder, HttpServer};
use actix_web::{web, App, HttpServer, Responder};
async fn index() -> impl Responder {
"Hello world!"
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new().service(
web::scope("/app").route("/index.html", web::get().to(index)),
// prefixes all resources and routes attached to it...
web::scope("/app")
// ...so this handles requests for `GET /app/index.html`
.route("/index.html", web::get().to(index)),
)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,24 +1,27 @@
#![allow(dead_code)]
use actix_web::{web, App, HttpResponse, HttpServer};
// <combine>
struct State1;
struct State2;
#[rustfmt::skip]
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(
web::scope("/app1")
.data(State1)
.route("/", web::to(|| HttpResponse::Ok())))
.route("/", web::to(|| HttpResponse::Ok())),
)
.service(
web::scope("/app2")
.data(State2)
.route("/", web::to(|| HttpResponse::Ok())))
.route("/", web::to(|| HttpResponse::Ok())),
)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,3 +1,5 @@
#![allow(dead_code)]
// <config>
use actix_web::{web, App, HttpResponse, HttpServer};
@ -19,7 +21,7 @@ fn config(cfg: &mut web::ServiceConfig) {
);
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
@ -27,7 +29,7 @@ async fn main() -> std::io::Result<()> {
.service(web::scope("/api").configure(scoped_config))
.route("/", web::get().to(|| HttpResponse::Ok().body("/")))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -8,7 +8,7 @@ pub mod state;
pub mod vh;
// <multi>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
@ -20,7 +20,7 @@ async fn main() -> std::io::Result<()> {
)
.route("/", web::to(|| HttpResponse::Ok()))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -15,7 +15,7 @@ async fn index(data: web::Data<AppStateWithCounter>) -> String {
// </setup_mutable>
// <make_app_mutable>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let counter = web::Data::new(AppStateWithCounter {
counter: Mutex::new(0),
@ -28,7 +28,7 @@ async fn main() -> std::io::Result<()> {
.app_data(counter.clone()) // <- register the created data
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,16 +1,14 @@
use actix_web::{web, App, HttpRequest, Responder};
use actix_web::{get, web, App, HttpRequest, Responder};
#[get("/show")]
async fn show_users(_req: HttpRequest) -> impl Responder {
"unimplemented!"
}
#[rustfmt::skip]
// <scope>
#[actix_rt::main]
#[actix_web::main]
async fn main() {
App::new()
.service(
web::scope("/users")
.route("/show", web::get().to(show_users)));
let scope = web::scope("/users").service(show_users);
App::new().service(scope);
}
// </scope>

View File

@ -1,12 +1,12 @@
// <setup>
use actix_web::{web, App, HttpServer};
use std::sync::Mutex;
use actix_web::{get, web, App, HttpServer};
// This struct represents state
struct AppState {
app_name: String,
}
#[get("/")]
async fn index(data: web::Data<AppState>) -> String {
let app_name = &data.app_name; // <- get app_name
@ -15,16 +15,16 @@ async fn index(data: web::Data<AppState>) -> String {
// </setup>
// <start_app>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.data(AppState {
app_name: String::from("Actix-web"),
})
.route("/", web::get().to(index))
.service(index)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,7 +1,7 @@
use actix_web::{guard, web, App, HttpResponse, HttpServer};
// <vh>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
@ -17,7 +17,7 @@ async fn main() -> std::io::Result<()> {
)
.route("/", web::to(|| HttpResponse::Ok()))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,7 +4,6 @@ version = "2.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
futures = "0.3.1"
bytes = "0.5"

View File

@ -1,10 +1,11 @@
// <stream>
use actix_web::{web, App, HttpServer, Error, HttpResponse};
use actix_web::{get, App, Error, HttpResponse, HttpServer};
use bytes::Bytes;
use futures::stream::once;
use futures::future::ok;
use futures::stream::once;
async fn index() -> HttpResponse {
#[get("/stream")]
async fn stream() -> HttpResponse {
let body = once(ok::<_, Error>(Bytes::from_static(b"test")));
HttpResponse::Ok()
@ -12,10 +13,10 @@ async fn index() -> HttpResponse {
.streaming(body)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/async", web::to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(stream))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,9 +0,0 @@
[package]
name = "autoreload"
version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
listenfd = "0.3"

View File

@ -1,22 +0,0 @@
// <autoreload>
use actix_web::{web, App, HttpRequest, HttpServer, Responder};
use listenfd::ListenFd;
async fn index(_req: HttpRequest) -> impl Responder {
"Hello World!"
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
let mut listenfd = ListenFd::from_env();
let mut server = HttpServer::new(|| App::new().route("/", web::get().to(index)));
server = if let Some(l) = listenfd.take_tcp_listener(0).unwrap() {
server.listen(l)?
} else {
server.bind("127.0.0.1:3000")?
};
server.run().await
}
// </autoreload>

View File

@ -0,0 +1,7 @@
[package]
name = "databases"
version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "3"

View File

@ -0,0 +1,63 @@
// <handler>
fn insert_new_user(db: &SqliteConnection, user: CreateUser) -> Result<User, Error> {
use self::schema::users::dsl::*;
// Create insertion model
let uuid = format!("{}", uuid::Uuid::new_v4());
let new_user = models::NewUser {
id: &uuid,
name: &user.name,
};
// normal diesel operations
diesel::insert_into(users)
.values(&new_user)
.execute(&self.0)
.expect("Error inserting person");
let mut items = users
.filter(id.eq(&uuid))
.load::<models::User>(&self.0)
.expect("Error loading person");
Ok(items.pop().unwrap())
}
// </handler>
// <main>
type DbPool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
#[actix_web::main]
async fn main() -> io::Result<()> {
// Create connection pool
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
// Start HTTP server
HttpServer::new(move || {
App::new::data(pool.clone())
.resource("/{name}", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
// </main>
// <index>
async fn index(req: web::Data<DbPool>, name: web::Path<(String)>) -> impl Responder {
let name = name.into_inner();
let conn = pool.get().expect("couldn't get db connection from pool");
let user = web::block(move || actions::insert_new_user(&conn, &user))
.await
.map_err(|e| {
eprintln!("{}", e);
HttpResponse::InternalServerError().finish()
})?;
Ok(HttpResponse::Ok().json(user))
}
// </index>

View File

@ -4,6 +4,5 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
serde = "1.0"

View File

@ -18,14 +18,14 @@ async fn register(form: web::Form<Register>) -> impl Responder {
format!("Hello {} from {}!", form.username, form.country)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
.route("/register", web::post().to(register))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,5 +4,4 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "1.0"
futures = "0.1"
actix-web = "3"

View File

@ -3,7 +3,7 @@ use actix_web::{Either, Error, HttpResponse};
type RegisterResult = Either<HttpResponse, Result<&'static str, Error>>;
fn index() -> RegisterResult {
async fn index() -> RegisterResult {
if is_a_variant() {
// <- choose variant A
Either::A(HttpResponse::BadRequest().body("Bad data"))
@ -14,14 +14,14 @@ fn index() -> RegisterResult {
}
// </either>
fn main() {
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind("127.0.0.1:8088")
.unwrap()
.bind("127.0.0.1:8080")?
.run()
.unwrap();
.await
}
fn is_a_variant() -> bool {

View File

@ -4,9 +4,8 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0.0"
actix-rt = "1.0.0"
env_logger = "0.7.1"
log = "0.4.8"
failure = "0.1.6"
actix-http = "1.0.1"
actix-web = "3"
derive_more = "0.99"
env_logger = "0.7"
log = "0.4"
# actix-http = "1"

View File

@ -1,12 +1,12 @@
use actix_web::{web, App};
// <helpers>
use actix_web::{error, Result};
use actix_web::{error, get, App, HttpServer, Result};
#[derive(Debug)]
struct MyError {
name: &'static str,
}
#[get("/")]
async fn index() -> Result<&'static str> {
let result: Result<&'static str, MyError> = Err(MyError { name: "test error" });
@ -14,12 +14,10 @@ async fn index() -> Result<&'static str> {
}
// </helpers>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::HttpServer;
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,10 +1,10 @@
// <logging>
use actix_web::{error, Result};
use failure::Fail;
use actix_web::{error, get, middleware::Logger, App, HttpServer, Result};
use log::debug;
use derive_more::{Display, Error};
#[derive(Fail, Debug)]
#[fail(display = "my error")]
#[derive(Debug, Display, Error)]
#[display(fmt = "my error: {}", name)]
pub struct MyError {
name: &'static str,
}
@ -12,27 +12,22 @@ pub struct MyError {
// Use default implementation for `error_response()` method
impl error::ResponseError for MyError {}
#[get("/")]
async fn index() -> Result<&'static str, MyError> {
let err = MyError { name: "test error" };
debug!("{}", err);
Err(err)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{middleware::Logger, web, App, HttpServer};
std::env::set_var("RUST_LOG", "my_errors=debug,actix_web=info");
std::env::set_var("RUST_BACKTRACE", "1");
env_logger::init();
HttpServer::new(|| {
App::new()
.wrap(Logger::default())
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8088")?
.run()
.await
HttpServer::new(|| App::new().wrap(Logger::default()).service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}
// </logging>

View File

@ -6,10 +6,10 @@ pub mod recommend_two;
// <response-error>
use actix_web::{error, Result};
use failure::Fail;
use derive_more::{Display, Error};
#[derive(Fail, Debug)]
#[fail(display = "my error")]
#[derive(Debug, Display, Error)]
#[display(fmt = "my error: {}", name)]
struct MyError {
name: &'static str,
}
@ -22,12 +22,12 @@ async fn index() -> Result<&'static str, MyError> {
}
// </response-error>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,22 +1,24 @@
use actix_web::{web, App};
// <override>
use actix_http::ResponseBuilder;
use actix_web::{error, http::header, http::StatusCode, HttpResponse};
use failure::Fail;
use actix_web::{
dev::HttpResponseBuilder, error, get, http::header, http::StatusCode, App, HttpResponse,
};
use derive_more::{Display, Error};
#[derive(Fail, Debug)]
#[derive(Debug, Display, Error)]
enum MyError {
#[fail(display = "internal error")]
#[display(fmt = "internal error")]
InternalError,
#[fail(display = "bad request")]
#[display(fmt = "bad request")]
BadClientData,
#[fail(display = "timeout")]
#[display(fmt = "timeout")]
Timeout,
}
impl error::ResponseError for MyError {
fn error_response(&self) -> HttpResponse {
ResponseBuilder::new(self.status_code())
HttpResponseBuilder::new(self.status_code())
.set_header(header::CONTENT_TYPE, "text/html; charset=utf-8")
.body(self.to_string())
}
@ -30,30 +32,28 @@ impl error::ResponseError for MyError {
}
}
#[get("/")]
async fn index() -> Result<&'static str, MyError> {
Err(MyError::BadClientData)
}
// </override>
#[get("/e2")]
async fn error2() -> Result<&'static str, MyError> {
Err(MyError::InternalError)
}
#[get("/e3")]
async fn error3() -> Result<&'static str, MyError> {
Err(MyError::Timeout)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::HttpServer;
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
.route("/e2", web::get().to(error2))
.route("/e3", web::get().to(error3))
})
.bind("127.0.0.1:8088")?
.run()
.await
HttpServer::new(|| App::new().service(index).service(error2).service(error3))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,17 +1,19 @@
// <recommend-one>
use actix_http::ResponseBuilder;
use actix_web::{error, http::header, http::StatusCode, HttpResponse};
use failure::Fail;
use actix_web::{
dev::HttpResponseBuilder, error, get, http::header, http::StatusCode, App, HttpResponse,
HttpServer,
};
use derive_more::{Display, Error};
#[derive(Fail, Debug)]
#[derive(Debug, Display, Error)]
enum UserError {
#[fail(display = "Validation error on field: {}", field)]
#[display(fmt = "Validation error on field: {}", field)]
ValidationError { field: String },
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
ResponseBuilder::new(self.status_code())
HttpResponseBuilder::new(self.status_code())
.set_header(header::CONTENT_TYPE, "text/html; charset=utf-8")
.body(self.to_string())
}
@ -22,18 +24,18 @@ impl error::ResponseError for UserError {
}
}
// </recommend-one>
#[get("/")]
async fn index() -> Result<&'static str, UserError> {
Err(UserError::ValidationError {
field: "bad stuff".to_string(),
})
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,17 +1,19 @@
// <recommend-two>
use actix_http::ResponseBuilder;
use actix_web::{error, http::header, http::StatusCode, HttpResponse};
use failure::Fail;
use actix_web::{
dev::HttpResponseBuilder, error, get, http::header, http::StatusCode, App, HttpResponse,
HttpServer,
};
use derive_more::{Display, Error};
#[derive(Fail, Debug)]
#[derive(Debug, Display, Error)]
enum UserError {
#[fail(display = "An internal error occurred. Please try again later.")]
#[display(fmt = "An internal error occurred. Please try again later.")]
InternalError,
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
ResponseBuilder::new(self.status_code())
HttpResponseBuilder::new(self.status_code())
.set_header(header::CONTENT_TYPE, "text/html; charset=utf-8")
.body(self.to_string())
}
@ -22,22 +24,21 @@ impl error::ResponseError for UserError {
}
}
#[get("/")]
async fn index() -> Result<&'static str, UserError> {
do_thing_that_failes().map_err(|_e| UserError::InternalError)?;
do_thing_that_fails().map_err(|_e| UserError::InternalError)?;
Ok("success!")
}
// </recommend-two>
fn do_thing_that_failes() -> Result<(), std::io::Error> {
fn do_thing_that_fails() -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "some error"))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,7 +4,6 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
serde = "1.0"
serde_json = "1.0"

View File

@ -1,5 +1,5 @@
// <form>
use actix_web::{web, Result};
use actix_web::{post, web, App, HttpServer, Result};
use serde::Deserialize;
#[derive(Deserialize)]
@ -10,17 +10,16 @@ struct FormData {
/// extract form data using serde
/// this handler gets called only if the content type is *x-www-form-urlencoded*
/// and the content of the request could be deserialized to a `FormData` struct
#[post("/")]
async fn index(form: web::Form<FormData>) -> Result<String> {
Ok(format!("Welcome {}!", form.username))
}
// </form>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| App::new().route("/", web::post().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,5 +1,5 @@
// <json-one>
use actix_web::{web, Result};
use actix_web::{get, web, App, HttpServer, Result};
use serde::Deserialize;
#[derive(Deserialize)]
@ -8,17 +8,16 @@ struct Info {
}
/// deserialize `Info` from request's body
#[get("/")]
async fn index(info: web::Json<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
// </json-one>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| App::new().route("/", web::post().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,5 +1,7 @@
#![allow(dead_code)]
// <json-two>
use actix_web::{error, web, FromRequest, HttpResponse, Responder};
use actix_web::{error, web, App, FromRequest, HttpResponse, HttpServer, Responder};
use serde::Deserialize;
#[derive(Deserialize)]
@ -12,28 +14,24 @@ async fn index(info: web::Json<Info>) -> impl Responder {
format!("Welcome {}!", info.username)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| {
let json_config = web::JsonConfig::default()
.limit(4096)
.error_handler(|err, _req| {
// create custom error response
error::InternalError::from_response(err, HttpResponse::Conflict().finish()).into()
});
App::new().service(
web::resource("/")
// change json extractor configuration
.app_data(web::Json::<Info>::configure(|cfg| {
cfg.limit(4096).error_handler(|err, _req| {
// create custom error response
error::InternalError::from_response(
err,
HttpResponse::Conflict().finish(),
)
.into()
})
}))
.app_data(json_config)
.route(web::post().to(index)),
)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -18,17 +18,18 @@ struct MyInfo {
}
// <option-one>
async fn index(
path: web::Path<(String, String)>,
json: web::Json<MyInfo>,
) -> impl Responder {
async fn index(path: web::Path<(String, String)>, json: web::Json<MyInfo>) -> impl Responder {
let path = path.into_inner();
format!("{} {} {} {}", path.0, path.1, json.id, json.username)
}
// </option-one>
// <option-two>
async fn extract(req: HttpRequest) -> impl Responder {
let params = web::Path::<(String, String)>::extract(&req).await.unwrap();
let params = web::Path::<(String, String)>::extract(&req)
.await
.unwrap()
.into_inner();
let info = web::Json::<MyInfo>::extract(&req)
.await
@ -38,14 +39,14 @@ async fn extract(req: HttpRequest) -> impl Responder {
}
// </option-two>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/{name}/{id}", web::post().to(index))
.route("/{name}/{id}/extract", web::post().to(extract))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,5 +1,5 @@
// <multi>
use actix_web::web;
use actix_web::{get, web};
use serde::Deserialize;
#[derive(Deserialize)]
@ -7,27 +7,24 @@ struct Info {
username: String,
}
#[get("/users/{user_id}/{friend}")] // <- define path parameters
async fn index(
(path, query): (web::Path<(u32, String)>, web::Query<Info>),
web::Path((user_id, friend)): web::Path<(u32, String)>,
query: web::Query<Info>,
) -> String {
format!(
"Welcome {}, friend {}, userid {}!",
query.username, path.1, path.0
"Welcome {}, friend {}, user_id {}!",
query.username, friend, user_id
)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| {
App::new().route(
"/users/{userid}/{friend}", // <- define path parameters
web::get().to(index),
)
})
.bind("127.0.0.1:8088")?
.run()
.await
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}
// </multi>

View File

@ -1,25 +1,21 @@
// <path-one>
use actix_web::{web, Result};
use actix_web::{get, web, Result};
/// extract path info from "/users/{userid}/{friend}" url
/// {userid} - - deserializes to a u32
/// extract path info from "/users/{user_id}/{friend}" url
/// {user_id} - deserializes to a u32
/// {friend} - deserializes to a String
async fn index(info: web::Path<(u32, String)>) -> Result<String> {
Ok(format!("Welcome {}, userid {}!", info.1, info.0))
#[get("/users/{user_id}/{friend}")] // <- define path parameters
async fn index(web::Path((user_id, friend)): web::Path<(u32, String)>) -> Result<String> {
Ok(format!("Welcome {}, user_id {}!", friend, user_id))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| {
App::new().route(
"/users/{userid}/{friend}", // <- define path parameters
web::get().to(index),
)
})
.bind("127.0.0.1:8088")?
.run()
.await
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}
// </path-one>

View File

@ -1,26 +1,21 @@
use actix_web::{web, HttpRequest, Result};
use actix_web::{get, HttpRequest, Result};
// <path-three>
#[get("/users/{userid}/{friend}")] // <- define path parameters
async fn index(req: HttpRequest) -> Result<String> {
let name: String =
req.match_info().get("friend").unwrap().parse().unwrap();
let name: String = req.match_info().get("friend").unwrap().parse().unwrap();
let userid: i32 = req.match_info().query("userid").parse().unwrap();
Ok(format!("Welcome {}, userid {}!", name, userid))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| {
App::new().route(
"/users/{userid}/{friend}", // <- define path parameters
web::get().to(index),
)
})
.bind("127.0.0.1:8088")?
.run()
.await
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}
// </path-three>

View File

@ -1,30 +1,29 @@
// <path-two>
use actix_web::{web, Result};
use actix_web::{get, web, Result};
use serde::Deserialize;
#[derive(Deserialize)]
struct Info {
userid: u32,
user_id: u32,
friend: String,
}
/// extract path info using serde
#[get("/users/{user_id}/{friend}")] // <- define path parameters
async fn index(info: web::Path<Info>) -> Result<String> {
Ok(format!("Welcome {}, userid {}!", info.friend, info.userid))
Ok(format!(
"Welcome {}, user_id {}!",
info.friend, info.user_id
))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| {
App::new().route(
"/users/{userid}/{friend}", // <- define path parameters
web::get().to(index),
)
})
.bind("127.0.0.1:8088")?
.run()
.await
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}
// </path-two>

View File

@ -1,5 +1,5 @@
// <query>
use actix_web::web;
use actix_web::{get, web, App, HttpServer};
use serde::Deserialize;
#[derive(Deserialize)]
@ -8,17 +8,16 @@ struct Info {
}
// this handler get called only if the request's query contains `username` field
#[get("/")]
async fn index(info: web::Query<Info>) -> String {
format!("Welcome {}!", info.username)
}
// </query>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,6 +4,5 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
serde = "1.0"

View File

@ -15,14 +15,14 @@ async fn current_temperature() -> impl Responder {
web::Json(Measurement { temperature: 42.3 })
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(web::resource("/").to(hello_world))
.service(web::resource("/temp").to(current_temperature))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -5,5 +5,4 @@ edition = "2018"
workspace = "../"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0.0"
actix-web = "3"

View File

@ -1,33 +1,31 @@
// <setup>
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
// <handlers>
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
async fn index() -> impl Responder {
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
}
async fn index2() -> impl Responder {
HttpResponse::Ok().body("Hello world again!")
#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
}
// </setup>
// <macro-attributes>
use actix_web::get;
#[get("/hello")]
async fn index3() -> impl Responder {
async fn manual_hello() -> impl Responder {
HttpResponse::Ok().body("Hey there!")
}
// </macro-attributes>
// </handlers>
// <main>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
.route("/again", web::get().to(index2))
.service(hello)
.service(echo)
.route("/hey", web::get().to(manual_hello))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,6 +4,5 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = { version = "2.0", features = ["openssl"] }
actix-rt = "1.0"
actix-web = { version = "3", features = ["openssl"] }
openssl = { version = "0.10", features = ["v110"] }

View File

@ -6,7 +6,7 @@ async fn index(_req: HttpRequest) -> impl Responder {
"Hello."
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// load ssl keys
// to create a self-signed temporary cert for testing:
@ -18,7 +18,7 @@ async fn main() -> std::io::Result<()> {
builder.set_certificate_chain_file("cert.pem").unwrap();
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind_openssl("127.0.0.1:8088", builder)?
.bind_openssl("127.0.0.1:8080", builder)?
.run()
.await
}

View File

@ -4,5 +4,4 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"

View File

@ -6,14 +6,14 @@ async fn greet(req: HttpRequest) -> impl Responder {
format!("Hello {}!", &name)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(greet))
.route("/{name}", web::get().to(greet))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,9 +4,8 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-service = "1.0"
actix-session = "0.3"
futures = "0.3.1"
env_logger = "0.6"
actix-web = "3"
actix-service = "1"
actix-session = "0.4"
futures = "0.3"
env_logger = "0.7"

View File

@ -1,7 +1,7 @@
// <default-headers>
use actix_web::{http, middleware, HttpResponse};
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
@ -17,7 +17,7 @@ async fn main() -> std::io::Result<()> {
),
)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,3 +1,5 @@
#![allow(dead_code)]
// <error-handler>
use actix_web::middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers};
use actix_web::{dev, http, HttpResponse, Result};
@ -10,7 +12,7 @@ fn render_500<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerRespons
Ok(ErrorHandlerResponse::Response(res))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
@ -26,7 +28,7 @@ async fn main() -> std::io::Result<()> {
.route(web::head().to(|| HttpResponse::MethodNotAllowed())),
)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -2,7 +2,7 @@
use actix_web::middleware::Logger;
use env_logger::Env;
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
@ -13,7 +13,7 @@ async fn main() -> std::io::Result<()> {
.wrap(Logger::default())
.wrap(Logger::new("%a %{User-Agent}i"))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -74,7 +74,7 @@ where
}
// </simple>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
@ -86,7 +86,7 @@ async fn main() -> std::io::Result<()> {
}),
)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,3 +1,5 @@
#![allow(dead_code)]
// <user-session>
use actix_session::{CookieSession, Session};
use actix_web::{web, App, Error, HttpResponse, HttpServer};
@ -16,7 +18,7 @@ async fn index(session: Session) -> Result<HttpResponse, Error> {
)))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
@ -26,7 +28,7 @@ async fn main() -> std::io::Result<()> {
)
.service(web::resource("/").to(index))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,9 +1,11 @@
#![allow(dead_code, unused_variables)]
// <wrap-fn>
use actix_service::Service;
use actix_web::{web, App};
use futures::future::FutureExt;
#[actix_rt::main]
#[actix_web::main]
async fn main() {
let app = App::new()
.wrap_fn(|req, srv| {

View File

@ -1,7 +0,0 @@
[package]
name = "og_databases"
version = "0.7.0"
edition = "2018"
[dependencies]
actix-web = "0.7"

View File

@ -1,98 +0,0 @@
// <actor>
use actix::prelude::*;
struct DbExecutor(SqliteConnection);
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
// </actor>
// <message>
struct CreateUser {
name: String,
}
impl Message for CreateUser {
type Result = Result<User, Error>;
}
// </message>
// <handler>
impl Handler<CreateUser> for DbExecutor {
type Result = Result<User, Error>;
fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result {
use self::schema::users::dsl::*;
// Create insertion model
let uuid = format!("{}", uuid::Uuid::new_v4());
let new_user = models::NewUser {
id: &uuid,
name: &msg.name,
};
// normal diesel operations
diesel::insert_into(users)
.values(&new_user)
.execute(&self.0)
.expect("Error inserting person");
let mut items = users
.filter(id.eq(&uuid))
.load::<models::User>(&self.0)
.expect("Error loading person");
Ok(items.pop().unwrap())
}
}
// </handler>
// <main>
/// This is state where we will store *DbExecutor* address.
struct State {
db: Addr<DbExecutor>,
}
fn main() {
let sys = actix::System::new("diesel-example");
// Start 3 parallel db executors
let addr = SyncArbiter::start(3, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
// Start http server
HttpServer::new(move || {
App::new::data(State { db: addr.clone() })
.resource("/{name}", |r| r.method(Method::GET).a(index))
})
.bind("127.0.0.1:8080")
.unwrap()
.start()
.unwrap();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}
// </main>
// <index>
/// Async handler
fn index(req: &HttpRequest<State>) -> Box<Future<Item = HttpResponse, Error = Error>> {
let name = &req.match_info()["name"];
// Send message to `DbExecutor` actor
req.state()
.db
.send(CreateUser {
name: name.to_owned(),
})
.from_err()
.and_then(|res| match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into()),
})
.responder()
}
// </index>

View File

@ -4,6 +4,5 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
serde = "1.0"

View File

@ -31,14 +31,14 @@ async fn index() -> HttpResponse {
.body(include_str!("../static/form.html"))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
.route("/event", web::post().to(capture_event))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -18,7 +18,7 @@
}
function submitJson() {
fetch('http://localhost:8088/event', {
fetch('http://localhost:8080/event', {
method: 'POST',
headers: {
'Accept': 'application/json',

View File

@ -4,5 +4,4 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"

View File

@ -1,5 +1,5 @@
// <arc>
use actix_web::{web, Responder};
use actix_web::{get, web, App, HttpServer, Responder};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
@ -8,20 +8,20 @@ struct AppState {
count: Arc<AtomicUsize>,
}
#[get("/")]
async fn show_count(data: web::Data<AppState>) -> impl Responder {
format!("count: {}", data.count.load(Ordering::Relaxed))
}
#[get("/add")]
async fn add_one(data: web::Data<AppState>) -> impl Responder {
data.count.fetch_add(1, Ordering::Relaxed);
format!("count: {}", data.count.load(Ordering::Relaxed))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
let data = AppState {
count: Arc::new(AtomicUsize::new(0)),
};
@ -29,10 +29,10 @@ async fn main() -> std::io::Result<()> {
HttpServer::new(move || {
App::new()
.data(data.clone())
.route("/", web::to(show_count))
.route("/add", web::to(add_one))
.service(show_count)
.service(add_one)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -19,7 +19,7 @@ async fn add_one(data: web::Data<AppState>) -> impl Responder {
format!("count: {}", data.count.get())
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
@ -33,7 +33,7 @@ async fn main() -> std::io::Result<()> {
.route("/", web::to(show_count))
.route("/add", web::to(add_one))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,5 +4,4 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"

View File

@ -9,14 +9,14 @@ async fn hello(path: web::Path<String>) -> impl Responder {
format!("Hello {}!", &path)
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(web::resource("/").to(index))
.service(web::resource("/{name}").to(hello))
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -6,8 +6,6 @@ edition = "2018"
[dependencies]
serde = "1.0"
serde_json = "1.0"
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
futures = "0.3.1"
bytes = "0.4"
actix-multipart = "0.2"
actix-multipart = "0.3"

View File

@ -1,21 +0,0 @@
// // <json-two>
// use actix_web::{error::Error, HttpRequest, HttpResponse};
// use futures::Future;
// use serde::{Deserialize, Serialize};
// #[derive(Debug, Serialize, Deserialize)]
// struct MyObj {
// name: String,
// number: i32,
// }
// pub fn index(req: HttpRequest) -> Box<Future<Item = HttpResponse, Error = Error>> {
// req.json()
// .from_err()
// .and_then(|val: MyObj| {
// println!("model: {:?}", val);
// Ok(HttpResponse::Ok().json(val)) // <- send response
// })
// .responder()
// }
// // </json-two>

View File

@ -1,4 +1,3 @@
pub mod json_two;
pub mod manual;
pub mod multipart;
pub mod streaming;
@ -18,10 +17,10 @@ async fn index(info: web::Json<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/", web::post().to(index)))
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,6 +1,5 @@
// <json-manual>
use actix_web::{error, web, App, Error, HttpResponse};
use bytes::BytesMut;
use actix_web::{error, post, web, App, Error, HttpResponse};
use futures::StreamExt;
use serde::{Deserialize, Serialize};
use serde_json;
@ -13,9 +12,10 @@ struct MyObj {
const MAX_SIZE: usize = 262_144; // max payload size is 256k
#[post("/")]
async fn index_manual(mut payload: web::Payload) -> Result<HttpResponse, Error> {
// payload is a stream of Bytes objects
let mut body = BytesMut::new();
let mut body = web::BytesMut::new();
while let Some(chunk) = payload.next().await {
let chunk = chunk?;
// limit max size of in-memory payload
@ -31,12 +31,12 @@ async fn index_manual(mut payload: web::Payload) -> Result<HttpResponse, Error>
}
// </json-manual>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::HttpServer;
HttpServer::new(|| App::new().route("/", web::post().to(index_manual)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index_manual))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,7 +1,8 @@
// <streaming>
use actix_web::{web, Error, HttpResponse};
use actix_web::{get, web, Error, HttpResponse};
use futures::StreamExt;
#[get("/")]
async fn index(mut body: web::Payload) -> Result<HttpResponse, Error> {
let mut bytes = web::BytesMut::new();
while let Some(item) = body.next().await {
@ -14,12 +15,12 @@ async fn index(mut body: web::Payload) -> Result<HttpResponse, Error> {
}
// </streaming>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| App::new().route("/", web::post().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,5 +1,5 @@
// <urlencoded>
use actix_web::{web, HttpResponse};
use actix_web::{post, web, HttpResponse};
use serde::Deserialize;
#[derive(Deserialize)]
@ -7,17 +7,18 @@ struct FormData {
username: String,
}
#[post("/")]
async fn index(form: web::Form<FormData>) -> HttpResponse {
HttpResponse::Ok().body(format!("username: {}", form.username))
}
// </urlencoded>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{App, HttpServer};
HttpServer::new(|| App::new().route("/", web::post().to(index)))
.bind("127.0.0.1:8088")?
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,8 +4,7 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
futures = "0.3.1"
serde = "1.0"
serde_json = "1.0"

View File

@ -28,12 +28,12 @@ async fn index() -> impl Responder {
}
// </responder-trait>
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| App::new().route("/", web::get().to(index)))
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -4,8 +4,7 @@ version = "1.0.0"
edition = "2018"
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
actix-web = "3"
serde = "1.0"
futures = "0.3.1"
bytes = "0.5"

View File

@ -1,20 +1,19 @@
// <auto>
use actix_web::{http::ContentEncoding, middleware, HttpResponse};
use actix_web::{get, http::ContentEncoding, middleware, App, HttpResponse, HttpServer};
#[get("/")]
async fn index() -> HttpResponse {
HttpResponse::Ok().body("data")
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| {
App::new()
.wrap(middleware::Compress::new(ContentEncoding::Br))
.route("/", web::get().to(index))
.service(index)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -1,22 +1,23 @@
// <brotli>
use actix_web::{http::ContentEncoding, dev::BodyEncoding, HttpResponse};
use actix_web::{
dev::BodyEncoding, get, http::ContentEncoding, middleware, App, HttpResponse, HttpServer,
};
#[get("/")]
async fn index_br() -> HttpResponse {
HttpResponse::Ok()
.encoding(ContentEncoding::Br)
.body("data")
}
#[actix_rt::main]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
use actix_web::{middleware, web, App, HttpServer};
HttpServer::new(|| {
App::new()
.wrap(middleware::Compress::default())
.route("/", web::get().to(index_br))
.service(index_br)
})
.bind("127.0.0.1:8088")?
.bind("127.0.0.1:8080")?
.run()
.await
}

Some files were not shown because too many files have changed in this diff Show More