Using A Wildcard Route Param to Download Storage Images

In this lesson, we'll learn how we can utilize a wildcard route parameter to dynamically download images that've been uploaded and stored within our application storage.

Published
Jun 20, 24
Duration
7m 57s

Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.

Adocasts

Burlington, KY

🕰️ Chapters
00:00 - Refactoring Our Avatars Route as a Generic Storage Route
02:05 - Inspecting Wildcard Route Parameters
03:00 - Getting Requested Image File Path
03:25 - Reviewing the File Upload Documentation
04:30 - Normalizing and Testing the File Path Validity
05:38 - Downloading the Requested Image
06:02 - Accessing Our Images
07:06 - Testing Our Storage Download Route

Join The Discussion! (8 Comments)

Please sign in or sign up for free to join in on the dicussion.

  1. Commented 21 days ago

    Hello,

    When I try to access uploaded file, for example /storage/avatars/filename.png, without a route or controller, the file displays just fine. The StorageController isn’t called.

    Finally, I get this error when I try to delete a movie’s poster : 'ENOENT: no such file or directory, unlink', I think the error comes from this line: 'await unlink(app.makePath('storage', movie.posterUrl))'. The generated path seems to be incorrect.

    But I don’t understand why it seems to work for you.

    1

    Please sign in or sign up for free to reply

    1. Commented 20 days ago

      Hi Gribbl!

      If you're able to directly access the file via the URL without going through a route definition, that leads me to believe the file is actually within your public directory. Files within this directory are made accessible by the AdonisJS static file server.

      That would also explain the "no such file" error on the attempted deletion, as app.makePath('storage') is going to be looking in the ~/storage directory directly off your application root, not within the public directory.

      Can't say for certain though - just making an educated guess based on the info provided.

      Hope this helps!

      1

      Please sign in or sign up for free to reply

      1. Commented 19 days ago

        I don’t have a public directory, only storage at the root of the project.

        The line router.get('/storage/*', [StorageController, 'show']).as('storage.show') is commented, and I can still access my downloaded files in that directory. 🤔

        And for file deletion, it seems like the makePath method generates the following path: .../storage/storage/posters/filename.png since posterUrl also contains /posters . So, I used app.makePath('.', movie.posterUrl) instead, and it works. 😁

        1

        Please sign in or sign up for free to reply

        1. Commented 15 days ago

          Sorry for the delayed response! Are you able to share the repo url? Neither should be the case, and I can't immediately think of anything that would cause either of those.

          1

          Please sign in or sign up for free to reply

          1. Commented 13 days ago

            No problemo.

            That's strange. I have the exact same code as you. But just to confirm, if I understood correctly (and correct me if I'm wrong), when we save a movie's poster, we use the following lines in the movie service:

             await poster.move(app.makePath('storage/posters'), {
                  name: fileName,
                })
            
            return `/storage/posters/${fileName}`
            Copied!

            So, the file is saved at storage/posters, and in the database, poster_url will have the value /storage/posters/filename.png.

            And when we want to delete the poster, we do this:

            await unlink(app.makePath('storage', movie.posterUrl))
            Copied!

            So, the generated path will contain storage twice. As a result, since no file is located in storage/storage/posters, the deletion will not work. Right? Or did I misunderstand?

            1

            Please sign in or sign up for free to reply

            1. Commented 13 days ago

              I'm so sorry, my head was in the wrong spot! You're absolutely right, the /storage gets added to the saved value in the database so the unlink should be:

              await unlink(app.makePath('.', movie.posterUrl))
              Copied!

              Terribly sorry for the confusion there! I'll make a note to correct this lesson.

              1

              Please sign in or sign up for free to reply

              1. Commented 12 days ago

                No problem at all. Thank you for your response.😊

                1

                Please sign in or sign up for free to reply

                1. Commented 10 days ago

                  Anytime! 😊

                  0

                  Please sign in or sign up for free to reply