DEV Community

Cover image for Creating your own ExpressJS from scratch (Part 5) - Serving static files
Wesley Miranda
Wesley Miranda

Posted on

Creating your own ExpressJS from scratch (Part 5) - Serving static files

Our Web Framework so far can create a REST API, but cannot serve files yet, we need to implement it to make the framework complete.

To serve files we are going to use the Streams concept to read the files and serve to the client.

If you want to know more about NodeJS Streams take a look at it here

Let's go!


Reading files and folders

src/app.js

// (1)
const { readdir } = require('fs/promises')
const { statSync, createReadStream } = require('fs')
const path = require('path')
const { pipeline } = require('stream/promises')

// (2)
async function* getAllStaticFiles(folder) {

    const files = await readdir(folder)
    for (const file of files) {
        const absolutePath = path.join(folder, file)
        if (statSync(absolutePath).isDirectory()) {
            yield* getAllStaticFiles(absolutePath)
        }
        else {
            yield absolutePath
        }
    }
}

// (3)
const static = async (folderPath) => {
    let folderRelative = folderPath.replace('./', '')
    for await (const file of getAllStaticFiles(folderPath)) {
        const pathWithoutBase = file.replace(folderRelative, '')
        get(pathWithoutBase, async (req, res) => {
            const relativePath = path.join(__dirname, '..', file)
            const fileStream = createReadStream(relativePath)
            res.setHeader('Content-Type', file.split('.').filter(Boolean).slice(1).join('.'))
            return await pipeline(fileStream, res)
        })
    }
}

// (4)
return {
    run,
    get,
    post,
    patch,
    put,
    del,
    use,
    useAll,
    useRouter,
    static
}
Enter fullscreen mode Exit fullscreen mode

From the code sessions above

1 - To read files and folders and deal with Streams we need to import fs and stream libraries.

2 - Here we are reading files and folders' paths recursively using a generator pattern to make the reader be ordered.

3 - For each file path found we are going create a new GET route, read the file path as a Stream, and pass the Stream to the response object. If you didn't know the response object is a Writable Stream.

4 - Exporting the static function.

Testing

Now we can call the static function passing the folder path that contains the files we want to serve.

index.js

app.static('./files')

const start = async () => {
    app.run(3000)
}

start()
Enter fullscreen mode Exit fullscreen mode

To test I will create a folder structure with a file like that.

files/folder1/file.json

{
  "test": "test"
}
Enter fullscreen mode Exit fullscreen mode

If I run the app and try to access the path localhost:3000/folder1/file.json, I can see the content inside it.

You can see herehow the code is looking.

See you in the next tutorial to improve our Web Framework, we are going to create a body-parser middleware.

I hope you like it!

Top comments (2)

Collapse
 
hudsonpufferfish profile image
Hudson Nguyen

wow can't wait for next part!!!!

Collapse
 
wesleymreng7 profile image
Wesley Miranda