Updates on 2022/4/9

The anticipation of knowing that something you're capable of building can solve a problem you've been struggling with for a long time, but you can't actually see it work until you build it.

A full file/object storage service in ~30 lines of Oak!

with server.route('/blob/:fileName') fn(params) fn(req, end) if req.method {
        'GET' -> with fs.readFile(path.join(BlobDir, params.fileName)) fn(file) if file {
                ? -> end(http.NotFound)
                _ -> end({
                        status: 200
                        headers: { 'Content-Type': http.mimeForPath(params.fileName) }
                        body: file
                })
        }
        'POST' -> if ext := params.fileName |> str.split('.') |> std.last() |> str.lower() {
                'jpg', 'jpeg', 'png', 'svg', 'gif', 'gifv' -> {
                        blobPath := crypto.uuid() + '.' + ext
                        with fs.writeFile(path.join(BlobDir, blobPath), req.body) fn(res) if res {
                                ? -> end({
                                        status: 500
                                        headers: { 'Content-Type': http.MimeTypes.txt }
                                        body: 'could not save blob'
                                })
                                _ -> end({
                                        status: 201
                                        headers: { 'Content-Type': http.MimeTypes.txt }
                                        body: blobPath
                                })
                        }
                }
                _ -> end({
                        status: 400
                        headers: { 'Content-Type': http.MimeTypes.txt }
                        body: 'unsupported file type'
                })
        }
        _ -> end(http.MethodNotAllowed)
}

I wrote this as a part of my work to add file upload/attachment support to Lig3, but I might pull this out as a separate cross-app service for my personal infrastructure because it's so simple and it's something every app needs at some point.