Introduction
As I was tinkering around with prestd, I wanted to include a custom header within its response. According to the documentation, this should be as easy as creating the middleware code, and build it.
middleware code
package main
import (
"net/http"
"github.com/urfave/negroni/v3"
)
func FoobarMiddlewareLoad() negroni.Handler {
return negroni.HandlerFunc(func(rw http.ResponseWriter, rq *http.Request, next http.HandlerFunc) {
rw.Header().Add("Foo", "Bar")
next(rw, rq)
})
}
prest.toml
pluginpath="./lib"
[pluginmiddlewarelist]
file = "foobar"
func = "Foobar"
Building
Using a simple go build -o /app/lib/middlewares/foobar.so -buildmode=plugin ./foobar.go yielded several issues
negroni
the negroni dependency is an issue. First it couldn't fetch it, requiring me to perform go mod init and go get github.com/urfave/negroni/v3@v3.1.1 to set it up
build hash
I could then build the plugin, but then the dependencies didn't match when loading the plugin
Waiting for port : to become available...
Plugin/build: starting...
Go build simple plugins in only file!
go build: hello plugin...
Go build complex plugins in folder (with main.go file)!
Plugin/build: ending
Ready hosting to port !
2025/12/02 16:26:26 'warning' adapter is not set. Using the default (postgres)
2025/12/02 16:26:26 'warning' You are running prestd in public mode.
2025/12/02 16:26:26 'warning' command.go:1019 You are running prestd in debug mode.
'prestd' listening on 0.0.0.0:3000 and serving on /
2025/12/02 16:26:26 plugin.Open("lib/middlewares/foobar"): plugin was built with a different version of package github.com/urfave/negroni/v3
Apparently, the prestd binary hides the hash, while the plugin doesn't
# go version -m /usr/bin/prestd
/usr/bin/prestd: go1.23.6
path command-line-arguments
dep github.com/avelino/slugify v0.0.0-20180501145920-855f152bd774
dep github.com/clbanning/mxj v1.8.4
dep github.com/fsnotify/fsnotify v1.9.0
dep github.com/go-viper/mapstructure/v2 v2.4.0
dep github.com/gorilla/mux v1.8.1
dep github.com/gosidekick/migration/v3 v3.0.0
dep github.com/jmoiron/sqlx v1.4.0
dep github.com/lestrrat-go/blackmagic v1.0.3
dep github.com/lestrrat-go/httpcc v1.0.1
dep github.com/lestrrat-go/httprc v1.0.6
dep github.com/lestrrat-go/iter v1.0.2
dep github.com/lestrrat-go/jwx/v2 v2.1.5
dep github.com/lestrrat-go/option v1.0.1
dep github.com/lib/pq v1.10.9
dep github.com/mitchellh/go-homedir v1.1.0
dep github.com/pelletier/go-toml/v2 v2.2.4
dep github.com/pkg/errors v0.9.1
dep github.com/prest/prest/v2 (devel)
dep github.com/rs/cors v1.11.1
dep github.com/sagikazarmark/locafero v0.11.0
dep github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8
dep github.com/spf13/afero v1.15.0
dep github.com/spf13/cast v1.10.0
dep github.com/spf13/cobra v1.10.1
dep github.com/spf13/pflag v1.0.10
dep github.com/spf13/viper v1.21.0
dep github.com/structy/log v0.0.0-20220126205329-1f766c8d0b3c
dep github.com/subosito/gotenv v1.6.0
dep github.com/tidwall/btree v1.7.0
dep github.com/tidwall/buntdb v1.3.2
dep github.com/tidwall/gjson v1.17.0
dep github.com/tidwall/grect v0.1.4
dep github.com/tidwall/match v1.1.1
dep github.com/tidwall/pretty v1.2.1
dep github.com/tidwall/rtred v0.1.2
dep github.com/tidwall/tinyqueue v0.1.1
dep github.com/urfave/negroni/v3 v3.1.1
dep go.yaml.in/yaml/v3 v3.0.4
dep golang.org/x/crypto v0.35.0
dep golang.org/x/sys v0.31.0
dep golang.org/x/text v0.28.0
dep golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
dep gopkg.in/square/go-jose.v2 v2.6.0
build -buildmode=exe
build -compiler=gc
build -ldflags="-s -w"
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
rootÉdb900ab1603d:/app# go version -m /app/lib/middlewares/foobar.so
/app/lib/middlewares/foobar.so: go1.23.6
path command-line-arguments
dep github.com/urfave/negroni/v3 v3.1.1 h1:6MS4nG9Jk/UuCACaUlNXCbiKa0ywF9LXz5dGu09v8hw=
build -buildmode=plugin
build -compiler=gc
build -trimpath=true
build CGO_ENABLED=1
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
more fixes
In order to overcome this, I had to apply additional build parameters and mimic the prestd build 100%:
go mod vendor
go build -trimpath -ldflags "-s -w" -o /app/lib/middlewares/foobar.so -buildmode=plugin ./foobar.go
This got rid of the error, and resulted in another one, which I can't fix :/
2025/12/02 16:15:52 'warning' adapter is not set. Using the default (postgres)
2025/12/02 16:15:53 plugin.Open("lib/middlewares/foobar"): plugin was built with a different version of package internal/goarch
2025/12/02 16:15:53 'warning' You are running prestd in public mode.
2025/12/02 16:15:53 'warning' command.go:1019 You are running prestd in debug mode.
'prestd' listening on 0.0.0.0:3000 and serving on /
final result
after hours of tinkering, I seem to get stuck in some kind of never-ending loop of error after error. The documentation clearly lacks somethings, and the existing 'hello' example doesn't even build (see #875). It would be very useful if a working example can be demonstrated and included in the code base for other to build upon.
Introduction
As I was tinkering around with prestd, I wanted to include a custom header within its response. According to the documentation, this should be as easy as creating the middleware code, and build it.
middleware code
prest.toml
Building
Using a simple
go build -o /app/lib/middlewares/foobar.so -buildmode=plugin ./foobar.goyielded several issuesnegroni
the negroni dependency is an issue. First it couldn't fetch it, requiring me to perform
go mod initandgo get github.com/urfave/negroni/v3@v3.1.1to set it upbuild hash
I could then build the plugin, but then the dependencies didn't match when loading the plugin
Apparently, the prestd binary hides the hash, while the plugin doesn't
more fixes
In order to overcome this, I had to apply additional build parameters and mimic the prestd build 100%:
go mod vendor go build -trimpath -ldflags "-s -w" -o /app/lib/middlewares/foobar.so -buildmode=plugin ./foobar.goThis got rid of the error, and resulted in another one, which I can't fix :/
final result
after hours of tinkering, I seem to get stuck in some kind of never-ending loop of error after error. The documentation clearly lacks somethings, and the existing 'hello' example doesn't even build (see #875). It would be very useful if a working example can be demonstrated and included in the code base for other to build upon.