Skip to content

Releases: go-goyave/goyave

Release v5.0.1

13 Jun 14:52
44a81c1
Compare
Choose a tag to compare
  • httputil: fixed a race condition when initializing the quality value regex
  • util/session: improved support for nested transactions

Release v5.0.0

11 Jun 14:55
6cb4cf0
Compare
Choose a tag to compare

Introduction

Goyave v5 has been in the oven for over two years. With the first production applications deployed, a ton of issues and flaws revealed themselves, preventing real long-lived projects from cleanly evolving. The initial goals of the framework started to weaken the more the applications were developed and changed: the strong basis it promised to provide wasn't actually that strong. From this invaluable experience, I decided to go back to the drawing board and redesign the framework.

This new major version is an almost entire rewrite of the framework. In order to limit the frequency of releases containing breaking changes, all accumulated ideas for reworks and improvements that would introduce those were grouped in v5. This new major version not only aims at fixing the outstanding issues and design flaws, but also improves on existing features by upgrading them to the latest available technology. Expect v5 to feel modern and to neatly integrate with all the new language features such as generics, file systems, structured logging, and more.

These release notes will be organized in categories. They will explain the overall change of direction for each area of the framework as well as shortly showcase the new or improved features. The list of changes may be incomplete as many features were rewritten entirely.

Motivations

Among the many aspects that needed to be reworked, some of them stood out and fueled the initial drive to rewrite the framework.

Dependency coupling

Every layer and components of a v4 application had strong dependency coupling. The HTTP, business and database layers were all mixed up together. The framework was systematically imposing a dependency to itself, direct or indirect. Its locked-up architecture, entirely based on globals was hindering the more business-oriented applications. Those struggled to detach their domains from the rest of the application, and encountered obstacles every time they needed to handle more complex business logic.

For example: to access the database, you were forced to use the framework, which was loaded from a configuration system that also was handled by the framework. This created a long chain of dependencies that was hard to separate from the rest, even more so when it came to writing tests.

On top of that, the all-global architecture required a ton of synchronization, which were detrimental to the overall performance of the application.

Locked architecture

All components of the framework were strongly linked together and quite opaque, despite an initial effort made to make the framework flexible and hackable. In the end, many non-elegant workarounds had to be made in real-world scenarios. This made it harder to adapt an application to the constraints often encountered by companies developing their ecosystem and trying to solve real-world issues that needed deeper access to the inner-workings.

The validation system was one of the biggest, if not the biggest, culprit. It was very inconvenient to use compared to the new one brought with v5. The hacks required to make some advanced field comparison or business-logic validation were very fragile and hard to maintain. This design made it impossible to re-use code, and forced the hassle of creating a new validator for every single specific use-case.

The framework was also a bit too reliant on magic in some aspects. Many functions were using weak typing (any) and reflection, or even string identifiers, all for the sake of conciseness. But this came at a cost: no compile-time checks, hard code navigation, no completion, the need to rely on documentation all the time, etc. In the end, by trying to be concise for a better DX (developer experience), the framework sacrificed code cleanliness, reliability, readability, maintainability and actually ruined its DX this way.

Testing

All these issues accumulate and become a huge pain the moment you start trying to add tests to your project. They were very difficult to write, which is the exact opposite of what you want. Tests should be painless and as easy to read and maintain as possible. Also suffering from the locked architecture and mandatory dependency to the framework, they couldn't even be run in parallel. Almost nothing could be mocked because of the dependency coupling. This was in turn forcing you to use the database for your tests, which made tests even slower and complicated.

In short, the design of the framework prior to v5 treated tests as an after-thought despite how important they are.

Streamlining

There were many smaller and non-blocking issues as well. Together they made the entire development flow awkward by moments, like there was a missing piece to make the whole process fluid from start to finish.

The first one was the relation between the user-sent data and the internal data. Making use of the data sent by users was inconvenient and also quite unsafe, requiring a ton of type assertions and map navigation. This is very subpar compared to most Go applications which use structures. It also caused problems when interacting with the database.

Another issue was error handling and debugging. The framework was relying too much on panic, which is not a very sane nor idiomatic way to handle errors. Although it allowed for a pretty good debugging experience for developers with more precise stacktraces, a much better solution was possible. This solution wouldn't compromise on code quality for the sake of DX, again.

The last major one was the low interoperability and control, notably with the lack of access over the context API, or some missing configuration options and settings.

Philosophy

The overall philosophy of the framework stays the same. Goyave remains an opinionated framework, focused on DX (developer experience) by enabling quick and enjoyable development by being expressive, reliable and complete. The goal is to make business logic development as painless as possible by handling as many recurring things for developers as possible so they can focus on implementing what actually creates value for their company.

New direction

However, there are some important evolutions in the general direction of the framework:

  • v5 takes architecture and utilities one step further. At first glance, a typical application will be less simple to grasp. Therefore, the "progessive" nature of the framework is no more.
  • Despite its opinionated nature, the new design tries to be as open as possible. The framework should not be a black box and developers should have no trouble making it their own effortlessly.
  • The design should focus its efforts on creating tools that simplify the reduction or elimination of the dependencies between application layers and business layers.
  • The design and development of the framework now assumes full focus on catering to businesses and medium to large projects.
  • The development of the framework will now consider real-world use-cases and scenarios with more importance. No "quick and easy" solutions, tools or fancy gadgets will be developed from now on.
  • The framework and documentation will expand even more on architecture recommendations and good practices to cover more questions developers could have when working on their project. The goal of an opinionated framework is to save time to its users, while giving them all the tools they need to do produce the best possible quality software.
  • The open-source process has been revised to make contributions easier. Gathering and taking care of a strong community has always been very important. More efforts will be made in this direction.

Architecture

The framework goes even further than before when it comes to architecture recommendations for your projects. The goal is to answer more of the questions any team will inevitably encounter when setting up their project. By providing tools that will works seemlessly with this architecture, the frameworks aims at saving you a lot of time and make the development process as fluid as possible.

A project build with Goyave v5 will be split in three distinct layers:

  • Presentation: HTTP/REST layer, it's your application's facade
  • Domain/Business: contains services
  • Data: interacts with the database with repositories and contains the models

Each layer doesn't directly depend on the others because they define interfaces representing their own needs. The following chart describes the usual flow of a request into a Goyave application.

Architecture overview

This architecture has several advantages:

  • Good separation of concerns and no direct dependency
  • Easily testable
  • The data layer doesn't leak into the business layer even if there are transactions involved
  • Lowers the risk of exposing information that is not meant to be public
  • Easily readable, explorable and maintainable

In Goyave v5, nothing is global anymore. The costly need for goroutine synchronization is eliminated. The overall design is now interface-focused. On top of that, the entire framework now takes full advantage of the standard context API and encourages it use.

Components

Because nothing is global, a mechanism is necessary so the server's essential resources (such as the configuration, logger, etc) can be distributed to every component of the server. This mechanism is actually called Components, and described by the interface goyave.Composable. Most structures in the presentation layer actually are Goyave components: controllers, middleware, validators, etc.

Server

Changing all global resources to non-global required a central element that would hold them all. A server contains all the base resourc...

Read more

Pre-release v5.0.0-rc14

31 May 15:45
a81a647
Compare
Choose a tag to compare
Pre-release
  • Fixed a panic occurring in validation when the expected type is a slice but the value is not.

Pre-release v5.0.0-rc13

21 May 10:25
d3f977d
Compare
Choose a tag to compare
Pre-release
  • The CORS middleware is now global.
  • Updated docs.

Pre-release v5.0.0-rc12

14 May 08:31
d8b7697
Compare
Choose a tag to compare
Pre-release
  • Fixed "invalid db" error when using server.CloseDB() on a server having a DB with a custom dialector (usually for tests). This error is now ignored.
  • osfs: added a constructor with an optional base directory parameter: osfs.New("/home").
  • Validation: fixed a reflect error when trying to validate elements of a nil array.

Pre-release v5.0.0-rc11

10 May 13:57
f199e05
Compare
Choose a tag to compare
Pre-release
  • Updated some documentation
  • Use errors.Is() instead of strict equality for http.ErrServerClosed
  • Database initialization now return previously omitted errors
  • fsutil.File now supports DTO conversion
  • osfs.FS new method Sub() returns a sub OS file system
  • Use path.Join() instead of concatenation
  • testutil.FindRootDirectory() doesn't add a trailing slash anymore and cleans up the path. Use with path.Join() instead of concatenation.

Pre-release v5.0.0-rc10

26 Apr 09:52
31622b6
Compare
Choose a tag to compare
Pre-release
  • Cleanup
    • Removed unused structure in the auth package
    • Updated some documentation in the fsutil package
  • Reworked the auth package
    • Authenticators depend on a UserService instead of executing DB query themselves
    • Encourage using user DTO instead of models
    • This all results in removing a dependency between presentation and data layer
    • Removed FindColumns. The "username" and "password" fields are not marked with struct tags anymore: they are handled by a repository.
    • Reduced (but not eliminated) uses of reflection. Now only the password field from the DTO returned by the user service is retrieved using reflection.
    • Take advantage of generics even more
    • The request's context is now properly propagated by JWT and basic authenticators

Pre-release v5.0.0-rc9

11 Apr 10:01
69104d3
Compare
Choose a tag to compare
Pre-release
  • Slog: the dev mode handler now uses a pointer for its mutex and shares the same mutex among all his clones.
  • Server.Stop() won't attempt to close sigChannel again if the server has already been stopped. This method can this be called several times safely now.
  • Router
    • Changed the subrouter matching so it doesn't work with prefix only. This will remove conflicts between two subrouters having a prefix starting with the same characters (e.g.: /test and /test-2 won't conflict anymore)
    • The router won't turn back and explore other branches if the subrouter matches but none of its routes do. This will fix some false matches.
    • Fixed / route defined at the main router being matched if a subrouter matches but none of its routes do and a trailing slash is present in the request URI.
  • Cleanup: removed some unused resources, outdated comments and updated incorrect documentation
  • Validation
    • Fixed a reflect error in ArrayValidator if the first element of the array is invalid (e.g.: nil)
    • Use error wrapping in Unique/Exists validators for better error stacktraces
    • Add a timeout on the SQL query executed by the ExistsArray validator.
    • Remove suffix [] from n-dimensional array elements field name in error messages.

Pre-release v5.0.0-rc8

02 Apr 13:26
5dc81f2
Compare
Choose a tag to compare
Pre-release
  • Improved docs
  • server.Stop() doesn't attempt to stop the server a second time if it was already stopped
  • Validation: added validation.Context accessors for current element path and array element errors
  • Validation: added validation.Context methods AddValidationError and AddValidationErrors so validators can merge additional errors that may be coming from nested validation
  • validation.Context's Extra field is never nil
  • Fixed OPTIONS method not added to routes if their router inherited their CORS settings from parent router
  • Updated dependencies
  • Improved language files unmarshal error messages

Pre-release v5.0.0-rc7

21 Mar 13:45
ddb0a3e
Compare
Choose a tag to compare
Pre-release
  • Updated dependencies
  • Improved thread-safety of server status
  • Updated contribution resources (issue templates, etc) and license