If I was to use this code on Actix Web 3 it would work, but I need to use the latest stable release... so 4^.
Here is the snippet in question (actually this is the entirety of my code):
use actix_web::{web, App, HttpResponse, HttpServer, ResponseError, Handler};
fn hello_world() -> HttpResponse {
HttpResponse::Ok().body("Hello, Mr. World") }
#[actix_web::main] async fn main() -> std::io::Result<()> {
HttpServer::new(move || App::new().route("hello", web::get().to(hello_world)))
.bind("0.0.0.0:8000")?
.run()
.await
}
Here is the error I get in version 4 or higher.
web::get().to(hello_world)))
| -- ^^^^^^^^^^^ the trait `Handler<_>` is not implemented for `fn() -> HttpResponse {hello_world}`
| |
| required by a bound introduced by this call
|
note: required by a bound in `Route::to`
--> /Users/xavierfontvillasenor/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-web-4.1.0/src/route.rs:211:12
|
211 | F: Handler<Args>,
| ^^^^^^^^^^^^^ required by this bound in `Route::to`
When I add the trait,
impl Handler<T> for HttpResponse {
type Output = ();
type Future = ();
fn call(&self, args: T) -> Self::Future {
todo!()
}
}
I get
impl Handler<T> for HttpResponse {
| - ^ not found in this scope
| |
| help: you might be missing a type parameter: `<T>`
This works in V.3 why not now? What can I do?
You are not meant to implement Handler yourself, the issue is that handlers are required to be async functions, see the docs for more details:
// 👇
async fn hello_world() -> HttpResponse {
HttpResponse::Ok().body("Hello, Mr. World")
}
Actix Web v4 removed the implementation of Future for HttpResponse causing this error. The compiler is correct but it's not the most useful error. TL;DR: all handlers must be async.
See the migration guide
Related
I develop an authentication middleware for actix_web. I can send an OK response just fine but I cannot send an error message. Here's what I've done so far using the example given here:
/// ResponseBody is my own custom struct to send an error/content body
#[derive(Debug, Serialize, Deserialize)]
pub struct ResponseBody<T> {
pub message: String,
pub data: T,
}
impl<T> ResponseBody<T> {
pub fn new(message: &str, data: T) -> ResponseBody<T> {
ResponseBody {
message: message.to_string(),
data,
}
}
}
/// ....somewhere in my middleware
/// if user passes then I will send him to the destination
/// this code was copied from https://actix.rs/docs/middleware/ example
if authenticate_pass {
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
Ok(res)
})
/// but if he fails to signin or for some other reasons
/// I want to send an error response UNAUTHORIZED (401)
} else {
Box::pin(async move {
Ok(req.into_response(
HttpResponse::Unauthorized()
.json(ResponseBody::new("Session ends. Please login again", ""))
.into_body(),
))
})
}
It displays an error message that I should implement a conversion from actix_web::dev::Response into BoxBody. I don't have any idea what BoxBody is and how to implement them.
error[E0277]: the trait bound `actix_web::dev::Response<_>: std::convert::From<BoxBody>` is not satisfied
--> src\auth.rs:103:21
|
102 | Ok(req.into_response(
| ------------- required by a bound introduced by this call
103 | / HttpResponse::Unauthorized()
104 | | .json(ResponseBody::new("Session ends. Please login again", ""))
105 | | .into_body(),
| |____________________________________^ the trait `std::convert::From<BoxBody>` is not implemented for `actix_web::dev::Response<_>`
|
= help: the following other types implement trait `std::convert::From<T>`:
<actix_web::dev::Response<&'static [u8]> as std::convert::From<&'static [u8]>>
<actix_web::dev::Response<&'static str> as std::convert::From<&'static str>>
<actix_web::dev::Response<B> as std::convert::From<HttpResponse<B>>>
<actix_web::dev::Response<B> as std::convert::From<ServiceResponse<B>>>
<actix_web::dev::Response<BoxBody> as std::convert::From<&actix_http::ws::HandshakeError>>
<actix_web::dev::Response<BoxBody> as std::convert::From<HttpResponseBuilder>>
<actix_web::dev::Response<BoxBody> as std::convert::From<Infallible>>
<actix_web::dev::Response<BoxBody> as std::convert::From<Result<I, E>>>
and 13 others
= note: required because of the requirements on the impl of `Into<actix_web::dev::Response<_>>` for `BoxBody`
note: required by a bound in `ServiceRequest::into_response`
--> C:\Users\mdenn\.cargo\registry\src\github.com-1ecc6299db9ec823\actix-web-4.1.0\src\service.rs:144:32
|
144 | pub fn into_response<B, R: Into<Response<B>>>(self, res: R) -> ServiceResponse<B> {
| ^^^^^^^^^^^^^^^^^ required by this bound in `ServiceRequest::into_response`
If anyone have experience with actix_web middleware, please help. Thanks in advance.
FULL CODE: https://pastebin.com/9PtvSyS9
actix-web = "4.1.0"
futures = "0.3.24"
tokio = { version = "1.18.2", features = ["full"] }
serde = { version = "1.0.137", features = ["derive"] }
If you just want to return the UNAUTHORIZED(401) response, you can try the following code.
Ok(req.into_response(
HttpResponse::Unauthorized()
.finish().map_into_boxed_body(),
))
BoxedBody is defined as follows.
/// A boxed message body with boxed errors.
#[derive(Debug)]
pub struct BoxBody(BoxBodyInner);
The reason of using BoxedBody is because of req.into_response needs that type.
I'm trying to write to standard output using the writeln!() instead of the println!() macro, so I can handle I/O errors (e.g. when I pipe long-running output to head) gracefully. I found the following snippet at https://rust-cli.github.io/book/tutorial/output.html#a-note-on-printing-performance, wrapped up here in an error handling function:
use std::io;
fn main() {
if let Err(error) = run() {
eprintln!("{}", error);
}
}
fn run() -> Result<(), io::Error> {
let stdout = io::stdout(); // get the global stdout entity
let mut handle = io::BufWriter::new(stdout); // wrap that handle in a buffer
writeln!(handle, "foo: {}", 42)?; // add ? if you care about errors here
return Ok(());
}
It works on the website "run this code" button, but when I try to build it for myself, I get a compiler error:
error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<std::io::Stdout>` in the current scope
--> src/main.rs:12:5
|
12 | writeln!(handle, "foo: {}", 42)?; // add ? if you care about errors here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<std::io::Stdout>`
|
::: /home/hwalters/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/io/mod.rs:1516:8
|
1516 | fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
| --------- the method is available for `std::boxed::Box<std::io::BufWriter<std::io::Stdout>>` here
|
= help: items from traits can only be used if the trait is in scope
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
1 | use std::io::Write;
|
Going on the "the method is available for..." hint, I tried wrapping the BufWriter in a Box, but this did not make any difference.
I'm using Rust 2018. Is there something I'm missing?
You need to import the std::io::Write trait as the error suggests:
use std::io::Write;
In Rust traits must be imported to be able to use the methods they implement.
It works on the website "run this code" button, but when I try to build it for myself, I get a compiler error:
If you're referring to the "A note on printing performance", which you link to, then it does include the import in the form of use std::io::{self, Write};.
The writeln! macro requires that its first argument has a write_fmt method. By default, io::BufWriter<T> doesn't implement this method, it's only implemented for io::BufWriter<T: io::Write> so to get access to the implementation you have to import the io::Write trait into your code. Fixed example:
use std::io;
use std::io::Write; // need to import this trait
fn main() {
if let Err(error) = run() {
eprintln!("{}", error);
}
}
fn run() -> Result<(), io::Error> {
let stdout = io::stdout();
let mut handle = io::BufWriter::new(stdout);
writeln!(handle, "foo: {}", 42)?;
Ok(())
}
playground
I've got a scenario looking like this:
struct Instance {
id: Option<String>,
}
struct Context {
instances: Vec<Instance>,
}
impl Context {
async fn filter_async(&self) -> Vec<String> {
self.instances.iter().filter_map(|x|x.id).collect()
}
fn filter(&self) -> Vec<String> {
self.instances.iter().filter_map(|x| x.id).collect()
}
}
With error message:
--> src/main.rs:41:46
|
41 | self.instances.iter().filter_map(|x| x.id).collect()
| ^^^^
| |
| move occurs because `x.id` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `x.id.as_ref()`
I'm trying to figure out what it means. the filter function works just fine, but using the async functions yields a error message.
I'm curious about what's going on here. In the async func It wants to be able to Copy the x.id, this can however be solved though .clone().
Does this mean that the non-async function uses some form of memcpy or otherwise that can't be used in the async scope?
I am creating a rust web application. I am new to this thing and I am trying to make API requests and pass a result form a request as Response to the web view. There are main.rs , route.rs and common.rs files. Basically main.rs file call relevant route and then route will call the function.
But, there is an error with a function in the route.rs file.
error[E0277]: the trait bound `fn() -> impl std::future::Future {<search::routes::get_token as actix_web::service::HttpServiceFactory>::register::get_token}: actix_web::handler::Factory<_, _, _>` is not satisfied
--> src\search\routes.rs:20:10
|
20 | async fn get_token() -> Result<String, reqwest::Error> {
| ^^^^^^^^^ the trait `actix_web::handler::Factory<_, _, _>` is not implemented for `fn() -> impl std::future::Future {<search::routes::get_token as actix_web::service::HttpServiceFactory>::register::get_token}`
How can I Fix this ??
route.rs
use crate::search::User;
use actix_web::{get, post, put, delete, web, HttpResponse, Responder};
use serde_json::json;
extern crate reqwest;
extern crate serde;
mod bfm;
mod common;
#[get("/token")]
async fn get_token() -> Result<String, reqwest::Error> {
let set_token = common::authenticate();
// let set_token = common::get_rust_posts();
return set_token.await;
//HttpResponse::Ok().json(set_token)
}
common.rs
extern crate reqwest;
use reqwest::header::HeaderMap;
use reqwest::header::AUTHORIZATION;
use reqwest::header::CONTENT_TYPE;
pub async fn authenticate() -> Result<String, reqwest::Error> {
fn construct_headers() -> HeaderMap {
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, "Basic bghythjuikyt==".parse().unwrap());
headers.insert(CONTENT_TYPE, "application/x-www-form-urlencoded".parse().unwrap());
assert!(headers.contains_key(AUTHORIZATION));
assert!(!headers.contains_key(CONTENT_TYPE));
headers
}
let client = reqwest::Client::new();
let reszr = client.post("https://api.test.com/auth/token")
.headers(construct_headers())
.body("grant_type=client_credentials")
.send()
.await?
.text()
.await;
return reszr;
}
First of all, please read: https://actix.rs/docs/errors/
--
Do you have implemented ResponseError for reqwest::Error?
You have to implement ResponseError trait because framework have to response with something in case when Result is Err.
Here is an example
impl ResponseError for Error {
fn error_response(&self) -> HttpResponse {
match self.kind_ref() {
ErrorKind::HttpResponse { msg, code, real } => {
println!("{}", real);
HttpResponse::build(code.to_owned()).json(json!({
"status": false,
"msg": msg
}))
}
_ => {
println!("{}", self);
HttpResponse::build(StatusCode::INTERNAL_SERVER_ERROR).finish()
}
}
}
}
Error in this case is my custom error that contains msg, code, real, but the logic should be similar in your case.
--
UPDATE: after #Masklinn comment about error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
Code above works only on custom Error you own.
What you can to do is:
map reqwest::Error to Error that already implements ResponseError. You can check list of implementations here: https://docs.rs/actix-web/3.0.0-alpha.1/actix_web/trait.ResponseError.html#implementors
create custom Error that wraps reqwest::Error (and other errors in your code) and implement ResponseError on it (this is basicaly same/similar as first)
I am pretty sure a code like this worked before:
fn f<F: fn()>(f: F) {
}
However, now it gives the following error:
error: expected one of `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path, found `fn`
--> src/main.rs:96:13
|
96 | fn f<F: fn()>(f: F) {
| -^^ unexpected token
| |
| expected one of 8 possible tokens here
Note that this compiles fine:
fn f(f: fn()) {
}
You must use the function trait:
fn f<F: Fn()>(f: F) {
}
fn is a function pointer, not a trait.
Note that you can also write this:
fn f(f: fn()) {
}