Releases: go-goyave/goyave
Pre-release v5.0.0-rc1
- Added new server options
- Added config entry
server.readHeaderTimeout
which represents the amount of time allowed to read request headers. - Added
Options.BaseContext
, allowing to define the base context for the server. - Added
Options.ConnContext
, allowing to modify the context used for new client connections. - Added
Options.ConnState
, allowing to get notified when the client connection state changes. - Added
Options.MaxHeaderBytes
, which controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line.
- Added config entry
- Improvements on the embedded resources support:
- Added a
fsutil.Embed.Sub
method, allowing to get sub filesystems forembed.FS
. fsutil.Embed
now acceptsfs.ReadDirFS
instead ofembed.FS
- The lang package loads from root FS directory instead of forcing
resources/lang
, unless the FS implementsfsutil.WorkingDirDS
- Added a
Pre-release v5.0.0-preview7
Breaking changes are marked with a
⚠️ testutil: removed the route registrer parameter fromNewTestServer
andNewTestServerWithOptions
- Redirect the default test server logger to
testing.T.Log()
- Added the new
util/session
package for business transaction management. - Validation: the email validator now converts the value to string instead of
mail.Address
to improve the experience with DTO conversion.mail.Address
was serialized as a struct instead of a string. - Paginator: the page info query and the actual query are now executed in a transaction.
⚠️ Paginator:Find()
andUpdatePageInfo()
now return an error instead ofgorm.DB
Pre-release v5.0.0-preview6
- Removed requirements to implement
fsutil.FS
forfsutil.WorkingDirFS
,fsutil.MkdirFS
,fsutil.WritableFS
,fsutil.RemoveFS
- Fixed
RouteParams
were emptied if the matched route doesn't have parameters but its parents do. - Fixed error trace added twice as an attribute in slog when logging
*errors.Error
having a reason of type*errors.Error
. Only the correct trace is printed now. - Validation: the request context is now automatically attached to the DB in the validation middleware.
- Extra in request and validation are now using typed keys instead of strings. You can now (and you are encouraged to) use comparable structures as keys.
ExtraJWTClaims
key has been moved to theauth
package.
Pre-release v5.0.0-preview5
Server options
When creating a new server with goyave.New()
, you can now pass a goyave.Options
structure that will override the default values. Currently, you can replace the automatically loaded config, the logger and provide a file system to load the language files. You can find out more about this in the section below.
Adding a structure as parameter is flexible from an API point of view, as more options can be added without breaking changes. For developers, it is easier to use and more intuitive than to manually replace those elements after creating the server. This also removes unnecessary startup operations in case developers want to replace those components.
This change is breaking compared to the preview pre-release version of the framework.
goyave.NewWithConfig()
was removed, usegoyave.New(goyave.Options{Config: cfg})
instead.testutil.NewTestServerWithConfig(t, cfg, routeRegistrer)
becomestestutil.NewTestServerWithOptions, options, routeRegistrer)
. By default, the test servers useosfs.FS
.
File systems
All features using files in some way have been revisited and improved to take full advantage of the standard io/fs
package. All future components of the framework will be designed with this in mind. The util/fsutil
package now defines a few useful interfaces in addition to standard ones in io/fs
.
fsutil.FS
: combination offs.ReadDirFS
andfs.StatFS
.fsutil.WorkingDirFS
fsutil.MkdirFS
fsutil.WritableFS
fsutil.RemoveFS
The fsutil.Embed
structure allows easy implementation of fs.StatFS
on embed.FS
:
//go:embed resources
var resources embed.FS
func main() {
resourcesFS := fsutil.Embed{FS: resources}
}
A new package util/fsutil/osfs
contains an implementation of the OS filesystem. This structure is just a proxy to the standard os
package so it can be passed around as an interface parameter.
Below is a list of features that can now take advantage of this abstraction. These changes introduce breaking changes compared to the preview pre-release version of the framework.
auth.JWTService
now takes a file system for loading the signing keysauth.NewJWTService(config)
becomesauth.NewJWTService(config, fs)
- By default, and when added automatically by the
JWTController
, the service usesosfs.FS
.
- Language loading now takes a
fsutil.FS
parameterlang.Languages.Load(language, path)
becomeslang.Languages.Load(fs, language, path)
lang.Languages.LoadLoadAllAvailableLanguages()
becomeslang.Languages.LoadLoadAllAvailableLanguages(fs)
lang.Languages.LoadDirectory(directory)
becomeslang.Languages.LoadDirectory(fs, directory)
Response.File(path)
andResponse.Download(path, fileName)
becomeResponse.File(fs, path)
andResponse.Download(fs, path, fileName)
Router.Static(uri, directory, download)
becomesRouter.Static(fs, uri, directory, download)
fsutil.File.Save(path, name)
becomesfsutil.File.Save(fs, path, name)
fsutil.GetMIMEType(file)
becomesfsutil.GetMIMEType(fs, file)
fsutil.FileExists(file)
becomesfsutil.FileExists(fs, file)
fsutil.IsDirectory(path)
becomesfsutil.IsDirectory(fs, path)
fsutil.Delete(path)
was removed. Useosfs.FS.Remove()
instead.testutil.WriteMultipartFile(writer, path, fieldName)
becomestestutil.WriteMultipartFile(writer, fs, path, fieldName)
-
testutil.CreateTestFiles(file1, file2)
becomestestutil.WriteMultipartFile(fs, file1, file2)
Using this abstraction is beneficial in many ways for maximum flexibility:
- It is easily possible to serve remote resources, such as static assets stored on a cloud storage bucket
- It is possible to take advantage of the embedding capabilities of Go, be it for language files, or static assets. Bundling your executable will require less external resources.
It is advised to expose the file systems through a service so all components have centralized and easy access to them.
Misc
- Removed default values for database configuration. Previously, they were defaults for the MySQL DB engine. The framework had no reason assuming this engine should be the default.
- New exported readonly field
validation.Context.Invalid
, making it easier to unit-test validators that use the now removedcontext.Valid()
method. - In the log middleware, the slog attributes are ignored to reduce clutter. The message itself is enough.
- The internal config loader has been refactored to use
io/fs
too so it's future-proof. - Avoid duplicate CORS middleware if the middleware is already defined as a global middleware.
Pre-release v5.0.0-preview4
- Use
goyave.dev/copier
, which is a fork ofjinzhu/copier
. This fixes a few issues in the original library. - Added the ability to get and replace a request's
context.Context
usingrequest.Context()
andrequest.WithContext()
. typeutil.Undefined
now implementsScan
, allowing it to be copied both ways.typeutil.Undefined
now allows non-pointer types to implementCopyValue()
andValue()
- Slog: change default output to
os.Stderr
- Configuration: rename
server.websocketTimeout
toserver.websocketCloseTimeout
so it is more expressive. - Setting configuration entry
server.port
to0
will now assign an automatically chosen port. The actual port used can be retrieved withserver.Host()
orserver.Port()
. - Added back the
websocket
package and upgraded it for v5. The example project has a v5 branch showcasing how to use the feature.
Pre-release v5.0.0-preview3
Unified structured logging
This preview release entirely revamps how logging is handled in a Goyave application. Instead of having multiple std *log.Logger
, a Goyave server now uses a unified *slog.Logger
with some added features. This implementation is based on the standard library log/slog
and maintains compatibility with it. All logs, including the logs generated by Gorm, will all be processed by this new single logger.
By default, the handler used depends on the configuration entry app.debug
. If the debug is enabled, a dev mode log handler is used. This will format logs in a human-readable way. Otherwise the standard JSON handler is used.
Custom handlers are supported: the logger can be replaced entirely when initializing the server.
This change further improves the error handling done in v5.0.0-preview2
. All errors will have additional attributes added into the log entry.
Access logging (using Goyave's log
package and middleware) was also changed to support structured logging and provide useful information.
Breaking changes
Component.Logger()
returns*slog.Logger
instead of*log.Logger
. This means thatPrintf
,Println
, etc are not available anymore. You can now useDebug
,Info
,Warn
,Error
instead.Component.AccessLogger()
andComponent.ErrLogger()
are removed.database.New()
now takes afunc() *slog.Logger
as a parameter. It is a function returning a logger instead of a logger directly, allowing the server logger to be replaced.- Validation components also only have one
*slog.Logger
.
Architecture
The service/repository architecture has been slightly changed.
- The
Init()
function has been removed. - It is encouraged to use interfaces to represent repositories inside services instead of the actual implementation. This removes coupling between the two and makes testing easier. This also completely detaches the domain logic and database layer from the HTTP layer.
- Repositories and services are now initialized in
main.go
. This makes for a more verbose main function, but is a good improvements for code quality. - It is encouraged to initialize services and repositories using a
New()
function.
Misc
- Fixed a bug in model mapping when copying
typeutil.Undefined
into a normal field. - The error logger of the underlying
http.Server
now always prints to the new unified logger, even if it is replaced. - The built-in
auth.JWTService
has been updated to the new service architecture. - You may need to add the following replace directive in your go.mod for the project to compile:
replace github.com/jinzhu/copier v0.3.6-0.20230809063302-70b1d4e41a98 => github.com/System-Glitch/copier v0.0.0-20230810143212-ca7f7fa385a2
This is temporary and will not be needed on future releases.
Full Changelog: v5.0.0-preview2...v5.0.0-preview3
Pre-release v5.0.0-preview2
Error handling
Added the new package util/errors
providing custom error type collecting useful information on errors (such as the caller frames) and improved handling of JSON marshaling.
Using these errors (*errors.Error
) will help better pin-point the exact location an error has occurred instead of having to panic. Error handling will be more idiomatic as a result: functions returning errors, those errors wrapped/chained then brought down the stack. The additional information can be used for error tracking/reporting as well.
All the errors returned and panics from the framework's components now use this system. You can expect errors that are more informative from now on. Error handling of several built-in functions have been improved.
It is recommended to wrap your errors (or those returned by libraries) as early as possible to get the more accurate results.
This system also supports error wrapping, and can wrap many errors into one.
import "goyave.dev/goyave/v5/util/errors"
//...
result, err := somelib.Func()
if err != nil {
return nil, errors.New(err)
}
Errors related to the request life-cycle are now stored in the Response
and accessible using response.GetError()
. Errors gathered this way are ensured to be *errors.Error
. They were previously stored in request.Extra[ExtraError]
and weren't type-safe.
goyave.Error
and defined exit codes have been removed. Exit codes weren't providing a lot of value compared to the unnecessary complexity brought by the custom error type. The error log is what really gives information. Developers can still define exit codes as they see fit. Errors returned by goyave.New()
are now *errors.Error
Misc
- Removed
sliceutil
,reflectutil
packages - Fixed panic status handler attempting to write to hijacked connections
- The recovery middleware now forces override of the HTTP status to 500. This prevents empty 200 responses if an error occurs before writing the body (such as trying to JSON marshal an unsupported type).
- Cleanup of old unused resources
- Added tests for the
testutil
package - Removed
mergo
from the dependencies.database.Factory
now usescopier
- Added
typeutil.Copy()
allowing to copy a DTO's non-zero fields into a model. This is useful for full-state updates for example.
Pre-release v5.0.0-preview1
v5.0.0-preview1 is finally here!
It's been over a year since I started working on v5. It was hard finding time to dedicate to the project but here we are, at last!
Disclaimer
Stability
This pre-release if a preview version of the v5. There is still a lot of work to do before it is ready: expect breaking changes and API instability. The goal of this pre-release is to start experimenting with the framework reborn, solve possible blocking points, smooth out the experience, fix potential bugs, etc. This is the perfect time to play with it and provide feedback, which is always greatly appreciated. I don't recommend starting building production applications with this preview version.
The current code is entirely tested but this doesn't mean every possible bug or use-case has been tested. I did my best to make the tests as complete as possible.
Here is a non-exhaustive list of topics that are going to be worked on next:
- Error handling and better support for error reporting services
- Support for
io.FS
for everything file-related. - Support for embeds for config, language files, etc
- The default database engine will be changed from MySQL to PostgreSQL as it better represents the type of application that Goyave targets
- Native handlers compatiblity layer
- Websocket support
- Logging improvements and flexibility
- DTO to Model mapping
- First party libraries (such as
goyave.dev/filter
) support for v5
Documentation
The technical documentation is available on go.pkg.dev and only misses a few more advanced topics. However, there is currently no extra documentation like what you can find on goyave.dev for v4. I am sorry that I am not able to provide a complete documentation with in-depth concept explanation and examples as of now.
The changes are so massive that writing a changelog will take time too. An upgrade guide will be available at a later date as well. You can still check them here if you want: v4.4.11...v5.0.0-preview1
As many aspects are still subject to change, maintaining a documentation would require too much work. A complete documentation will come later when we move past the preview stage. If you want help working with it, I will answer your questions over on Discord.
Getting started
The template project has a v5
branch that you can take example on to get started.
Release v4.4.11
- Fixed panic when parsing a multipart form containing an empty file.
Release v4.4.10
- Fixed potential SQL errors when using the
unique
/exists
validation rules #191 - Updated dependencies
- Dropped support for go 1.17