Skip to content

Releases: go-goyave/goyave

Pre-release v5.0.0-rc1

12 Jan 09:42
19f927b
Compare
Choose a tag to compare
Pre-release
  • 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.
  • Improvements on the embedded resources support:
    • Added a fsutil.Embed.Sub method, allowing to get sub filesystems for embed.FS.
    • fsutil.Embed now accepts fs.ReadDirFS instead of embed.FS
    • The lang package loads from root FS directory instead of forcing resources/lang, unless the FS implements fsutil.WorkingDirDS

Pre-release v5.0.0-preview7

04 Dec 10:19
49f4407
Compare
Choose a tag to compare
Pre-release

Breaking changes are marked with a ⚠️.

  • ⚠️ testutil: removed the route registrer parameter from NewTestServer and NewTestServerWithOptions
  • 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() and UpdatePageInfo() now return an error instead of gorm.DB

Pre-release v5.0.0-preview6

10 Nov 14:48
0940170
Compare
Choose a tag to compare
Pre-release
  • Removed requirements to implement fsutil.FS for fsutil.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 the auth package.

Pre-release v5.0.0-preview5

08 Nov 14:28
6cf5741
Compare
Choose a tag to compare
Pre-release

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, use goyave.New(goyave.Options{Config: cfg}) instead.
  • testutil.NewTestServerWithConfig(t, cfg, routeRegistrer) becomes testutil.NewTestServerWithOptions, options, routeRegistrer). By default, the test servers use osfs.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 of fs.ReadDirFS and fs.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 keys
    • auth.NewJWTService(config) becomes auth.NewJWTService(config, fs)
    • By default, and when added automatically by the JWTController, the service uses osfs.FS.
  • Language loading now takes a fsutil.FS parameter
    • lang.Languages.Load(language, path) becomes lang.Languages.Load(fs, language, path)
    • lang.Languages.LoadLoadAllAvailableLanguages() becomes lang.Languages.LoadLoadAllAvailableLanguages(fs)
    • lang.Languages.LoadDirectory(directory) becomes lang.Languages.LoadDirectory(fs, directory)
  • Response.File(path) and Response.Download(path, fileName) become Response.File(fs, path) and Response.Download(fs, path, fileName)
  • Router.Static(uri, directory, download) becomes Router.Static(fs, uri, directory, download)
  • fsutil.File.Save(path, name) becomes fsutil.File.Save(fs, path, name)
  • fsutil.GetMIMEType(file) becomes fsutil.GetMIMEType(fs, file)
  • fsutil.FileExists(file) becomes fsutil.FileExists(fs, file)
  • fsutil.IsDirectory(path) becomes fsutil.IsDirectory(fs, path)
  • fsutil.Delete(path) was removed. Use osfs.FS.Remove() instead.
  • testutil.WriteMultipartFile(writer, path, fieldName) becomes testutil.WriteMultipartFile(writer, fs, path, fieldName)
    • testutil.CreateTestFiles(file1, file2) becomes testutil.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 removed context.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

18 Oct 13:45
40b33f5
Compare
Choose a tag to compare
Pre-release
  • Use goyave.dev/copier, which is a fork of jinzhu/copier. This fixes a few issues in the original library.
  • Added the ability to get and replace a request's context.Context using request.Context() and request.WithContext().
  • typeutil.Undefined now implements Scan, allowing it to be copied both ways.
  • typeutil.Undefined now allows non-pointer types to implement CopyValue() and Value()
  • Slog: change default output to os.Stderr
  • Configuration: rename server.websocketTimeout to server.websocketCloseTimeout so it is more expressive.
  • Setting configuration entry server.port to 0 will now assign an automatically chosen port. The actual port used can be retrieved with server.Host() or server.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

08 Sep 13:55
9b4288e
Compare
Choose a tag to compare
Pre-release

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 that Printf, Println, etc are not available anymore. You can now use Debug, Info, Warn, Error instead.
  • Component.AccessLogger() and Component.ErrLogger() are removed.
  • database.New() now takes a func() *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

02 Aug 14:08
5b3d5c1
Compare
Choose a tag to compare
Pre-release

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 uses copier
  • 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

29 Jun 16:36
ad8f057
Compare
Choose a tag to compare
Pre-release

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

09 Jun 14:45
61a17f5
Compare
Choose a tag to compare
  • Fixed panic when parsing a multipart form containing an empty file.

Release v4.4.10

11 May 09:46
18fd161
Compare
Choose a tag to compare
  • Fixed potential SQL errors when using the unique/exists validation rules #191
  • Updated dependencies
  • Dropped support for go 1.17