To remain true to the challenge's objective of utilizing Netlify Platform primitives, StoryBlobs doesn't use any external database or storage.
It uses Netlify Blobs not only to store the app's users details and story blobs, but also the story cover images. Of course, the skeptic in me says this might not be ideal for a production load, but we're in it for the fun, right?
So how is everything tied up together? Let's see.
The app uses three different blob namespaces (stores, in Netlify Blobs lingo)
To handle email/password login, for every new user create, 2 entries are added to the users store, one using id as the key, while the other one using email. The latter is used to query against email to check for an existing user. Here is the createUser function.
exportconstcreateUser=async (user:User&{password:string})=>{conststore=getStore(BlobStores.User);constexistingUser=awaitstore.getMetadata(user.email,{consistency:'strong',});if (existingUser){thrownewError('User already exists');}// save with email keyawaitstore.setJSON(user.email,user);// also save with id keyawaitstore.setJSON(user.id,user);};
Write now I'm not doing query against id and have put it for future usage. Old habits die hard you say?
Now you can pretty much guess the login functionality. We fetch the user, verify against the hashed password and done.
Any story consists of one story head (the meta part), and multiple story blobs written by same or multiple people. To organize the head, and other blobs the pattern used is as shown below
// for story headconstkey='<story-slug>'// for story blobsconstkey='<story-slug>/<blob-id>'
Having the above pattern allows me to list all parts of a story using a store list method call with prefix <story-slug>.
While populating the home page feed, we just want the story heads of different stories. To achieve this we can turn on the directories flag while making the store list call.
While publishing a story we first save the image as a blob with a new key of the form of ${cuid}.${image file extension}. Here are the relevant code parts for image handling
Image Upload from Nuxt Frontend
constuploadCover=async ()=>{// selectedFile.value is a File objectif (selectedFile.value){constformData=newFormData();formData.append('file',selectedFile.value);constres=await$fetch('/api/images/upload',{method:'POST',body:formData,});returnres.fileName;}};
Apart from Netlify Blobs, the app uses Netlify Image CDN to optimize image display. To do this, it uses the @nuxt/image package which is integrated with Netlify Image CDN. This makes it easier to do image manipulation on the fly.
Some of the problems I faced during the development of StoryBlobs.
Nuxt Blobs Configuration Context
StoryBlobs is a Nuxt app deployed on Netlify (the whole app is deployed as a Netlify function) yet Netlify Blobs doesn't work out of the box. I got some configuration errors.
As per the Netlify Blobs repo, configuration context can be read automatically from the execution environment. Since that didn't happen, I assume that the server function created for the app is in Lambda Compatibility mode. So I need to call connectLambda(event) method. But the event types are a mismatch.
Instead of putting more effort into finding out a solution, I simply set the NETLIFY_BLOBS_CONTEXT environment variable which is a base64 encoded string created using the below code
constobj={siteId:"<your_site_id>",token:"<your_personal_access_token>"//created from Netlify Dashboard}constval=btoa(JSON.stringify(obj))
Things started working as expected after setting the environment variable.
Do not forget to redeploy if no code was changed.
Lack of Directories flag support for local development
We can use almost every functionality of Netlify Blobs locally by using the Netlify CLI and running the netlify dev command from the app root dir. This sets the needed configuration context for Netlify Blobs.
But the pattern I used above (directories) doesn't work locally. On using the '/' separator locally, I got 500 Status Code from Netlify Blobs. As an alternative, I tried using the '#' as separator and then querying with prefix ${slug}#, but that also didn't work and returned all entries starting with ${slug}. So had to put some workarounds for local testing.
Before we part
Despite the above issues, working with Netlify Blobs was quite smooth. If they can support sorting the listing results natively, and maybe add a bulk get method, one can go quite far using Netlify Blobs :-).
I hope you enjoyed reading the post. Please do say "hi" in the comments section, to keep the conversation going.