Return static files from the server
Is there a possibility to return files from the server app using
res.sendFile()
?
If so, how would you include the assets folder in the output directory and reference it from the code?
The functionality i want to achieve is to return an image based on some db calculated data. Its a small set of images, so a whole external image storage seems like overkill as its supposed to be around 6 images.18 Replies
depending on your implementation, you might need to use
import.meta.url
to get the directory, as wasp outputs compiled files in a different path than your root src
but what you're mainly looking for is setting up a custom API that doesn't depend on Entities, nor operations, allowing you to use e.g. res.sendFile()
: https://wasp-lang.dev/docs/language/features#apisThank you for your very quick response!
Yes exactly i am trying to setup a custom api like following code:
and i have my image stored here:
But that entire folder is not copied to the output folder when the project is built, so there is no way, this code could ever work. Or what am i missing?
is the wasp server running?
wasp start
?yes π
Wohooo @Gwaggli, you just became a Waspeteer level 1!
ah. try putting the folder in ./src/shared
actually, that shouldn't matter. If they are in
src/server/assets
they will get compiled to the .wasp/out
folder
and then all you'll have to do is give the relative path. so if your api file is in the src/server folder then just make the path const ASSETS_DIR = './assets'
;
Ah i see now, yes it does get compiled into the output folder inside the ext-src folder.
So i got it to work with:
and then with the relative path
./assets/image.png
Seems a little hacky tho, is there no cleaner way? As my code now relies on some wasp-internal file structuring
While this code works locally, it doesnt seem to work on the fly.dev server. As there is no src
folder on the fly machine but only the dist
folder which does not contain the assets
folder.You can do that via
api
feature that @Vinny (@Wasp) shared, there you can direclty define your Express routes, like the one you described. You will have to figure out the details on your own, but it shouldn't be anything particularly Wasp specific. If you get stuck, ping us.
One thing though -> where will you store files? Are they always the same, or are they re-calculated every so and so? The thing is, if you are storing at the file system of where your server is running, then it depends on where you will host the app -> it will be important that they guarantee the file system to be permanent, or at least the part of it where you will store the files.
Other options are S3 or something similar, as you mentioned, or even storing the images in the DB if you have only a couple. Finally, they could be living even on the frontend possibly, as static assets.
I think it would be useful to understand the lifecycle of these images, for us to be able to maybe help a bit more -> are they completely static and you have them already know, are they created per user, ... .
You said they are calculated from the db, but I am not sure what that means -> at which moment, and how often?Yeah @martinsos asks good questions, because it seems in this code youβre trying to access this file path from the client perhaps?
Thank you for your help! I try to explain in more detail what I want to achieve:
I need to have an API (which I set up and is reachable from the outside world) that returns an image for a product based on its score.
So I would call let's say
server.fly.dev/static-files/:productId
and then calculate the score of that product based on some data stored in the DB and depending on the score (0-6) the API would return one of 6 images that all are static and won't change.
Here is the code i have for now:
This code works fine while working locally, but having declared my root
with ../../../src/ext-src
seems horribly wrong and doesn't work once deployed to fly.
While the asset
folder in question gets copied into /.wasp/out/server/src/ext-src
(inside the src
folder) it does not get copied anywhere inside the dist
(/.wasp/out/server/dist/
) folder. (that's why I tried to declare the root
to be in src/ext-src
) On the deployed fly machine there is no src
folder tho and thus the whole assets folder is missing.
So my file structure looks like this:
The path to the api file inside the dist
folder is: .wasp/out/server/dist/ext-src/api/product.js
The path to the api file inside the src
folder is: .wasp/out/server/src/ext-src/api/product.ts
The path to the image file inside the dist
folder is: does not exist
The path to the image file inside the src
folder is: .wasp/out/server/src/ext-src/assets/label.png
I feel like bc there is no compile time reference to the file it is not getting bundled and thus copied to the dist folder, could that be?Yes, your last sentence is very correct! There is no import of those files, nothing to tell bundler they are important, so it ignores them.
Ok, so to rehash, you need an API route that respond with one of the 6 images that you know and have prepared.
You tried to put them into some "assets" folder in the server, but failed.
You could put them on S3 or even in the DB, but that feels like an overkill since you have only 6 images -> I agree with that.
I think approach with "assets" folder is reasonable, and we should look into enabling you to do that.
I know that on frontend you can actually import those png images in your code, via
import
. I am not 100% sure if you can do that on backend, I think not so hm, but if you could give that a try that could be interesting.
If not, then I think it is on us really to ensure we provide you with a way to provide static assets -> we could make it so that Wasp has a directory "public" or "assets" in server where any files can be put and they will certainly be included in the server when bundled.
@miho what do you say about this, any other ideas?@Gwaggli are the 6 photos secret and that's why you are sending them via backend?
If they are not, you could:
1. upload them to some 3rd party storage and just send the link from the backend
2. keep them in your frontend and make a switch case on the frontend
`backend says "Score is 5" -> frontend shows the photo for "score 5"
@miho what if they still wanted to share them from the server, via API, and they wanted to store them on the server for that purpose -> is there any easy way to include them in the server code? Kind of like public assets, but on the server side? They can just put it in the code because it seems bundler (actually, typescript compiler I guess?) drops those hm.
Recreating the issue locally helped me understand the issue a bit better.
- create a file in
server/media/file.txt
- Wasp copied over files from server
to <serverApp>/src/ext-src
- Wasp builds the app -> but only TS and JS files are transpiled and copied -> no media
folder or file.txt
in the built app
- Wasp deploys the app -> it only takes the build artifiacts i.e. not the media
folder or file.txt
For now, we can't help with this other then what I mentioned above:
- host it on S3 (a bit an overkill but it should work)
- return names from server, but keep the files in the frontend code (if the file contents are not secret)
π‘ In the future we should introduce a media
folder (well known idea in other frameworks) which would be copied over when deploying, maybe even served statically so users can access it via /media/<filename>
?
@martinsos do we have an issue for this already?We have this one: I will add this into to it! https://github.com/wasp-lang/wasp/issues/609
Added: https://github.com/wasp-lang/wasp/issues/609#issuecomment-1572189300 .
@Gwaggli to summarize: We don't currently have a way to do it by adding those files to server/ source code, but will have in the future.
In the meantime solution is either external hosting (S3, some image hosting), DB, or as static files on frontend (if you don't really need them in the api but just on frontend).
Thank you very much guys for analyzing! So for now I will probably go for 3rd party solution. But would definitely be nice to have this in the future π
The reason I don't really wanna add it to the frontend itself is that this API would be supposed to be called from external websites to display it directly on their websites.
Sure, I guess that makes sense!
Then third party is probably the best option, as services for hosting images usually have fast response times and caches and stuff, and your API can instead just respond with the link to such image. Also, it will result in less load on your server (otherwise your server would need to be sending those images quite often).