fiber icon indicating copy to clipboard operation
fiber copied to clipboard

🐛 [Bug]: staticConfig.FS won't accept http.FileSystem in v3

Open idearat opened this issue 1 year ago • 3 comments

Bug Description

v3 removes the filesystem middleware and replaces it with static saying that static now does everything filesystem used to, however, you can't provide an http.FileSystem to the static.Config.FS parameter (what used to be 'Root'.

How to Reproduce

Steps to reproduce the behavior:

See the code snippets for a "v2 that works" and "v3 that doesn't" sample.

Expected Behavior

You should be able to replace filesystem.Config with static.Config without having to alter how you construct the embed you pass to it from an http.FileSystem to a non-http.FileSystem.

Template package Version

v3.0.0-beta.3

Code Snippet (optional)

Here's what worked in V2:



package main

import (
    "fmt"
    "log"
    "os"
    "embed"
    "io/fs"
    "net/http"

    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/filesystem"

    "github.com/goccy/go-json"
)

// Embed the build directory from the frontend.
//go:embed public/*
var BuildFs embed.FS

// Get the subtree of the embedded files with `build` directory as a root.
func BuildHTTPFS() http.FileSystem {
    public, err := fs.Sub(BuildFs, "public")
    if err != nil {
        log.Fatal(err)
    }
    return http.FS(public)
}

func handleHello(c *fiber.Ctx) error {
    return c.JSON(fiber.Map{"message": "hello from the fiber server"})
}

func main() {
    app := fiber.New(fiber.Config{
        JSONEncoder: json.Marshal,
        JSONDecoder: json.Unmarshal,
    })

    app.Get("/*", filesystem.New(filesystem.Config{
        Root:         BuildHTTPFS(),
        NotFoundFile: "404.html",
    }))

    app.Get("/hello.json", handleHello)

    log.Fatal(app.Listen(fmt.Sprintf(":%s", os.Getenv("APP_PORT"))))
}

The minimal changes I expected based on docs (simply replace filesystem with static... NotFoundFile with NotFoundHandler, etc... won't compile):

package main

import (
    "fmt"
    "log"
    "os"
    "embed"
    "io/fs"
    "net/http"

    "github.com/gofiber/fiber/v3"
    "github.com/gofiber/fiber/v3/middleware/static"

    "github.com/goccy/go-json"
)

// Embed the build directory from the frontend.
//go:embed public/*
var BuildFs embed.FS

// Get the subtree of the embedded files with `build` directory as a root.
func BuildHTTPFS() http.FileSystem {
    public, err := fs.Sub(BuildFs, "public")
    if err != nil {
        log.Fatal(err)
    }
    return http.FS(public)
}

func handle404(c fiber.Ctx) error {
    return c.JSON(fiber.Map{"message": "page not found"})
}

func handleHello(c fiber.Ctx) error {
    return c.JSON(fiber.Map{"message": "hello from the fiber server"})
}

func main() {
    app := fiber.New(fiber.Config{
        JSONEncoder: json.Marshal,
        JSONDecoder: json.Unmarshal,
    })

    app.Get("/*", static.New("", static.Config{
        FS:         BuildHTTPFS(),
        NotFoundHandler: handle404,
    }))

    app.Get("/hello.json", handleHello)

    log.Fatal(app.Listen(fmt.Sprintf(":%s", os.Getenv("APP_PORT"))))
}

Here's the error which references the "API change" that's not something I expected:

ss 󰁔 go run main.go                                      v1.22.4 4m39s411ms
# command-line-arguments
./main.go:45:21: cannot use BuildHTTPFS() (value of type http.FileSystem) as fs.FS value in struct literal: http.FileSystem does not implement fs.FS (wrong type for method Open)
		have Open(string) (http.File, error)
		want Open(string) (fs.File, error)



### Checklist:

- [X] I agree to follow Fiber's [Code of Conduct](https://github.com/gofiber/fiber/blob/master/.github/CODE_OF_CONDUCT.md).
- [X] I have checked for existing issues that describe my problem prior to opening this one.
- [X] I understand that improperly formatted bug reports may be closed without explanation.

idearat avatar Sep 15 '24 18:09 idearat

Moving to core, doesnt belong here.

gaby avatar Sep 15 '24 18:09 gaby

Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

welcome[bot] avatar Sep 15 '24 18:09 welcome[bot]

@idearat Why not use BuildFs directly in static.Config, it's supported. What benefit you get from adding http.FileSystem?

gaby avatar Sep 15 '24 23:09 gaby

@idearat any updates?

efectn avatar Dec 05 '24 06:12 efectn

You can use fs.Sub directly without converting it to http.FS. New static middleware accepts fs.FS as FS config property. I don't think you need that part.

efectn avatar Dec 05 '24 06:12 efectn

Tested, it works.

package main

import (
	"embed"
	"io/fs"
	"log"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/middleware/static"
)

// Embed the build directory from the frontend.
//
//go:embed fiber/* fiber/public/*
var BuildFs embed.FS

// Get the subtree of the embedded files with `build` directory as a root.
func BuildHTTPFS() fs.FS {
	public, err := fs.Sub(BuildFs, "fiber/public")
	if err != nil {
		log.Fatal(err)
	}

	return public
}
func main() {
	app := fiber.New(fiber.Config{})

	app.Get("/*", static.New("", static.Config{
		FS:     BuildHTTPFS(),
		Browse: true,
	}))

	log.Fatal(app.Listen(":3000"))
}

efectn avatar Dec 05 '24 06:12 efectn