#HttpResponse does not implement `Copy` trait

1 messages · Page 1 of 1 (latest)

modern zodiac
#
#[derive(Debug)]
pub struct ServiceResponse(HttpResponse);

impl std::fmt::Display for ServiceResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "ServiceResponse")
    }
}

impl ServiceResponse {
    pub fn new<T>(status_code: StatusCode, value: T) -> Self
    where
        T: Serialize,
    {
        Self(HttpResponse::build(status_code).json(value))
    }
}

impl ResponseError for ServiceResponse {
    fn error_response(&self) -> HttpResponse {
        //cannot move out of `self` which is behind a shared reference
        // move occurs because `self.0` has type `HttpResponse`, which does not implement the `Copy` trait
        self.0
    }
}

how can i fix the error if i cant clone the HttpResponse?

sleek geyser
modern zodiac
sleek geyser
modern zodiac
sleek geyser
#

replace ErrorUnauthorized with desired error

#

from actix_web::error

#

if error_struct wont work, try stringify it using serde_json

#

hope it's work

sleek geyser
#

lemme check a sec

modern zodiac
#

and that would return a HttpResponse which i cant use

#

it expects actix-web::error::Error

modern zodiac
sleek geyser
rapid girder
#
let res: RefCell<Option<HttpResponse>> = ...;
resp.borrow_mut().take();
modern zodiac
# rapid girder ```rust let res: RefCell<Option<HttpResponse>> = ...; resp.borrow_mut().take(); ...
pub struct ServiceResponse(HttpResponse);

impl ResponseError for ServiceResponse {
    fn error_response(&self) -> HttpResponse {
/* 
`&mut HttpResponse` is not an iterator
the following trait bounds were not satisfied:
`HttpResponse: Iterator`
which is required by `&mut HttpResponse: Iterator`
`&mut HttpResponse: Iterator`
which is required by `&mut &mut HttpResponse: Iterator`
*/
        self.0.borrow_mut().take()
    }
}

how would i implement it?

sleek geyser
# modern zodiac ```rs pub struct ServiceResponse(HttpResponse); impl ResponseError for ServiceR...

found a way.

use one of actix middleware example
delete all the <B>

here's working example

use std::{
    future::{ready, Ready},
    rc::Rc
};

use actix_web::{
    dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
    Error,
    http::{header, StatusCode}, HttpResponseBuilder
};
use futures_util::future::LocalBoxFuture;

pub struct Auth;

impl<S: 'static> Transform<S, ServiceRequest> for Auth
where
    S: Service<ServiceRequest, Response = ServiceResponse, Error = Error>,
    S::Future: 'static
{
    type Response = ServiceResponse;
    type Error = Error;
    type InitError = ();
    type Transform = AuthMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ready(Ok(AuthMiddleware {
            service: Rc::new(service),
        }))
    }
}

pub struct AuthMiddleware<S> {
    // This is special: We need this to avoid lifetime issues.
    service: Rc<S>,
}

impl<S> Service<ServiceRequest> for AuthMiddleware<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse, Error = Error> + 'static,
    S::Future: 'static
{
    type Response = ServiceResponse;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    dev::forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let svc = self.service.clone();


        Box::pin(async move {
            
            let headers =  req.headers();
            let auth_header = match headers.get("Authorization") {
                Some(e) => e,
                None => {
                    let new_response = HttpResponseBuilder::new(StatusCode::BAD_REQUEST)
                            .insert_header((header::CONTENT_TYPE, "application/json"))
                            .json("Unauthorized xxx");
                    return Ok(ServiceResponse::new(
                        req.request().to_owned(),
                        new_response
                    ))
                }
            };
            
            let res = svc.call(req).await?;
            Ok(res)
        })
    }
}
#

highlighted this code to return custom body.

let new_response = HttpResponseBuilder::new(StatusCode::BAD_REQUEST)
        .insert_header((header::CONTENT_TYPE, "application/json"))
        .json("json content");
return Ok(ServiceResponse::new(
    req.request().to_owned(),
    new_response
))

change StatusCode::BAD_REQUEST as desired

#

i think i'll do a pull request to middleware example. ❓

#

without authorization

#

another test

#

hope it helps @modern zodiac

sleek geyser
#

@rapid girder opened PR regarding this on examples

modern zodiac
#

@sleek geyser your method does work, but at that point i believe your implementation just makes the middleware a handler

#

i started playing around with it, and i modified my original code to get a method that somewhat works

#
#[derive(Debug)]
pub struct ServiceResponse {
    res: HttpResponse,
    display: String,
}

impl std::fmt::Display for ServiceResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.display)
    }
}

impl ServiceResponse {
    pub fn new<T>(status_code: StatusCode, data: T) -> Self
    where
        T: Serialize,
    {
        ServiceResponse {
            res: HttpResponse::build(status_code).json(&data),
            display: serde_json::to_string(&data).unwrap().replace("\\\"", "\""),
        }
    }
}

impl ResponseError for ServiceResponse {
    fn error_response(&self) -> HttpResponse {
        let mut res = HttpResponse::build(self.res.status());

        res.insert_header((
            header::CONTENT_TYPE,
            HeaderValue::from_static("application/json"),
        ));

        res.body(self.display.to_owned())
    }
}
#

I had a really difficult time extracting the body from the httpresponse stored, so i just decided to store it on the struct directly. As for error_response, i manually set the content type and body because json internally uses to_string() again which would re-add the \" which i removed.