# Macaron vs Flamego: Quick Reference This document provides quick lookup tables for common migration patterns. ## At a Glance | Aspect | Macaron | Flamego | Status | |--------|---------|---------|--------| | **Creator** | Unknwon | Unknwon | ✅ Same author | | **Status** | Maintenance only | Active development | âš ī¸ Macaron deprecated | | **Go Version** | 1.11+ | 1.19+ | 📈 Modern | | **Philosophy** | Dependency injection | Dependency injection | ✅ Same | | **Performance** | Good | Better | 📈 Improved | | **Routing** | Basic | Advanced | 📈 Enhanced | ## Import Mapping | Macaron Package | Flamego Package | Notes | |----------------|-----------------|-------| | `gopkg.in/macaron.v1` | `github.com/flamego/flamego` | Core framework | | `github.com/go-macaron/binding` | `github.com/flamego/binding` | Form binding | | `github.com/go-macaron/cache` | `github.com/flamego/cache` | Caching | | `github.com/go-macaron/captcha` | `github.com/flamego/captcha` | Captcha | | `github.com/go-macaron/csrf` | `github.com/flamego/csrf` | CSRF protection | | `github.com/go-macaron/gzip` | `github.com/flamego/gzip` | Gzip compression | | `github.com/go-macaron/i18n` | `github.com/flamego/i18n` | Internationalization | | `github.com/go-macaron/session` | `github.com/flamego/session` | Session management | | Built-in | `github.com/flamego/template` | Template rendering | | `github.com/go-macaron/toolbox` | ❌ Custom implementation | Health checks | ## Type Mapping | Macaron Type | Flamego Type | Change | |--------------|--------------|--------| | `*macaron.Macaron` | `*flamego.Flame` | Main app type | | `macaron.Context` | `flamego.Context` | Interface vs pointer | | `macaron.Handler` | `flamego.Handler` | Same concept | | `session.Store` | `session.Session` | Interface name | | `csrf.CSRF` | `csrf.CSRF` | Same | | `cache.Cache` | `cache.Cache` | Same | ## Method Mapping ### Core Methods | Operation | Macaron | Flamego | |-----------|---------|---------| | Create app | `macaron.New()` | `flamego.New()` | | Classic setup | `macaron.Classic()` | `flamego.Classic()` | | Add middleware | `m.Use(handler)` | `f.Use(handler)` | | GET route | `m.Get(path, h)` | `f.Get(path, h)` | | POST route | `m.Post(path, h)` | `f.Post(path, h)` | | Route group | `m.Group(path, fn)` | `f.Group(path, fn)` | | Combo route | `m.Combo(path)` | `f.Combo(path)` | | Start server | `http.ListenAndServe(addr, m)` | `f.Run(addr)` | ### Context Methods | Operation | Macaron | Flamego | |-----------|---------|---------| | Get param | `c.Params(":name")` | `c.Param("name")` | | Get query | `c.Query("key")` | `c.Query("key")` | | Get request | `c.Req` | `c.Request()` | | Get response | `c.Resp` | `c.ResponseWriter()` | | Redirect | `c.Redirect(url)` | `c.Redirect(url)` | | Set cookie | `c.SetCookie(...)` | `c.SetCookie(...)` | | Get cookie | `c.GetCookie(name)` | `c.Cookie(name)` | ### Session Methods | Operation | Macaron | Flamego | |-----------|---------|---------| | Set value | `sess.Set(k, v)` | `sess.Set(k, v)` | | Get value | `sess.Get(k)` | `sess.Get(k)` | | Delete | `sess.Delete(k)` | `sess.Delete(k)` | | ID | `sess.ID()` | `sess.ID()` | | Flush | `sess.Flush()` | `sess.Flush()` | ### CSRF Methods | Operation | Macaron | Flamego | |-----------|---------|---------| | Get token | `x.GetToken()` | `x.Token()` | | Validate | Automatic | Automatic | ### Cache Methods | Operation | Macaron | Flamego | |-----------|---------|---------| | Set value | `c.Put(k, v, timeout)` | `c.Set(k, v, timeout)` | | Get value | `c.Get(k)` | `c.Get(k)` | | Delete | `c.Delete(k)` | `c.Delete(k)` | | Flush | `c.Flush()` | `c.Flush()` | ## Route Syntax | Feature | Macaron | Flamego | Example | |---------|---------|---------|---------| | Basic param | `:param` | `` | `/:id` → `/` | | Regex param | `^:name(a\|b)$` | `` | Pattern matching | | Optional param | Multiple routes | `?` | `/wiki/?` | | Wildcard | `:path(*)` | `<**path>` | Glob pattern | ### Before (Macaron) ```go m.Get("/", handler) // Root m.Get("/:username", handler) // Basic param m.Get("/:username/:repo", handler) // Multiple params m.Get("/^:type(issues|pulls)$", handler) // Regex ``` ### After (Flamego) ```go f.Get("/", handler) // Root f.Get("/", handler) // Basic param f.Get("//", handler) // Multiple params f.Get("/", handler) // Regex ``` ## Handler Signatures ### Basic Handler **Macaron:** ```go func Handler(c *macaron.Context) { c.JSON(200, map[string]string{"msg": "hello"}) } ``` **Flamego:** ```go func Handler(c flamego.Context) { c.ResponseWriter().Header().Set("Content-Type", "application/json") c.ResponseWriter().WriteHeader(200) json.NewEncoder(c.ResponseWriter()).Encode(map[string]string{"msg": "hello"}) } ``` ### With Custom Context **Macaron:** ```go func Handler(c *context.Context) { c.Data["Title"] = "Page" c.HTML(200, "template") } ``` **Flamego:** ```go func Handler(c *context.Context, t template.Template, data template.Data) { data["Title"] = "Page" t.HTML(200, "template") } ``` ### With Session **Macaron:** ```go func Handler(c *context.Context, sess session.Store) { sess.Set("key", "value") } ``` **Flamego:** ```go func Handler(c *context.Context, sess session.Session) { sess.Set("key", "value") } ``` ### With Form Binding **Macaron:** ```go func Handler(c *context.Context, form Form) { // Use form } // Route m.Post("/", binding.Bind(Form{}), Handler) ``` **Flamego:** ```go func Handler(c *context.Context, form Form) { // Use form } // Route f.Post("/", binding.Form(Form{}), Handler) ``` ## Form Tags | Validation | Macaron | Flamego | |------------|---------|---------| | Required | `binding:"Required"` | `validate:"required"` | | Email | `binding:"Email"` | `validate:"email"` | | URL | `binding:"Url"` | `validate:"url"` | | Min length | `binding:"MinSize(5)"` | `validate:"min=5"` | | Max length | `binding:"MaxSize(100)"` | `validate:"max=100"` | | Range | `binding:"Range(1,10)"` | `validate:"min=1,max=10"` | | Alpha | `binding:"Alpha"` | `validate:"alpha"` | | AlphaDash | `binding:"AlphaDash"` | `validate:"alphanum"` | ### Before (Macaron) ```go type LoginForm struct { Username string `form:"username" binding:"Required;AlphaDash"` Password string `form:"password" binding:"Required;MinSize(6)"` Email string `form:"email" binding:"Email"` } ``` ### After (Flamego) ```go type LoginForm struct { Username string `form:"username" validate:"required,alphanum"` Password string `form:"password" validate:"required,min=6"` Email string `form:"email" validate:"email"` } ``` ## Middleware Configuration ### Session **Macaron:** ```go m.Use(session.Sessioner(session.Options{ Provider: "memory", ProviderConfig: "", CookieName: "session_id", CookiePath: "/", Gclifetime: 3600, Maxlifetime: 3600, })) ``` **Flamego:** ```go f.Use(session.Sessioner(session.Options{ Config: session.MemoryConfig{ GCInterval: 3600, }, Cookie: session.CookieOptions{ Name: "session_id", Path: "/", MaxAge: 3600, }, })) ``` ### CSRF **Macaron:** ```go m.Use(csrf.Csrfer(csrf.Options{ Secret: "secret-key", Cookie: "_csrf", CookiePath: "/", SetCookie: true, Secure: false, })) ``` **Flamego:** ```go f.Use(csrf.Csrfer(csrf.Options{ Secret: "secret-key", Cookie: "_csrf", CookiePath: "/", Secure: false, })) ``` ### Cache **Macaron:** ```go m.Use(cache.Cacher(cache.Options{ Adapter: "memory", AdapterConfig: "", Interval: 60, })) ``` **Flamego:** ```go f.Use(cache.Cacher(cache.Options{ Config: cache.MemoryConfig{ GCInterval: 60, }, })) ``` ### Template **Macaron:** ```go m.Use(macaron.Renderer(macaron.RenderOptions{ Directory: "templates", Funcs: template.FuncMap(), })) ``` **Flamego:** ```go f.Use(template.Templater(template.Options{ Directory: "templates", FuncMaps: []template.FuncMap{template.FuncMap()}, })) ``` ### i18n **Macaron:** ```go m.Use(i18n.I18n(i18n.Options{ SubURL: "/", Langs: []string{"en-US", "zh-CN"}, Names: []string{"English", "įŽ€äŊ“中文"}, DefaultLang: "en-US", })) ``` **Flamego:** ```go f.Use(i18n.I18n(i18n.Options{ URLPrefix: "/", Languages: []string{"en-US", "zh-CN"}, Names: []string{"English", "įŽ€äŊ“中文"}, DefaultLanguage: "en-US", })) ``` ## Common Patterns ### Pattern: Get User by Username **Macaron:** ```go func UserProfile(c *context.Context) { username := c.Params(":username") user, err := database.GetUserByName(username) if err != nil { c.NotFoundOrError(err, "get user") return } c.Data["User"] = user c.HTML(200, "user/profile") } ``` **Flamego:** ```go func UserProfile(c *context.Context, t template.Template, data template.Data) { username := c.Param("username") user, err := database.GetUserByName(username) if err != nil { c.NotFoundOrError(err, "get user") return } data["User"] = user t.HTML(200, "user/profile") } ``` ### Pattern: Form Submission **Macaron:** ```go // Form struct type CreateRepoForm struct { Name string `form:"name" binding:"Required;AlphaDashDot"` } // Route m.Post("/repo/create", binding.Bind(CreateRepoForm{}), CreateRepoPost) // Handler func CreateRepoPost(c *context.Context, form CreateRepoForm) { if c.HasError() { c.RenderWithErr(c.GetErrMsg(), "repo/create", &form) return } // Create repo... c.Redirect("/") } ``` **Flamego:** ```go // Form struct type CreateRepoForm struct { Name string `form:"name" validate:"required,alphaDashDot"` } // Route f.Post("/repo/create", binding.Form(CreateRepoForm{}), CreateRepoPost) // Handler func CreateRepoPost(c *context.Context, form CreateRepoForm, t template.Template, data template.Data) { if c.HasError() { c.RenderWithErr(c.GetErrMsg(), "repo/create", &form, t, data) return } // Create repo... c.Redirect("/") } ``` ### Pattern: JSON API **Macaron:** ```go func APIHandler(c *context.APIContext) { data := map[string]any{ "id": 123, "name": "example", } c.JSON(200, data) } ``` **Flamego:** ```go func APIHandler(c *context.APIContext) { data := map[string]any{ "id": 123, "name": "example", } c.ResponseWriter().Header().Set("Content-Type", "application/json") c.ResponseWriter().WriteHeader(200) json.NewEncoder(c.ResponseWriter()).Encode(data) } // Or create helper method on APIContext func (c *APIContext) JSON(status int, v any) error { c.ResponseWriter().Header().Set("Content-Type", "application/json") c.ResponseWriter().WriteHeader(status) return json.NewEncoder(c.ResponseWriter()).Encode(v) } ``` ### Pattern: Middleware Chain **Macaron:** ```go m.Group("/repo", func() { m.Get("/create", repo.Create) m.Post("/create", binding.Bind(form.CreateRepo{}), repo.CreatePost) }, reqSignIn, context.RepoAssignment()) ``` **Flamego:** ```go f.Group("/repo", func() { f.Get("/create", repo.Create) f.Post("/create", binding.Form(form.CreateRepo{}), repo.CreatePost) }, reqSignIn, context.RepoAssignment()) ``` ## Error Handling ### Not Found **Macaron:** ```go func Handler(c *context.Context) { user, err := getUser() if err != nil { if isNotFound(err) { c.NotFound() return } c.Error(err, "get user") return } } ``` **Flamego:** ```go func Handler(c *context.Context) { user, err := getUser() if err != nil { if isNotFound(err) { c.NotFound() return } c.Error(err, "get user") return } } ``` ## Testing ### Mock Context **Macaron:** ```go import "gopkg.in/macaron.v1" func TestHandler(t *testing.T) { m := macaron.New() req, _ := http.NewRequest("GET", "/", nil) resp := httptest.NewRecorder() m.ServeHTTP(resp, req) } ``` **Flamego:** ```go import "github.com/flamego/flamego" func TestHandler(t *testing.T) { f := flamego.New() req, _ := http.NewRequest("GET", "/", nil) resp := httptest.NewRecorder() f.ServeHTTP(resp, req) } ``` ## Migration Checklist (Quick) - [ ] Update imports - [ ] Change `:param` → `` in routes - [ ] Change `macaron.Handler` → `flamego.Handler` - [ ] Change `*macaron.Context` → `flamego.Context` - [ ] Change `c.Params(":name")` → `c.Param("name")` - [ ] Change `c.Resp` → `c.ResponseWriter()` - [ ] Change `c.Req` → `c.Request()` - [ ] Change `session.Store` → `session.Session` - [ ] Change `x.GetToken()` → `x.Token()` - [ ] Change `cache.Put()` → `cache.Set()` - [ ] Add template parameters to handlers - [ ] Update form validation tags - [ ] Test everything! ## Common Pitfalls | Issue | Solution | |-------|----------| | Forgot to remove `:` from param name | Use `c.Param("name")` not `c.Param(":name")` | | Template not rendering | Add `template.Template` and `template.Data` to handler | | Session not working | Changed interface from `Store` to `Session` | | CSRF validation fails | Use `Token()` not `GetToken()` | | Cache not working | Use `Set()` not `Put()` | | Form validation errors | Update tags: `binding` → `validate` | | Context methods fail | Use methods not fields: `c.ResponseWriter()` not `c.Resp` | ## Performance Notes ### Flamego Advantages 1. **O(1) static route lookup** - Faster than Macaron's tree 2. **Better regex handling** - Compiled patterns cached 3. **Reduced allocations** - More efficient memory usage 4. **Faster middleware chain** - Optimized injection ### Expected Improvements - 10-30% faster route matching for static routes - 5-15% faster overall request handling - Slightly lower memory usage - Better scalability under load ## Support and Resources | Need Help? | Resource | |------------|----------| | Official Docs | https://flamego.dev/ | | API Reference | https://pkg.go.dev/github.com/flamego/flamego | | GitHub | https://github.com/flamego/flamego | | Middleware | https://github.com/flamego (multiple repos) | | FAQ | https://flamego.dev/faqs.html | | Examples | https://github.com/flamego/flamego/tree/main/_examples | ## Version Information | Framework | Current Version | Release Date | Status | |-----------|----------------|--------------|--------| | Macaron | v1.5.0 | 2021 | Maintenance | | Flamego | v1.9.0+ | 2024 | Active | --- **Last Updated:** 2026-01-25 **Applies to:** Gogs migration from Macaron to Flamego