1
0
mirror of https://github.com/actix/actix-website synced 2024-11-23 16:31:08 +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 Cargo.lock
build/ build/
target/ 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 ## Getting Started
Building the website depends on [Hugo](http://gohugo.io). So, first make sure Building the website depends on [Hugo]. So, first make sure
that you have it installed. If on OS X and using Homebrew, run the following: that you have it installed. If on macOS and using [Homebrew], run the following:
```sh ```sh
brew update && brew install hugo brew update
brew install hugo
``` ```
Then, get the website running locally: Then, get the website running locally:
@ -16,16 +17,18 @@ Then, get the website running locally:
```sh ```sh
git clone https://github.com/actix/actix-website.git git clone https://github.com/actix/actix-website.git
cd actix-website cd actix-website
hugo server hugo server
``` ```
Then visit [http://localhost:1313](http://localhost:1313). Then visit http://localhost:1313.
## Updating diagrams ## 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: For instance to edit `connection_overview` diagram:
```sh ```sh
cd static/css/img/diagrams cd static/css/img/diagrams
vi connection_overview.mmd vi connection_overview.mmd
@ -35,5 +38,11 @@ mmdc -i connection_overview.mmd -o connection_overview.svg
# License # 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. 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" baseURL = "https://actix.rs"
[languages.en] [languages.en]
languageCode = "en-US" languageCode = "en-US"
languageName = "English" languageName = "English"
weight = 1 weight = 1
[params] [params]
actixVersion = "0.9" actixVersion = "0.10"
actixWebVersion = "2.0" actixWebVersion = "3"
actixRtVersion = "1.0" actixRtVersion = "1.1"
actixWebMinRustVersion = "1.39" actixWebMinRustVersion = "1.42"
actixMinRustVersion = "1.39" 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 # Browse the Code
All of actix is open source and can be found on our github organization: [actix The Actix ecosystem is fully open source on our GitHub organization [@actix](https://github.com/actix).
on github](https://github.com/actix)
Here are the most important projects and the link to their github repositories Here are the most important projects and the link to their github repositories
and related resources: 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), ([API docs](https://docs.rs/actix-web))
* [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)) - [actix-extras crates](https://github.com/actix/actix-extras)
* [example code](https://github.com/actix/examples) - [actix-net crates](https://github.com/actix/actix-net)
* [this website](https://github.com/actix/actix-website) - [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 # Join us
Want to talk to others about questions? The [actix gitter Want to talk to others about questions? The Actix [Gitter channel](https://gitter.im/actix/actix) or
channel](https://gitter.im/actix/actix) or [reddit community](https://www.reddit.com/r/actix/) are your best starting point.
[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 If you think you found a bug it's best to go to the [github](https://github.com/actix) directly.
[github](https://github.com/actix) directly. There are two repositories There are two repositories that you might want to report against.
that you might want to report against. [actix](https://github.com/actix/actix) [actix](https://github.com/actix/actix) for issues with the actor framework or
for issues with the actor framework or [actix-web](https://github.com/actix/actix-web) [actix-web](https://github.com/actix/actix-web) for the web framework.
for the high level web framework.
We're a welcoming community so don't be afraid to engage. Interactions We're a welcoming community so don't be afraid to engage. Interactions are
are [governed by our code of conduct](coc/). [governed by our code of conduct](coc/).

View File

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

View File

@ -6,35 +6,33 @@ weight: 140
# Writing an Application # Writing an Application
`actix-web` provides various primitives to build web servers and applications with Rust. `actix-web` provides various primitives to build web servers and applications with Rust. It provides
It provides routing, middlewares, pre-processing of requests, post-processing of routing, middleware, pre-processing of requests, post-processing of responses, etc.
responses, etc.
All `actix-web` servers are built around the [`App`][app] instance. It is used for All `actix-web` servers are built around the [`App`][app] instance. It is used for registering
registering routes for resources and middlewares. It also stores application routes for resources and middleware. It also stores application state shared across all handlers
state shared across all handlers within the same scope. within the same scope.
An application's [`scope`][scope] acts as a namespace for all routes, i.e. all routes for a An application's [`scope`][scope] acts as a namespace for all routes, i.e. all routes for a specific
specific application scope have the same url path prefix. The application prefix always application scope have the same url path prefix. The application prefix always contains a leading
contains a leading "/" slash. If a supplied prefix does not contain leading slash, "/" slash. If a supplied prefix does not contain leading slash, it is automatically inserted. The
it is automatically inserted. The prefix should consist of value path segments. prefix should consist of value path segments.
> For an application with scope `/app`, > For an application with scope `/app`, any request with the paths `/app`, `/app/`, or `/app/test`
> any request with the paths `/app`, `/app/`, or `/app/test` would match; > would match; however, the path `/application` would not match.
> however, the path `/application` would not match.
{{< include-example example="application" file="app.rs" section="setup" >}} {{< include-example example="application" file="app.rs" section="setup" >}}
In this example, an application with the `/app` prefix and a `index.html` resource In this example, an application with the `/app` prefix and a `index.html` resource are created. This
are created. This resource is available through the `/app/index.html` url. resource is available through the `/app/index.html` url.
> For more information, check the [URL Dispatch][usingappprefix] section. > For more information, check the [URL Dispatch][usingappprefix] section.
## State ## State
Application state is shared with all routes and resources within the same scope. State Application state is shared with all routes and resources within the same scope. State can be
can be accessed with the [`web::Data<T>`][data] extractor where `T` is the type of the state. State is accessed with the [`web::Data<T>`][data] extractor where `T` is the type of the state. State is also
also available for middlewares. accessible for middleware.
Let's write a simple application and store the application name in the state: 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 ## Shared Mutable State
`HttpServer` accepts an application factory rather than an application instance. `HttpServer` accepts an application factory rather than an application instance. An `HttpServer`
An `HttpServer` constructs an application instance for each thread. Therefore, application data must be constructs an application instance for each thread. Therefore, application data must be constructed
constructed multiple times. If you want to share data between different threads, a shareable multiple times. If you want to share data between different threads, a shareable object should be
object should be used, e.g. `Send` + `Sync`. 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" >}} {{< 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 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 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 configuration. This can be used to help mount a set of routes at a different location than the
than the original author intended while still maintaining the same resource names. original author intended while still maintaining the same resource names.
For example: For example:
{{< include-example example="application" file="scope.rs" section="scope" >}} {{< include-example example="application" file="scope.rs" section="scope" >}}
In the above example, the `show_users` route will have an effective route pattern of In the above example, the `show_users` route will have an effective route pattern of `/users/show`
`/users/show` instead of `/show` because the application's scope argument will be prepended instead of `/show` because the application's scope argument will be prepended to the pattern. The
to the pattern. The route will then only match if the URL path is `/users/show`, route will then only match if the URL path is `/users/show`, and when the
and when the [`HttpRequest.url_for()`][urlfor] function is called with the route name `show_users`, [`HttpRequest.url_for()`][urlfor] function is called with the route name `show_users`, it will
it will generate a URL with that same path. generate a URL with that same path.
## Application guards and virtual hosting ## Application guards and virtual hosting
You can think of a guard as a simple function that accepts a *request* object reference You can think of a guard as a simple function that accepts a _request_ object reference and returns
and returns *true* or *false*. Formally, a guard is any object that implements the _true_ or _false_. Formally, a guard is any object that implements the [`Guard`][guardtrait] trait.
[`Guard`][guardtrait] trait. Actix-web provides several guards. You can check the Actix-web provides several guards. You can check the [functions section][guardfuncs] of the API
[functions section][guardfuncs] of the API docs. docs.
One of the provided guards is [`Header`][guardheader]. It can be used as a One of the provided guards is [`Header`][guardheader]. It can be used as a filter based on request
filter based on request header information. header information.
{{< include-example example="application" file="vh.rs" section="vh" >}} {{< include-example example="application" file="vh.rs" section="vh" >}}
# Configure # Configure
For simplicity and reusability both [`App`][appconfig] and [`web::Scope`][webscopeconfig] provide the `configure` method. For simplicity and reusability both [`App`][appconfig] and [`web::Scope`][webscopeconfig] provide
This function is useful for moving parts of the configuration to a different module or even the `configure` method. This function is useful for moving parts of the configuration to a different
library. For example, some of the resource's configuration could be moved to a different module or even library. For example, some of the resource's configuration could be moved to a
module. different module.
{{< include-example example="application" file="config.rs" section="config" >}} {{< include-example example="application" file="config.rs" section="config" >}}
@ -108,19 +108,22 @@ The result of the above example would be:
/app -> "app" /app -> "app"
/api/test -> "test" /api/test -> "test"
``` ```
Each [`ServiceConfig`][serviceconfig] can have its own `data`, `routes`, and `services`. 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 [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 [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 [guardtrait]: https://docs.rs/actix-web/3/actix_web/guard/trait.Guard.html
[guardfuncs]: https://docs.rs/actix-web/2/actix_web/guard/index.html#functions [guardfuncs]: https://docs.rs/actix-web/3/actix_web/guard/index.html#functions
[guardheader]: https://docs.rs/actix-web/2/actix_web/guard/fn.Header.html [guardheader]: https://docs.rs/actix-web/3/actix_web/guard/fn.Header.html
[data]: https://docs.rs/actix-web/2/actix_web/web/struct.Data.html [data]: https://docs.rs/actix-web/3/actix_web/web/struct.Data.html
[app]: https://docs.rs/actix-web/2/actix_web/struct.App.html [app]: https://docs.rs/actix-web/3/actix_web/struct.App.html
[appconfig]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.configure [appconfig]: https://docs.rs/actix-web/3/actix_web/struct.App.html#method.configure
[appdata]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.app_data [appdata]: https://docs.rs/actix-web/3/actix_web/struct.App.html#method.app_data
[scope]: https://docs.rs/actix-web/2/actix_web/struct.Scope.html [scope]: https://docs.rs/actix-web/3/actix_web/struct.Scope.html
[webscopeconfig]: https://docs.rs/actix-web/2/actix_web/struct.Scope.html#method.configure [webscopeconfig]: https://docs.rs/actix-web/3/actix_web/struct.Scope.html#method.configure
[webscope]: https://docs.rs/actix-web/2/actix_web/web/fn.scope.html [webscope]: https://docs.rs/actix-web/3/actix_web/web/fn.scope.html
[urlfor]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.url_for [urlfor]: https://docs.rs/actix-web/3/actix_web/struct.HttpRequest.html#method.url_for
[serviceconfig]: https://docs.rs/actix-web/2/actix_web/web/struct.ServiceConfig.html [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 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 # Diesel
{{% alert %}} The current version of Diesel (v1) does not support asynchronous operations, so it is important to
NOTE: The `actix-web` 1.0 version of this section is still use the [`web::block`][web-block] function to offload your database operations to the Actix runtime
[being updated](https://github.com/cldershem/actix-website/tree/update1.0-db). Checkout thread-pool.
this [example](https://github.com/actix/examples/tree/master/async_db) until then.
{{% /alert %}}
At the moment, Diesel 1.0 does not support asynchronous operations, You can create action functions that correspond to all the operations your app will perform on the
but it's possible to use the `actix` synchronous actor system as a database interface api. database.
Technically, sync actors are worker style actors. Multiple sync actors {{< include-example example="databases" file="main.rs" section="handler" >}}
can be run in parallel and process messages from same queue. Sync actors work in mpsc mode.
Let's create a simple database api that can insert a new user row into a SQLite table. Now you should set up the database pool using a crate such as `r2d2`, which makes many DB
We must define a sync actor and a connection that this actor will use. The same approach connections available to your app. This means that multiple handlers can manipulate the DB at the
can be used for other databases. 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 {{< include-example example="databases" file="main.rs" section="index" >}}
`User` model instance. Next, we must define the handler implementation for this message.
{{< 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. [web-block]: https://docs.rs/actix-web/3/actix_web/web/fn.block.html
All we need is to start *DbExecutor* actors and store the address in a state where http handler [response-error]: https://docs.rs/actix-web/3/actix_web/trait.ResponseError.html
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

View File

@ -7,12 +7,12 @@ weight: 180
# Errors # Errors
Actix-web uses its own [`actix_web::error::Error`][actixerror] type and Actix-web uses its own [`actix_web::error::Error`][actixerror] type and
[`actix_web::error::ResponseError`][responseerror] trait for error handling [`actix_web::error::ResponseError`][responseerror] trait for error handling from web handlers.
from web handlers.
If a handler returns an `Error` (referring to the [general Rust trait If a handler returns an `Error` (referring to the [general Rust trait
`std::error::Error`][stderror]) in a `Result` that also implements the `std::error::Error`][stderror]) in a `Result` that also implements the `ResponseError` trait,
`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: 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 ```rust
pub trait ResponseError { 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> 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 `Error` in the code above is actix-web's error definition, and any errors that implement
implement `ResponseError` can be converted to one automatically. `ResponseError` can be converted to one automatically.
Actix-web provides `ResponseError` implementations for some common non-actix Actix-web provides `ResponseError` implementations for some common non-actix errors. For example, if
errors. For example, if a handler responds with an `io::Error`, that error is a handler responds with an `io::Error`, that error is converted into an `HttpInternalServerError`:
converted into an `HttpInternalServerError`:
```rust ```rust
use std::io; 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 See [the actix-web API documentation][responseerrorimpls] for a full list of foreign implementations
implementations for `ResponseError`. for `ResponseError`.
## An example of a custom error response ## 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" >}} {{< include-example example="errors" file="main.rs" section="response-error" >}}
`ResponseError` has a default implementation for `error_response()` that will `ResponseError` has a default implementation for `error_response()` that will render a _500_
render a _500_ (internal server error), and that's what will happen when the (internal server error), and that's what will happen when the `index` handler executes above.
`index` handler executes above.
Override `error_response()` to produce more useful results: Override `error_response()` to produce more useful results:
@ -62,69 +61,56 @@ Override `error_response()` to produce more useful results:
# Error helpers # Error helpers
Actix-web provides a set of error helper functions that are useful for generating Actix-web provides a set of error helper functions that are useful for generating specific HTTP
specific HTTP error codes from other errors. Here we convert `MyError`, which error codes from other errors. Here we convert `MyError`, which doesn't implement the
doesn't implement the `ResponseError` trait, to a _400_ (bad request) using `ResponseError` trait, to a _400_ (bad request) using `map_err`:
`map_err`:
{{< include-example example="errors" file="helpers.rs" section="helpers" >}} {{< include-example example="errors" file="helpers.rs" section="helpers" >}}
See the [API documentation for actix-web's `error` module][actixerror] See the [API documentation for actix-web's `error` module][actixerror] for a full list of available
for a full list of available error helpers. 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.
# Error logging # Error logging
Actix logs all errors at the `WARN` log level. If an application's log level is Actix logs all errors at the `WARN` log level. If an application's log level is set to `DEBUG` and
set to `DEBUG` and `RUST_BACKTRACE` is enabled, the backtrace is also logged. `RUST_BACKTRACE` is enabled, the backtrace is also logged. These are configurable with environmental
These are configurable with environmental variables: variables:
``` ```
>> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run >> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run
``` ```
The `Error` type uses the cause's error backtrace if available. If the The `Error` type uses the cause's error backtrace if available. If the underlying failure does not
underlying failure does not provide a backtrace, a new backtrace is constructed provide a backtrace, a new backtrace is constructed pointing to the point where the conversion
pointing to the point where the conversion occurred (rather than the origin of occurred (rather than the origin of the error).
the error).
# Recommended practices in error handling # Recommended practices in error handling
It might be useful to think about dividing the errors an application produces It might be useful to think about dividing the errors an application produces into two broad groups:
into two broad groups: those which are intended to be be user-facing, and those those which are intended to be be user-facing, and those which are not.
which are not.
An example of the former is that I might use failure to specify a `UserError` An example of the former is that I might use failure to specify a `UserError` enum which
enum which encapsulates a `ValidationError` to return whenever a user sends bad encapsulates a `ValidationError` to return whenever a user sends bad input:
input:
{{< include-example example="errors" file="recommend_one.rs" section="recommend-one" >}} {{< include-example example="errors" file="recommend_one.rs" section="recommend-one" >}}
This will behave exactly as intended because the error message defined with This will behave exactly as intended because the error message defined with `display` is written
`display` is written with the explicit intent to be read by a user. with the explicit intent to be read by a user.
However, sending back an error's message isn't desirable for all errors -- However, sending back an error's message isn't desirable for all errors -- there are many failures
there are many failures that occur in a server environment where we'd probably that occur in a server environment where we'd probably want the specifics to be hidden from the
want the specifics to be hidden from the user. For example, if a database goes user. For example, if a database goes down and client libraries start producing connect timeout
down and client libraries start producing connect timeout errors, or if an HTML errors, or if an HTML template was improperly formatted and errors when rendered. In these cases, it
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.
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` Here's an example that maps an internal error to a user-facing `InternalError` with a custom
with a custom message: message:
{{< include-example example="errors" file="recommend_two.rs" section="recommend-two" >}} {{< 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 By dividing errors into those which are user facing and those which are not, we can ensure that we
can ensure that we don't accidentally expose users to errors thrown by don't accidentally expose users to errors thrown by application internals which they weren't meant
application internals which they weren't meant to see. to see.
# Error Logging # Error Logging
@ -132,10 +118,11 @@ This is a basic example using `middleware::Logger`:
{{< include-example example="errors" file="logging.rs" section="logging" >}} {{< include-example example="errors" file="logging.rs" section="logging" >}}
[actixerror]: https://docs.rs/actix-web/2/actix_web/error/struct.Error.html [actixerror]: https://docs.rs/actix-web/3/actix_web/error/struct.Error.html
[errorhelpers]: https://docs.rs/actix-web/2/actix_web/trait.ResponseError.html [errorhelpers]: https://docs.rs/actix-web/3/actix_web/trait.ResponseError.html
[failure]: https://github.com/rust-lang-nursery/failure [derive_more]: https://crates.io/crates/derive_more
[responseerror]: https://docs.rs/actix-web/2/actix_web/error/trait.ResponseError.html [responseerror]: https://docs.rs/actix-web/3/actix_web/error/trait.ResponseError.html
[responseerrorimpls]: https://docs.rs/actix-web/2/actix_web/error/trait.ResponseError.html#foreign-impls [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 [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*][pathstruct] provides information that can be extracted from the Request's
path. You can deserialize any variable segment from the path. path. You can deserialize any variable segment from the path.
For instance, for resource that registered for the `/users/{userid}/{friend}` path, For instance, for resource that registered for the `/users/{user_id}/{friend}` path,
two segments could be deserialized, `userid` and `friend`. These segments could be 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 extracted into a `tuple`, i.e. `Path<(u32, String)>` or any structure that implements
the `Deserialize` trait from the *serde* crate. 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 > request handling processes would block. If you need to share or update some state
> from multiple threads, consider using the tokio synchronization primitives. > from multiple threads, consider using the tokio synchronization primitives.
[pathstruct]: https://docs.rs/actix-web/2/actix_web/dev/struct.Path.html [pathstruct]: https://docs.rs/actix-web/3/actix_web/dev/struct.Path.html
[querystruct]: https://docs.rs/actix-web/2/actix_web/web/struct.Query.html [querystruct]: https://docs.rs/actix-web/3/actix_web/web/struct.Query.html
[jsonstruct]: https://docs.rs/actix-web/2/actix_web/web/struct.Json.html [jsonstruct]: https://docs.rs/actix-web/3/actix_web/web/struct.Json.html
[jsonconfig]: https://docs.rs/actix-web/2/actix_web/web/struct.JsonConfig.html [jsonconfig]: https://docs.rs/actix-web/3/actix_web/web/struct.JsonConfig.html
[formconfig]: https://docs.rs/actix-web/2/actix_web/web/struct.FormConfig.html [formconfig]: https://docs.rs/actix-web/3/actix_web/web/struct.FormConfig.html
[datastruct]: https://docs.rs/actix-web/2/actix_web/web/struct.Data.html [datastruct]: https://docs.rs/actix-web/3/actix_web/web/struct.Data.html
[stringexample]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html#example-2 [stringexample]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html#example-2
[bytesexample]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html#example-4 [bytesexample]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html#example-4
[payloadexample]: https://docs.rs/actix-web/2/actix_web/web/struct.Payload.html [payloadexample]: https://docs.rs/actix-web/3/actix_web/web/struct.Payload.html
[actix]: https://actix.github.io/actix/actix/ [actix]: https://actix.github.io/actix/actix/

View File

@ -4,9 +4,14 @@ menu: docs_basics
weight: 130 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! ## Hello, world!
@ -17,71 +22,35 @@ cargo new hello-world
cd hello-world cd hello-world
``` ```
Now, add `actix-web` as a dependency of your project by ensuring your `Cargo.toml` Add `actix-web` as a dependency of your project by adding the following to your `Cargo.toml` file.
contains the following:
```ini ```toml
[dependencies] [dependencies]
actix-web = "{{< actix-version "actix-web" >}}" 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. Request handlers use an async functions that accept zero or more parameters. These parameters can be
Now your `Cargo.toml` should look like following: extracted from a request (see `FromRequest` trait) and returns a type that can be converted into an
`HttpResponse` (see `Responder` trait):
```ini {{< include-example example="getting-started" section="handlers" >}}
[dependencies]
actix-web = "{{< actix-version "actix-web" >}}"
actix-rt = "{{< actix-version "actix-rt" >}}"
```
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 Next, create an `App` instance and register the request handlers. Use `App::service` for the
extracted from a request (ie, `impl FromRequest`) and returns a type that can be handlers using routing macros and `App::route` for manually routed handlers, declaring the a path
converted into an `HttpResponse` (ie, `impl Responder`): 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="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.
{{< include-example example="getting-started" section="main" >}} {{< include-example example="getting-started" section="main" >}}
That's it! Now, compile and run the program with `cargo run`. That's it! Compile and run the program with `cargo run`. The `#[actix_web::main]` macro executes the
Head over to `http://localhost:8088/` to see the results. 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 <!-- LINKS -->
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].
[rustguide]: https://doc.rust-lang.org/book/ch01-01-installation.html
[actix-web-codegen]: https://docs.rs/actix-web-codegen/ [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 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. 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. different responder types into a single type.
{{< include-example example="either" file="main.rs" section="either" >}} {{< include-example example="either" file="main.rs" section="either" >}}
[implfromrequest]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html [implfromrequest]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html
[respondertrait]: https://docs.rs/actix-web/2/actix_web/trait.Responder.html [respondertrait]: https://docs.rs/actix-web/3/actix_web/trait.Responder.html
[responderimpls]: https://docs.rs/actix-web/2/actix_web/trait.Responder.html#foreign-impls [responderimpls]: https://docs.rs/actix-web/3/actix_web/trait.Responder.html#foreign-impls
[either]: https://docs.rs/actix-web/2/actix_web/enum.Either.html [either]: https://docs.rs/actix-web/3/actix_web/enum.Either.html

View File

@ -1,15 +1,16 @@
--- ---
title: HTTP/2.0 title: HTTP/2
menu: docs_proto menu: docs_protocols
weight: 250 weight: 250
--- ---
`actix-web` automatically upgrades connections to *HTTP/2.0* if possible. `actix-web` automatically upgrades connections to *HTTP/2* if possible.
# Negotiation # 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. > Currently, only `rust-openssl` has support.
`alpn` negotiation requires enabling the feature. When enabled, `HttpServer` provides the `alpn` negotiation requires enabling the feature. When enabled, `HttpServer` provides the
@ -18,7 +19,6 @@ weight: 250
```toml ```toml
[dependencies] [dependencies]
actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["openssl"] } actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["openssl"] }
actix-rt = "1.0.0"
openssl = { version = "0.10", features = ["v110"] } openssl = { version = "0.10", features = ["v110"] }
``` ```
{{< include-example example="http2" file="main.rs" section="main" >}} {{< 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 [rfcsection32]: https://http2.github.io/http2-spec/#rfc.section.3.2
[rfcsection34]: https://http2.github.io/http2-spec/#rfc.section.3.4 [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 [tlsalpn]: https://tools.ietf.org/html/rfc7301
[examples]: https://github.com/actix/examples/tree/master/rustls [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 menu: docs_architecture
weight: 1020 weight: 1020
--- ---
## Architecture overview ## 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 ```rust
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.route("/", web::to(|| HttpResponse::Ok())) .route("/", web::to(|| HttpResponse::Ok()))
}) })
.bind("127.0.0.1:8088")? .bind("127.0.0.1:8080")?
.run() .run()
.await .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 menu: docs_advanced
weight: 220 weight: 220
--- ---
@ -29,11 +29,11 @@ The following demonstrates creating a simple middleware:
{{< include-example example="middleware" file="main.rs" section="simple" >}} {{< 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" >}} {{< 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. > *compress*, etc.
# Logging # Logging
@ -89,8 +89,7 @@ a specified header.
## User sessions ## User sessions
Actix-web provides a general solution for session management. The Actix-web provides a general solution for session management. The
[**actix-session**][actixsession] middleware can be used with different backend types [**actix-session**][actixsession] middleware can use multiple backend types to store session data.
to store session data in different backends.
> By default, only cookie session backend is implemented. Other backend implementations > By default, only cookie session backend is implemented. Other backend implementations
> can be added. > can be added.
@ -132,6 +131,6 @@ into a response.
[cookiesession]: https://docs.rs/actix-session/0.3.0/actix_session/struct.CookieSession.html [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/ [actixsession]: https://docs.rs/actix-session/0.3.0/actix_session/
[envlogger]: https://docs.rs/env_logger/*/env_logger/ [envlogger]: https://docs.rs/env_logger/*/env_logger/
[servicetrait]: https://docs.rs/actix-web/2/actix_web/dev/trait.Service.html [servicetrait]: https://docs.rs/actix-web/3/actix_web/dev/trait.Service.html
[transformtrait]: https://docs.rs/actix-web/2/actix_web/dev/trait.Transform.html [transformtrait]: https://docs.rs/actix-web/3/actix_web/dev/trait.Transform.html
[wrap_fn]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.wrap_fn [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 [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 [fieldstruct]: https://docs.rs/actix-multipart/0.2/actix_multipart/struct.Field.html
[multipartexample]: https://github.com/actix/examples/tree/master/multipart/ [multipartexample]: https://github.com/actix/examples/tree/master/multipart/
[urlencoded]: https://docs.rs/actix-web/2/actix_web/dev/struct.UrlEncoded.html [urlencoded]: https://docs.rs/actix-web/3/actix_web/dev/struct.UrlEncoded.html
[payloadextractor]: https://docs.rs/actix-web/2/actix_web/web/struct.Payload.html [payloadextractor]: https://docs.rs/actix-web/3/actix_web/web/struct.Payload.html
[multipartcrate]: https://crates.io/crates/actix-multipart [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" >}} {{< include-example example="responses" file="json_resp.rs" section="json-resp" >}}
[responsebuilder]: https://docs.rs/actix-web/2/actix_web/dev/struct.HttpResponseBuilder.html [responsebuilder]: https://docs.rs/actix-web/3/actix_web/dev/struct.HttpResponseBuilder.html
[compressmidddleware]: https://docs.rs/actix-web/2/actix_web/middleware/struct.Compress.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 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 `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. 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 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 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. method.
{{< include-example example="server" section="main" >}} {{< include-example example="server" section="main" >}}
The `run()` method returns an instance of the [`Server`][server] type. Methods of server type 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 - `pause()` - Pause accepting incoming connections
- `resume()` - Resume accepting incoming connections - `resume()` - Resume accepting incoming connections
- `stop()` - Stop incoming connection processing, stop all workers and exit - `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" >}} {{< include-example example="server" file="signals.rs" section="signals" >}}
## Multi-threading ## 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 equal to the number of logical CPUs in the system. This number can be overridden with the
[`HttpServer::workers()`][workers] method. [`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 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 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*. > *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 > It is possible to disable signal handling with
[`HttpServer::disable_signals()`][disablesignals] method. [`HttpServer::disable_signals()`][disablesignals] method.
[server]: https://docs.rs/actix-web/2/actix_web/dev/struct.Server.html [server]: https://docs.rs/actix-web/3/actix_web/dev/struct.Server.html
[httpserverstruct]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html [httpserverstruct]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html
[bindmethod]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.bind [bindmethod]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.bind
[bindopensslmethod]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.bind_openssl [bindopensslmethod]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.bind_openssl
[bindrusttls]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.bind_rustls [bindrusttls]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.bind_rustls
[startmethod]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.start [startmethod]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.start
[workers]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.workers [workers]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.workers
[tlsalpn]: https://tools.ietf.org/html/rfc7301 [tlsalpn]: https://tools.ietf.org/html/rfc7301
[exampleopenssl]: https://github.com/actix/examples/blob/master/openssl [exampleopenssl]: https://github.com/actix/examples/blob/master/openssl
[shutdowntimeout]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.shutdown_timeout [shutdowntimeout]: https://docs.rs/actix-web/3/actix_web/struct.HttpServer.html#method.shutdown_timeout
[disablesignals]: https://docs.rs/actix-web/2/actix_web/struct.HttpServer.html#method.disable_signals [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 # Integration tests
There are a few methods for testing your application. Actix-web can be used 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 `TestRequest::get()`, `TestRequest::post()` and other
methods can be used to send requests to the test server. 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 To create a `Service` for testing, use the `test::init_service` method which accepts a
regular `App` builder. 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" >}} {{< 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" >}} {{< 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 [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 [responsebody]: https://docs.rs/actix-web/3/actix_web/body/enum.ResponseBody.html
[actixdocs]: https://docs.rs/actix-web/2/actix_web/test/index.html [actixdocs]: https://docs.rs/actix-web/3/actix_web/test/index.html
[testrequest]: https://docs.rs/actix-web/2/actix_web/test/struct.TestRequest.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 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*, 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. for the same path, in that case, multiple routes register for the same resource path.
{{< include-example example="url-dispatch" section="main" >}} {{< 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" >}} {{< 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 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 ## Configuring a Route
@ -197,7 +197,7 @@ When matching the following URL:
http://example.com/foo/La%20Pe%C3%B1a 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'} 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" >}} {{< include-example example="url-dispatch" file="scope.rs" section="scope" >}}
A *scoped* path can contain variable path segments as resources. Consistent with 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()`. You can get variable path segments from `HttpRequest::match_info()`.
[`Path` extractor][pathextractor] also is able to extract scope level variable segments. [`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] Actix provides functionality for type safe path information extraction. [*Path*][pathstruct]
extracts information, destination type could be defined in several different forms. Simplest 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 pattern. i.e. you can match path pattern `/{id}/{username}/` against
`Path<(u32, String)>` type, but `Path<(String, String, String)>` type will always fail. `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 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 and returns *true* or *false*. Formally, a guard is any object that implements the
[`Guard`][guardtrait] trait. Actix provides several predicates, you can check [`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*: 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" >}} {{< include-example example="url-dispatch" file="dhandler.rs" section="default" >}}
[handlersection]: ../handlers/ [handlersection]: ../handlers/
[approute]: https://docs.rs/actix-web/2/actix_web/struct.App.html#method.route [approute]: https://docs.rs/actix-web/3/actix_web/struct.App.html#method.route
[appservice]: https://docs.rs/actix-web/2/actix_web/struct.App.html?search=#method.service [appservice]: https://docs.rs/actix-web/3/actix_web/struct.App.html?search=#method.service
[webresource]: https://docs.rs/actix-web/2/actix_web/struct.Resource.html [webresource]: https://docs.rs/actix-web/3/actix_web/struct.Resource.html
[resourcehandler]: https://docs.rs/actix-web/2/actix_web/struct.Resource.html#method.route [resourcehandler]: https://docs.rs/actix-web/3/actix_web/struct.Resource.html#method.route
[route]: https://docs.rs/actix-web/2/actix_web/struct.Route.html [route]: https://docs.rs/actix-web/3/actix_web/struct.Route.html
[routeguard]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.guard [routeguard]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.guard
[routemethod]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.method [routemethod]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.method
[routeto]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.to [routeto]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.to
[routetoasync]: https://docs.rs/actix-web/2/actix_web/struct.Route.html#method.to_async [routetoasync]: https://docs.rs/actix-web/3/actix_web/struct.Route.html#method.to_async
[matchinfo]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.match_info [matchinfo]: https://docs.rs/actix-web/3/actix_web/struct.HttpRequest.html#method.match_info
[pathget]: https://docs.rs/actix-web/2/actix_web/dev/struct.Path.html#method.get [pathget]: https://docs.rs/actix-web/3/actix_web/dev/struct.Path.html#method.get
[pathstruct]: https://docs.rs/actix-web/2/actix_web/dev/struct.Path.html [pathstruct]: https://docs.rs/actix-web/3/actix_web/dev/struct.Path.html
[query]: https://docs.rs/actix-web/2/actix_web/web/struct.Query.html [query]: https://docs.rs/actix-web/3/actix_web/web/struct.Query.html
[urlfor]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.url_for [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 [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 [guardtrait]: https://docs.rs/actix-web/3/actix_web/guard/trait.Guard.html
[guardfuncs]: https://docs.rs/actix-web/2/actix_web/guard/index.html#functions [guardfuncs]: https://docs.rs/actix-web/3/actix_web/guard/index.html#functions
[requestextensions]: https://docs.rs/actix-web/2/actix_web/struct.HttpRequest.html#method.extensions [requestextensions]: https://docs.rs/actix-web/3/actix_web/struct.HttpRequest.html#method.extensions
[implfromrequest]: https://docs.rs/actix-web/2/actix_web/trait.FromRequest.html [implfromrequest]: https://docs.rs/actix-web/3/actix_web/trait.FromRequest.html
[implresponder]: https://docs.rs/actix-web/2/actix_web/trait.Responder.html [implresponder]: https://docs.rs/actix-web/3/actix_web/trait.Responder.html
[pathextractor]: ../extractors [pathextractor]: ../extractors

View File

@ -1,6 +1,6 @@
--- ---
title: Websockets title: Websockets
menu: docs_proto menu: docs_protocols
weight: 240 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]. > 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] > is available in [websocket-chat directory][chat]
[message]: https://docs.rs/actix-web-actors/2/actix_web_actors/ws/enum.Message.html [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/ [examples]: https://github.com/actix/examples/tree/master/websocket/
[chat]: https://github.com/actix/examples/tree/master/websocket-chat/ [chat]: https://github.com/actix/examples/tree/master/websocket-chat/

View File

@ -4,24 +4,29 @@ menu: docs_intro
weight: 100 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 Actix is a few things. The base of it is a powerful actor system for Rust on top of which the
top of which the `actix-web` system was originally built. This is what you are most `actix-web` system was originally built. This is what you are most likely going to work with. What
likely going to work with. What `actix-web` gives you is a fun and very fast web `actix-web` gives you is a powerful and very fast web development framework.
development framework.
We call `actix-web` a small and pragmatic framework. For all intents and purposes We call `actix-web` a small and pragmatic framework. For all intents and purposes it's a
it's a microframework with a few twists. If you are already a Rust programmer micro-framework with a few twists. If you are already a Rust programmer you will probably find
you will probably find yourself at home quickly, but even if you are coming from yourself at home quickly, but even if you are coming from another programming language you should
another programming language you should find `actix-web` easy to pick up. find `actix-web` easy to pick up.
An application developed with `actix-web` will expose an HTTP server contained An application developed with `actix-web` will expose an HTTP server contained within a native
within a native executable. You can either put this behind another HTTP server like executable. You can either put this behind another HTTP server like nginx or serve it up as-is. Even
nginx or serve it up as-is. Even in the complete absence of another HTTP in the complete absence of another HTTP server `actix-web` is powerful enough to provide HTTP/1 and
server `actix-web` is powerful enough to provide HTTP 1 and HTTP 2 support as HTTP/2 support as well as TLS (HTTPS). This makes it useful for building small services ready for
well as SSL/TLS. This makes it useful for building small services ready for
distribution. distribution.
Most importantly: `actix-web` runs on Rust {{< rust-version "actix-web" >}} or later Most importantly: `actix-web` runs on Rust {{< rust-version "actix-web" >}} or later and it works
and it works with stable releases. 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] [workspace]
members = [ members = [
"application", "application",
"async-handlers",
"easy-form-handling", "easy-form-handling",
"either",
"errors",
"extractors",
"flexible-responders", "flexible-responders",
"getting-started", "getting-started",
"main-example",
"powerful-extractors",
"request-routing",
"server",
"url-dispatch",
"responder-trait",
"either",
"extractors",
"autoreload",
"errors",
"requests",
"responses",
"middleware",
"static-files",
"http2", "http2",
"testing", "main-example",
"async-handlers", "middleware",
"websockets", "powerful-extractors",
"request-handlers", "request-handlers",
"request-routing",
"requests",
"responder-trait",
"responses",
"server",
"static-files",
"testing",
"url-dispatch",
"websockets",
] ]
exclude = [ exclude = ["databases", "sentry"]
"og_databases",
"sentry",
]

View File

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

View File

@ -1,18 +1,23 @@
#![allow(dead_code)]
// <setup> // <setup>
use actix_web::{web, App, Responder, HttpServer}; use actix_web::{web, App, HttpServer, Responder};
async fn index() -> impl Responder { async fn index() -> impl Responder {
"Hello world!" "Hello world!"
} }
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
HttpServer::new(|| { HttpServer::new(|| {
App::new().service( 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() .run()
.await .await
} }

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ async fn index(data: web::Data<AppStateWithCounter>) -> String {
// </setup_mutable> // </setup_mutable>
// <make_app_mutable> // <make_app_mutable>
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
let counter = web::Data::new(AppStateWithCounter { let counter = web::Data::new(AppStateWithCounter {
counter: Mutex::new(0), counter: Mutex::new(0),
@ -28,7 +28,7 @@ async fn main() -> std::io::Result<()> {
.app_data(counter.clone()) // <- register the created data .app_data(counter.clone()) // <- register the created data
.route("/", web::get().to(index)) .route("/", web::get().to(index))
}) })
.bind("127.0.0.1:8088")? .bind("127.0.0.1:8080")?
.run() .run()
.await .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 { async fn show_users(_req: HttpRequest) -> impl Responder {
"unimplemented!" "unimplemented!"
} }
#[rustfmt::skip]
// <scope> // <scope>
#[actix_rt::main] #[actix_web::main]
async fn main() { async fn main() {
App::new() let scope = web::scope("/users").service(show_users);
.service( App::new().service(scope);
web::scope("/users")
.route("/show", web::get().to(show_users)));
} }
// </scope> // </scope>

View File

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

View File

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

View File

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

View File

@ -1,10 +1,11 @@
// <stream> // <stream>
use actix_web::{web, App, HttpServer, Error, HttpResponse}; use actix_web::{get, App, Error, HttpResponse, HttpServer};
use bytes::Bytes; use bytes::Bytes;
use futures::stream::once;
use futures::future::ok; 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"))); let body = once(ok::<_, Error>(Bytes::from_static(b"test")));
HttpResponse::Ok() HttpResponse::Ok()
@ -12,10 +13,10 @@ async fn index() -> HttpResponse {
.streaming(body) .streaming(body)
} }
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/async", web::to(index))) HttpServer::new(|| App::new().service(stream))
.bind("127.0.0.1:8088")? .bind("127.0.0.1:8080")?
.run() .run()
.await .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" edition = "2018"
[dependencies] [dependencies]
actix-web = "2.0" actix-web = "3"
actix-rt = "1.0"
serde = "1.0" 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) format!("Hello {} from {}!", form.username, form.country)
} }
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.route("/", web::get().to(index)) .route("/", web::get().to(index))
.route("/register", web::post().to(register)) .route("/register", web::post().to(register))
}) })
.bind("127.0.0.1:8088")? .bind("127.0.0.1:8080")?
.run() .run()
.await .await
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
// <default-headers> // <default-headers>
use actix_web::{http, middleware, HttpResponse}; use actix_web::{http, middleware, HttpResponse};
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer}; 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() .run()
.await .await
} }

View File

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

View File

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

View File

@ -74,7 +74,7 @@ where
} }
// </simple> // </simple>
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
use actix_web::{web, App, HttpServer}; 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() .run()
.await .await
} }

View File

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

View File

@ -1,9 +1,11 @@
#![allow(dead_code, unused_variables)]
// <wrap-fn> // <wrap-fn>
use actix_service::Service; use actix_service::Service;
use actix_web::{web, App}; use actix_web::{web, App};
use futures::future::FutureExt; use futures::future::FutureExt;
#[actix_rt::main] #[actix_web::main]
async fn main() { async fn main() {
let app = App::new() let app = App::new()
.wrap_fn(|req, srv| { .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" edition = "2018"
[dependencies] [dependencies]
actix-web = "2.0" actix-web = "3"
actix-rt = "1.0"
serde = "1.0" serde = "1.0"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,22 +1,23 @@
// <brotli> // <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 { async fn index_br() -> HttpResponse {
HttpResponse::Ok() HttpResponse::Ok()
.encoding(ContentEncoding::Br) .encoding(ContentEncoding::Br)
.body("data") .body("data")
} }
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
use actix_web::{middleware, web, App, HttpServer};
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.wrap(middleware::Compress::default()) .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() .run()
.await .await
} }

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