Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to respond with an image using Vapor?

Tags:

swift

vapor

I just want to have a controller action that is basically doing the same as accessing an image directly through the Public/ folder. The difference is that the route can be whatever you want and the returned image will be the one that is determined inside of the controller function. But how to create a proper response?

My approach looks like this:

import Vapor

final class ImageController {
    func read(_ req: Request) throws -> Future<Data> {
        let directory = DirectoryConfig.detect()
        let promise = req.eventLoop.newPromise(Data.self)
        req.eventLoop.execute {
            do {
                let data = try Data(contentsOf: URL(fileURLWithPath: directory.workDir)
                    .appendingPathComponent("Public", isDirectory: true)
                    .appendingPathComponent("image.png"))
                promise.succeed(result: data)
            } catch {
                promise.fail(error: error)
            }
        }
        return promise.futureResult
//        try req.content.encode(data, as: .png)
    }
}

But it seems to me I'm overcomplicating it, do I?

like image 207
Marc Avatar asked Dec 13 '22 15:12

Marc


2 Answers

But how to create a proper response?

Directly create a Response and set the MediaType: request.makeResponse(data, as: MediaType.png)

Example:

struct ImageController: RouteCollection {
    func boot(router: Router) throws {
        let imageRoutes = router.grouped("images")
        // GET /images/get-test-image
        imageRoutes.get("get-test-image", use: getTestImage)    
    }

    func getTestImage(_ request: Request) throws -> Response {
        // add controller code here 
        // to determine which image is returned
        let filePath = "/path/to/image18.png"
        let fileUrl = URL(fileURLWithPath: filePath)

        do {
            let data = try Data(contentsOf: fileUrl)
            // makeResponse(body: LosslessHTTPBodyRepresentable, as: MediaType)
            let response: Response = request.makeResponse(data, as: MediaType.png)
            return response
        } catch {
            let response: Response = request.makeResponse("image not available")
            return response
        }
    }
}
like image 128
l --marc l Avatar answered Feb 11 '23 21:02

l --marc l


Two additional approaches:

  1. A route using Leaf to deploy the image:

    route.get("/my/random/route") {
         request -> Future<View> in
         return try request.view().render("image", ["imgname":"image.png"])
    }
    

With image.leaf containing:

<img src="#(imgname)">
  1. A re-direct to the original location in Public:

    route.get("/my/random/route") {
        request -> Response in
        return request.redirect(to: "/image.png")
    }
    
like image 27
Nick Avatar answered Feb 11 '23 20:02

Nick