The Full-Stack Web Framework for Go

Overview

Bud

The Full-Stack Web Framework for Go. Bud writes the boring code for you, helping you launch your website faster.

Video Demo

Watch a video demonstrating how to build a minimal HN clone in 15 minutes with Bud.

Documentation

Read the documentation to learn how to get started with Bud.

Installing Bud

Bud ships as a single binary that runs on Linux and Mac. You can follow along for Windows support in this issue.

The easiest way to get started is by copying and pasting the command below in your terminal:

$ curl -sf https://raw.githubusercontent.com/livebud/bud/main/install.sh | sh

This script will download the right binary for your operating system and move the binary to the right location in your $PATH.

Confirm that you've installed Bud by typing bud in your terminal.

bud -h

You should see the following:

Usage:
    bud [flags] [command]

Flags:
  -C, --chdir  Change the working directory

Commands:
  build    build the production server
  create   create a new project
  run      run the development server
  tool     extra tools
  version  Show package versions

Requirements

The following software is required to use Bud.

  • Node v14+

    This is a temporary requirement that we plan to remove in v0.3

  • Go v1.16+

    Bud relies heavily on io/fs and will take advantage of generics in the future, so while Go v1.16 will work, we suggest running Go v1.18+ if you can.

Your First Project

With bud installed, you can now scaffold a new project:

$ bud create hello
$ cd hello

The create command will scaffold everything you need to get started with bud.

$ ls
go.mod  node_modules/  package-lock.json  package.json

... which is not very much by the way! Unlike most other fullstack frameworks, Bud starts out very minimal. As you add dependencies, Bud will generate all the boring code to glue your app together. Let's see this in action.

Start the development server with bud run:

$ bud run
| Listening on http://127.0.0.1:3000

Click on the link to open the browser. You'll be greeted with bud's welcome page.

Congrats! You're running your first web server with Bud. The welcome server is your jumping off point to learn more about the framework.

CleanShot 2022-05-12 at 22.00.19@2x.png

Next Steps

Check out the Hacker News demo, read the documentation, schedule a quick call or go on your own adventure. The only limit is your imagination.

Recent discussions: Reddit, Hacker News, Twitter

How did Bud come into existence?

I started working on Bud 2 years ago after seeing how productive people could be in Laravel. I wanted the same for Go, so I decided to try creating Laravel for the Go ecosystem. However, my first version after 6 months needed to scaffold many files just to get started. If you are coming from Rails or Laravel, you may shrug and consider this as pretty normal.

Unfortunately, I have been spoiled by the renaissance in frontend frameworks like Next.js that start barebones but every file you add incrementally enhances your web application. This keeps the initial complexity under control.

With this additional inspiration, I worked on the next iteration for the ensuing 18 months.

The goals are now:

  • Generate files only as you need them. Keep these generated files away from your application code and give developers the choice to keep them out of source control. You shouldn't need to care about the generated code. You may be surprised to learn that Go also generates code to turn your Go code into an executable, but it works so well you don't need to think about it. Bud should feel like this.

  • Feel like using a modern JS framework. This means it should work with multiple modern frontend frameworks like Svelte and React, support live reload, and have server-side rendering for better performance and SEO.

  • The framework should be extensible from Day 1. Bud is too ambitious for one person. We're going to need an ambitious community behind this framework. Extensibility should be primarily driven by adding code, rather than by adding configuration.

  • Bud should provide high-level, type-safe APIs for developers while generating performant, low-level Go code under the covers.

  • Bud should compile to a single binary that contains your entire web app and can be copied to a server that doesn't even have Go installed.

Contributing

Please refer to the Contributing Guide to learn how to run and test Bud locally.

Issues
  • Error with NPM When Running make install During Contribution Set-Up

    Error with NPM When Running make install During Contribution Set-Up

    I've been extremely impressed by and interested in but (great work @matthewmueller!!) and I wanted to begin contributing to an interesting bug that I saw in the issues. So I cloned bud and was following the instructions in Contributing.md, but I ran into an error when running make install.

    OS: Windows 10 Go Version: 1.18.2 Node.js Version: 16.14.0

    Bud_Make_NPM_Error

    help wanted 
    opened by syke99 18
  • Error: invalid cross-device link

    Error: invalid cross-device link

    When I did 'bud create ff-bud', I got this error: | rename /tmp/bud-create-3425471412 ff-bud: invalid cross-device link Possibly because /tmp is different partition than the current directory. Rename will work only in same partition?

    opened by codevin 14
  • Add Windows Support

    Add Windows Support

    Windows support is currently blocked by:

    • https://github.com/rogchap/v8go/pull/234

    Bud's compiler will also transition to using Go plugins, which also do not have Windows support yet:

    • https://github.com/golang/go/issues/19282 Though we could use something like go-plugin for Windows.

    I haven't tested it yet, but you should be able to use Bud with the Windows Subsystem for Linux (WSL).

    If you get this working, please let us know how!

    opened by matthewmueller 12
  • Unused import error in generated controller

    Unused import error in generated controller

    I'm attempting to implement persistence. So I create a new folder models. Write a struct. Update the controllers to use that new struct instead of the autogenerated one. Then run bud run. But bud errors out with

    bud/.app/controller/controller.go:10:2: imported and not used: "github/donovanrost/bud-test/models"
    

    I don't think that bud needs to do any code generation with this package. Is there a way to tell bud to ignore it?

    bug 
    opened by donovanrost 8
  • Too many return values error on loadController()

    Too many return values error on loadController()

    Hi, Firstly this project looks great. Really looking forward to working with it.

    Getting the error...

    bud/.app/controller/controller.go:133:15: too many return values have (nil, error)

    Looks the loadController() is missing a return error definination

    func loadController() *controller.Controller { controllerController, err := controller.Load() if err != nil { return nil, err } return controllerController }

    bug 
    opened by joesamcoke 8
  • run error

    run error

    Hello, After I bud build the project, I remove the *.go and go.mod source files. run ./bud/app in the terminal, but it output the error: unable to find go.mod: file does not exist in "/Users/Works/news"

    ---- for exmaple input the command in the terminal news % ./bud/app unable to find go.mod: file does not exist in "/Users/Works/news"

    Why the app is running and it needs to depend go.mod?

    bug help wanted 
    opened by huqiuyun 8
  • ../../../go/pkg/mod/github.com/livebud/bud@v0.1.4/package/scaffold/template.go:28:8: undefined: any

    ../../../go/pkg/mod/github.com/livebud/[email protected]/package/scaffold/template.go:28:8: undefined: any

    ➜  bud-hello bud version
         bud: 0.1.4
      svelte: 3.47.0
       react: 18.0.0
    ➜  bud-hello bud run
    | Listening on http://127.0.0.1:3000
    # github.com/livebud/bud/package/scaffold
    ../../../go/pkg/mod/github.com/livebud/[email protected]/package/scaffold/template.go:28:8: undefined: any
    note: module requires Go 1.18
    ➜  bud-hello go version
    go version go1.17.10 darwin/amd64
    
    opened by forging2012 8
  • Trouble with nested routes

    Trouble with nested routes

    I ran:

    bud new controller associations index show
    bud new controller academies index show
    bud new controller associations/academies index show
    

    This laid out out the appropriate controllers in the /controller directory. However, I'm getting an error

    bud/.app/controller/controller.go:9:2: imported and not used: "bud-test/controller/associations/academies" as academies1

    looking at bud/.app/controller/controller.go, we can see that bud-test/controller/associations/academies is imported at as academies1 but that import isn't used. I can't delete it because the framework automatically generates it again.

    Is there a correct way to create nested controllers like this?

    package controller
    
    import (
    	view "bud-test/bud/.app/view"
    	controller "bud-test/controller"
    	academies "bud-test/controller/academies"
    	members "bud-test/controller/academies/members"
    	associations "bud-test/controller/associations"
    	academies1 "bud-test/controller/associations/academies"
    	users "bud-test/controller/users"
    	request "github.com/livebud/bud/runtime/controller/request"
    	response "github.com/livebud/bud/runtime/controller/response"
    	http "net/http"
    )
    
    // Controller struct
    type Controller struct {
    	Index        *IndexAction
    	Show         *ShowAction
    	Academies    *AcademiesController
    	Associations *AssociationsController
    	Users        *UsersController
    }
    
    // IndexAction struct
    type IndexAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (i *IndexAction) Key() string {
    	return "/index"
    }
    
    // Path is the default RESTful path to this action
    func (i *IndexAction) Path() string {
    	return "/"
    }
    
    // Method is the default RESTful method of this action
    func (i *IndexAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (i *IndexAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	i.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (i *IndexAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	controllerController := loadController()
    	fn := controllerController.Index
    	// Call the controller
    	stories, err := fn(
    		httpRequest.Context(),
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: i.View.Handler("/", map[string]interface{}{"stories": stories}),
    		JSON: response.JSON(stories),
    	}
    }
    
    // ShowAction struct
    type ShowAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (s *ShowAction) Key() string {
    	return "/show"
    }
    
    // Path is the default RESTful path to this action
    func (s *ShowAction) Path() string {
    	return "/:id"
    }
    
    // Method is the default RESTful method of this action
    func (s *ShowAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (s *ShowAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	s.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (s *ShowAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    		ID int `json:"id,omitempty"`
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	controllerController := loadController()
    	fn := controllerController.Show
    	// Call the controller
    	story, err := fn(
    		httpRequest.Context(),
    		in.ID,
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: s.View.Handler("/:id", map[string]interface{}{"story": story}),
    		JSON: response.JSON(story),
    	}
    }
    
    // Controller struct
    type AcademiesController struct {
    	Index   *AcademiesIndexAction
    	Show    *AcademiesShowAction
    	Members *AcademiesMembersController
    }
    
    // AcademiesIndexAction struct
    type AcademiesIndexAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (i *AcademiesIndexAction) Key() string {
    	return "/academies/index"
    }
    
    // Path is the default RESTful path to this action
    func (i *AcademiesIndexAction) Path() string {
    	return "/academies"
    }
    
    // Method is the default RESTful method of this action
    func (i *AcademiesIndexAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (i *AcademiesIndexAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	i.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (i *AcademiesIndexAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	academiesController := loadAcademiesController()
    	fn := academiesController.Index
    	// Call the controller
    	academies, err := fn(
    		httpRequest.Context(),
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: i.View.Handler("/academies", map[string]interface{}{"academies": academies}),
    		JSON: response.JSON(academies),
    	}
    }
    
    // AcademiesShowAction struct
    type AcademiesShowAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (s *AcademiesShowAction) Key() string {
    	return "/academies/show"
    }
    
    // Path is the default RESTful path to this action
    func (s *AcademiesShowAction) Path() string {
    	return "/academies/:id"
    }
    
    // Method is the default RESTful method of this action
    func (s *AcademiesShowAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (s *AcademiesShowAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	s.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (s *AcademiesShowAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    		ID int `json:"id,omitempty"`
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	academiesController := loadAcademiesController()
    	fn := academiesController.Show
    	// Call the controller
    	academy, err := fn(
    		httpRequest.Context(),
    		in.ID,
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: s.View.Handler("/academies/:id", map[string]interface{}{"academy": academy}),
    		JSON: response.JSON(academy),
    	}
    }
    
    // Controller struct
    type AcademiesMembersController struct {
    	Index *AcademiesMembersIndexAction
    	Show  *AcademiesMembersShowAction
    }
    
    // AcademiesMembersIndexAction struct
    type AcademiesMembersIndexAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (i *AcademiesMembersIndexAction) Key() string {
    	return "/academies/members/index"
    }
    
    // Path is the default RESTful path to this action
    func (i *AcademiesMembersIndexAction) Path() string {
    	return "/academies/:academy_id/members"
    }
    
    // Method is the default RESTful method of this action
    func (i *AcademiesMembersIndexAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (i *AcademiesMembersIndexAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	i.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (i *AcademiesMembersIndexAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	membersController := loadAcademiesMembersController()
    	fn := membersController.Index
    	// Call the controller
    	members, err := fn(
    		httpRequest.Context(),
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: i.View.Handler("/academies/:academy_id/members", map[string]interface{}{"members": members}),
    		JSON: response.JSON(members),
    	}
    }
    
    // AcademiesMembersShowAction struct
    type AcademiesMembersShowAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (s *AcademiesMembersShowAction) Key() string {
    	return "/academies/members/show"
    }
    
    // Path is the default RESTful path to this action
    func (s *AcademiesMembersShowAction) Path() string {
    	return "/academies/:academy_id/members/:id"
    }
    
    // Method is the default RESTful method of this action
    func (s *AcademiesMembersShowAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (s *AcademiesMembersShowAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	s.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (s *AcademiesMembersShowAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    		ID int `json:"id,omitempty"`
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	membersController := loadAcademiesMembersController()
    	fn := membersController.Show
    	// Call the controller
    	member, err := fn(
    		httpRequest.Context(),
    		in.ID,
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: s.View.Handler("/academies/:academy_id/members/:id", map[string]interface{}{"member": member}),
    		JSON: response.JSON(member),
    	}
    }
    
    // Controller struct
    type AssociationsController struct {
    	Index     *AssociationsIndexAction
    	Show      *AssociationsShowAction
    	Academies *AssociationsAcademiesController
    }
    
    // AssociationsIndexAction struct
    type AssociationsIndexAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (i *AssociationsIndexAction) Key() string {
    	return "/associations/index"
    }
    
    // Path is the default RESTful path to this action
    func (i *AssociationsIndexAction) Path() string {
    	return "/associations"
    }
    
    // Method is the default RESTful method of this action
    func (i *AssociationsIndexAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (i *AssociationsIndexAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	i.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (i *AssociationsIndexAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	associationsController := loadAssociationsController()
    	fn := associationsController.Index
    	// Call the controller
    	associations, err := fn(
    		httpRequest.Context(),
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: i.View.Handler("/associations", map[string]interface{}{"associations": associations}),
    		JSON: response.JSON(associations),
    	}
    }
    
    // AssociationsShowAction struct
    type AssociationsShowAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (s *AssociationsShowAction) Key() string {
    	return "/associations/show"
    }
    
    // Path is the default RESTful path to this action
    func (s *AssociationsShowAction) Path() string {
    	return "/associations/:id"
    }
    
    // Method is the default RESTful method of this action
    func (s *AssociationsShowAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (s *AssociationsShowAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	s.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (s *AssociationsShowAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    		ID int `json:"id,omitempty"`
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	associationsController := loadAssociationsController()
    	fn := associationsController.Show
    	// Call the controller
    	association, err := fn(
    		httpRequest.Context(),
    		in.ID,
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: s.View.Handler("/associations/:id", map[string]interface{}{"association": association}),
    		JSON: response.JSON(association),
    	}
    }
    
    // Controller struct
    type AssociationsAcademiesController struct {
    	Index *AssociationsAcademiesIndexAction
    	Show  *AssociationsAcademiesShowAction
    }
    
    // AssociationsAcademiesIndexAction struct
    type AssociationsAcademiesIndexAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (i *AssociationsAcademiesIndexAction) Key() string {
    	return "/associations/academies/index"
    }
    
    // Path is the default RESTful path to this action
    func (i *AssociationsAcademiesIndexAction) Path() string {
    	return "/associations/:association_id/academies"
    }
    
    // Method is the default RESTful method of this action
    func (i *AssociationsAcademiesIndexAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (i *AssociationsAcademiesIndexAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	i.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (i *AssociationsAcademiesIndexAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	academiesController := loadAssociationsAcademiesController()
    	fn := academiesController.Index
    	// Call the controller
    	academies, err := fn(
    		httpRequest.Context(),
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: i.View.Handler("/associations/:association_id/academies", map[string]interface{}{"academies": academies}),
    		JSON: response.JSON(academies),
    	}
    }
    
    // AssociationsAcademiesShowAction struct
    type AssociationsAcademiesShowAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (s *AssociationsAcademiesShowAction) Key() string {
    	return "/associations/academies/show"
    }
    
    // Path is the default RESTful path to this action
    func (s *AssociationsAcademiesShowAction) Path() string {
    	return "/associations/:association_id/academies/:id"
    }
    
    // Method is the default RESTful method of this action
    func (s *AssociationsAcademiesShowAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (s *AssociationsAcademiesShowAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	s.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (s *AssociationsAcademiesShowAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    		ID int `json:"id,omitempty"`
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	academiesController := loadAssociationsAcademiesController()
    	fn := academiesController.Show
    	// Call the controller
    	academy, err := fn(
    		httpRequest.Context(),
    		in.ID,
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: s.View.Handler("/associations/:association_id/academies/:id", map[string]interface{}{"academy": academy}),
    		JSON: response.JSON(academy),
    	}
    }
    
    // Controller struct
    type UsersController struct {
    	Index *UsersIndexAction
    	Show  *UsersShowAction
    }
    
    // UsersIndexAction struct
    type UsersIndexAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (i *UsersIndexAction) Key() string {
    	return "/users/index"
    }
    
    // Path is the default RESTful path to this action
    func (i *UsersIndexAction) Path() string {
    	return "/users"
    }
    
    // Method is the default RESTful method of this action
    func (i *UsersIndexAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (i *UsersIndexAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	i.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (i *UsersIndexAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	usersController := loadUsersController()
    	fn := usersController.Index
    	// Call the controller
    	users, err := fn(
    		httpRequest.Context(),
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: i.View.Handler("/users", map[string]interface{}{"users": users}),
    		JSON: response.JSON(users),
    	}
    }
    
    // UsersShowAction struct
    type UsersShowAction struct {
    	View *view.Server
    }
    
    // Key is a unique identifier of this action
    func (s *UsersShowAction) Key() string {
    	return "/users/show"
    }
    
    // Path is the default RESTful path to this action
    func (s *UsersShowAction) Path() string {
    	return "/users/:id"
    }
    
    // Method is the default RESTful method of this action
    func (s *UsersShowAction) Method() string {
    	return "GET"
    }
    
    // ServeHTTP fn
    func (s *UsersShowAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    	s.handler(r).ServeHTTP(w, r)
    }
    
    // Handler function
    func (s *UsersShowAction) handler(httpRequest *http.Request) http.Handler {
    	// Define the input struct
    	var in struct {
    		ID int `json:"id,omitempty"`
    	}
    	// Unmarshal the request body
    	if err := request.Unmarshal(httpRequest, &in); err != nil {
    		return &response.Format{
    			JSON: response.Status(400).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    	usersController := loadUsersController()
    	fn := usersController.Show
    	// Call the controller
    	user, err := fn(
    		httpRequest.Context(),
    		in.ID,
    	)
    	if err != nil {
    		return &response.Format{
    			JSON: response.Status(500).Set("Content-Type", "application/json").JSON(map[string]string{"error": err.Error()}),
    		}
    	}
    
    	// Respond
    	return &response.Format{
    		HTML: s.View.Handler("/users/:id", map[string]interface{}{"user": user}),
    		JSON: response.JSON(user),
    	}
    }
    
    func loadAcademiesController() *academies.Controller {
    	academiesController := &academies.Controller{}
    	return academiesController
    }
    
    func loadAcademiesMembersController() *members.Controller {
    	membersController := &members.Controller{}
    	return membersController
    }
    
    func loadAssociationsAcademiesController() *academies.Controller {
    	academiesController := &academies.Controller{}
    	return academiesController
    }
    
    func loadAssociationsController() *associations.Controller {
    	associationsController := &associations.Controller{}
    	return associationsController
    }
    
    func loadController() *controller.Controller {
    	controllerController := &controller.Controller{}
    	return controllerController
    }
    
    func loadUsersController() *users.Controller {
    	usersController := &users.Controller{}
    	return usersController
    }
    
    bug help wanted 
    opened by donovanrost 6
  • fix: move the prompt out of the routines

    fix: move the prompt out of the routines

    Current Behavior

    Both npm output and the prompt for the app modules is overlapped by each other

    Changes by the PR

    Use the original context while prioritizing the prompt and then running the other stuff in the derived context and routines.

    opened by barelyhuman 5
  • [ERROR] Could not resolve

    [ERROR] Could not resolve "svelte/internal"

    I'm following along the HackerNews video and am encountering build issues. I'm performing the following steps

    mkdir bud-test
    cd bud-test
    bud create .
    bud build
    bud run
    bud new controller stories:/ index show
    

    When I go to the webpage I'm given the following error

    | conjure: generate "bud/.app/view/view.go" > ✘ [ERROR] Could not resolve "svelte/internal"
    
        view/index.svelte:7:7:
          7 │ } from "svelte/internal";
            ╵        ~~~~~~~~~~~~~~~~~
    
      You can mark the path "svelte/internal" as external to exclude it from the
      bundle, which will remove this error.
    
    
    ✘ [ERROR] Could not resolve "svelte/internal"
    
        view/show.svelte:2:51:
          2 │ import { create_ssr_component, each, escape } from "svelte/internal";
            ╵                                                    ~~~~~~~~~~~~~~~~~
    
      You can mark the path "svelte/internal" as external to exclude it from the
      bundle, which will remove this error.
    

    Here are some details about my environment

    bud version
    ➜  bud-test bud version  
         bud: 0.1.4
      svelte: 3.47.0
       react: 18.0.0
    
    go version
    go version go1.18.3 darwin/arm64
    
    waiting for info 
    opened by donovanrost 4
  • ci: add matrix testing for supported Go and Node.js versions

    ci: add matrix testing for supported Go and Node.js versions

    Also,

    • ci: do not fail fast to preserve error messages
    • ci: prefer built-in caching for actions/setup-go
    • chore: update to the latest gh actions

    This PR is only meant to add support for matrix testing of supported Go and Node.js versions as proclaimed in https://github.com/livebud/bud/issues/90#issuecomment-1139315192 .

    I would propose that back-porting bud to older versions of Go should be done separately. The matrix testing already gives us hints about the lacking language features of older Go versions ;)

    opened by wheinze 4
  • `bud run` stdout/stderr improvements

    `bud run` stdout/stderr improvements

    Jotting down a quick list of bugs and improvements to make to bud run's terminal logging. @012e brought us a big step forward in terms of DX with #131, but there's a few loose ends left to cleanup:

    • [ ] Frontend reloads always show 0ms. This one is tricky to time because the start is in the app server, the end is in the bud dev server. The way frontend reloads work is they just send a signal to the frontend as an event source message to re-import it's page component. Should still be possible with @012e prompter state machine, we'll probably just need to make it concurrency safe and pass it through more places

    • [ ] Frontend errors don't show an error message in terminal or browser until refreshing the page. I think this is a regression, but I'm not sure. Eventually I'd like to show error messages in the same way that CRA or Next.js have these error message dialogs, but for now, I think it's fine to just print the error out in terminal and browser.

    • [ ] Rename internal prompter. Right now the prompter doesn't read from stdin and is more like a state machine that tracks what state the runner is in and updates the terminal accordingly. I'm sure there are packages that have something like this (maybe docker?), we should find a better name.

    • [ ] Simplify internal prompter API. It doesn't need track stdout and stderr separately, it can implement an io.Writer that stores any output into a buffer, then check if that buffer has been written to in order to determine whether we can replace the current line or not.

    bug improvement help wanted 
    opened by matthewmueller 0
  • Can't create routes named `index`, `show`

    Can't create routes named `index`, `show`

    Reproduce

    1. Create a new project bud create project
    2. Create a root route (important) bud new controller anything:/ index show
    3. bud new controller index or bud new controller show (with or without views)
    4. bud run will give an error:
    | conjure: generate "bud/.app/main.go". conjure: generate "bud/.app/program/program.go". program: unable to wire. di: unable to wire "bud-app/bud/program".loadApp function. di: unable to find definition for param "bud-app/bud/.app/controller".*Controller in "bud-app/bud/.app/web".*Server . parser: unable to find declaration for "bud-app/bud/.app/controller".Controller in "bud/.app/web/web.go". bud/.app/controller/controller.go:15:2: Index redeclared in this block
    	previous declaration at bud/.app/controller/controller.go:13:2
    
    bug help wanted 
    opened by 012e 4
  • Can't create routes with name begin in number

    Can't create routes with name begin in number

    When we create a route with a number at the beginning

    ❯ bud new controller 1 index
    | 1:9: expected 'IDENT', found 1
    

    The controller is not generated but the view is.

    view/
    ├── 1
    │   └── index.svelte
    └── index.svelte
    controller/
    └── controller.go
    

    Result in

    view: render error conjure: generate "bud/view/_ssr.js". ✘ [ERROR] [plugin tranform_svelte_to_js] Unexpected token (2:9)
    1: <script>
    2:   export let 1s = []
                ^
    3: </script>
    4:
    
        svelte:./bud/view/1/index.svelte:2:29:
          2 │ import View1IndexSvelte from "./view/1/index.svelte"
    
    bug needs decision 
    opened by 012e 3
  • Renaming or deleting views should trigger a recompile

    Renaming or deleting views should trigger a recompile

    Given the following file directory:

    view/
      show.svelte
    

    If you try renaming show.svelte to _show.svelte while running bud run, the change doesn't register.

    This is because bud currently treats all view changes as incrementally reloadable, but in this case, we need to regenerate the controller.

    Renames and deletes of views should trigger a full-page reload.

    bug 
    opened by matthewmueller 0
  • Fix installer error message for Window's 11

    Fix installer error message for Window's 11

    when i run this command in windows11's terminal:

    curl -sf https://raw.githubusercontent.com/livebud/bud/main/install.sh | sh

    sh: uname_os_check: internal error 'MINGW64_NT-10.0-25115' got converted to 'mingw64_nt-10.0-25115' which is not a GOOS value. Please file bug at https://github.com/client9/shlib

    Will it suport windows?

    help wanted needs investigation 
    opened by zhenfeng-zhu 2
  • Unable to live reload after SSR error

    Unable to live reload after SSR error

    Currently when there's a server-side rendering error, that you subsequently fix, you'll need to refresh the page again. This is likely because the event source isn't hooked up to that error yet.

    Steps to reproduce:

    1. Create a view with an error
    <script>
      export let _string = ""
      a.b = 'c'
    </script>
    
    <h1>{_string}</h1>
    
    <style>
      h1 {
        background: blue;
        padding: 20px;
        color: white;
      }
    </style>
    
    1. Make a change to the controller:
    package controller
    
    type Controller struct {
    }
    
    func (c *Controller) Index() string {
    	return "hello world."
    }
    
    func (c *Controller) Show(id string) string {
    	return "shows/" + id
    }
    

    And you'll see something like ReferenceError: a is not defined in the browser. Even if you fix the problem in Svelte, it won't refresh.

    bug 
    opened by matthewmueller 0
Releases(v0.1.9)
  • v0.1.9(Jun 26, 2022)

    • Better hot reload DX with bud run (#131) thanks to @012e

      Prior to v0.1.9, whenever a file change occurs it would rebuild and print a ready message if successful or an error message if unsuccessful. The ready messages would often clutter the terminal over time.

    • Large internal refactor (#133). The goals of this refactor:

      1. Make it easier to understand. The double generated binary building was something that often confused me.
      2. Make it easier to contribute. I'm so impressed with the contributions so far, with this refactor it should be even easier.
      3. Make it faster during development. The slowest step in the build process is running go build. We now only run go build once on boot, not twice.

      Learn more details in this comment. This PR concludes the work necessary to release v0.2.

    • Support glob embeds (#150) thanks to @vito

      Build caching now understands embedded globs like // go:embed *.sql. You'll no longer get stale builds when changing a file within an embedded glob.

    • Improved Dockerfile in contributing (#140) thanks to @wheinze

      The Dockerfile now supports passing Node and Go versions to build a custom container. It also uses a smaller base image.

    Source code(tar.gz)
    Source code(zip)
    bud_v0.1.9_darwin_amd64.tar.gz(16.88 MB)
    bud_v0.1.9_darwin_arm64.tar.gz(16.01 MB)
    bud_v0.1.9_linux_amd64.tar.gz(16.88 MB)
    checksums.txt(290 bytes)
  • v0.1.8(Jun 22, 2022)

    • Support func(w, r) controller actions (#147) (thanks @vito!)

      This release adds a highly-requested feature (atleast by me!) where you can now drop down to using the vanilla http.HandlerFunc signature.

      This is a useful escape hatch for webhooks, streaming and other complex use cases.

      package webhooks
      
      type Controller struct {
        GH *github.Client
      }
      
      func (c *Controller) Index() string {
        return "GitHub webhook service!"
      }
      
      // Create handles incoming webhooks
      func (c *Controller) Create(w http.ResponseWriter, r *http.Request) {
        // Respond to the webhook using a vanilla HTTP handler function!
      }
      
    • Replace redirect with case-insensitive routing (#142) (thanks @vito!)

      Prior to v0.1.8, if you defined the route /bud, but a user visited /BUD, they would be redirected to /bud. This was originally done for SEO purposes to prevent different casing from appearing as separate pages.

      However, this had an unfortunate side-effect in that you couldn't use parameters with mixed casing (e.g. base64 encoding).

      In v0.1.8, we changed this so that URL routing is now case insensitive, so /BUD will run the /bud action. This doesn't address the SEO issue, but that will be a follow-up task for a later time.

    Source code(tar.gz)
    Source code(zip)
    bud_v0.1.8_darwin_amd64.tar.gz(15.09 MB)
    bud_v0.1.8_darwin_arm64.tar.gz(14.32 MB)
    bud_v0.1.8_linux_amd64.tar.gz(15.14 MB)
    checksums.txt(290 bytes)
  • v0.1.7(Jun 4, 2022)

  • v0.1.6(Jun 4, 2022)

    • Ensure alignment between CLI and runtime (#126)

      In v0.1.5, we had a breaking change in the runtime. If you had an existing project and upgraded the CLI to v0.1.5, but you were still using the v0.1.4 runtime in go.mod, you'd encounter an error. This change automatically updates your go.mod to align with the CLI that's building it. Fixes: #125.

    Source code(tar.gz)
    Source code(zip)
    bud_v0.1.6_darwin_amd64.tar.gz(15.09 MB)
    bud_v0.1.6_darwin_arm64.tar.gz(14.32 MB)
    bud_v0.1.6_linux_amd64.tar.gz(15.14 MB)
    checksums.txt(290 bytes)
  • v0.1.5(Jun 4, 2022)

    This release focuses on paying down some technical debt that was accumulated prior to the release. It's part of the v0.2 plan.

    • Rename bud run [--port=<address>] to bud run [--listen=<address>]

      This breaking change addresses the confusion discussed in https://github.com/livebud/bud/discussions/42.

    • Rename bud tool v8 client to bud tool v8 serve

      This breaking change gives a better name for what the command does, listen for eval requests, evaluate the javascript and return the response.

    • 204 No Content improvements (thanks @theEyeD!)

      Now when controller don't have a return value or return a nil error, they return 204 No Content. For example:

      package users
      type Controller struct {}
      func (c *Controller) Create() error {
        return nil
      }
      
      $ curl -X POST /users
      HTTP/1.1 204 No Content
      Content-Length: 0
      
    • Dedupe and group watch events (#123)

      This reduces the number of events the watcher triggers on Linux causing less builds to trigger at once. It also hopefully fixed an issue where "remove" events sometimes weren't triggering rebuilds on all platforms.

    • Improve CI (thanks @wheinze!) (#118)

      Waldemar took a much needed pass over the CI. He cleaned up the file, fixed caching and extended the test matrix, so we can more confidently say what's required to use Bud.

    • Refactor, test and simplify the compiler (#93)

      The compiler wasn't really tested prior to v0.1.4. Issue that would crop up would be discovered due to E2E tests. In v0.1.5, the compiler was refactored to be testable, then tested. It was also simplified to reduce the number of ways you could use it programmatically. This makes it less likely a test will pass but the end-to-end usage will fail.

    • Extend the error chain (#100)

      Errors were being lost while merging the filesystems for plugins. Now errors that occur in generators will be extended through the merged filesystem, so it's easier to see when there are issues in the generators

    Source code(tar.gz)
    Source code(zip)
    bud_v0.1.5_darwin_amd64.tar.gz(15.09 MB)
    bud_v0.1.5_darwin_arm64.tar.gz(14.32 MB)
    bud_v0.1.5_linux_amd64.tar.gz(15.14 MB)
    checksums.txt(290 bytes)
  • v0.1.4(May 19, 2022)

    • Add support for custom actions (thanks @theEyeD!)

      This release adds support for defining custom actions on controllers that get mapped to GET requests. This feature closes: https://github.com/livebud/bud/pull/67.

      For example, given the following users controller in controller/users/users.go:

      package users
      type Controller struct {}
      func (c *Controller) Deactivate() error { return nil }
      

      The Deactivate method would get mapped to GET /users/deactivate. Learn more in the documentation.

    • Speed up tests by using existing GOMODCACHE

      Some of the test suite used an empty GOMODCACHE to test plugin support. This turned added about a 1-minute overhead to those tests while dependencies were downloaded and the cache was populated.

      We now rely on real module fixtures: https://github.com/livebud/bud-test-plugin and https://github.com/livebud/bud-test-plugin.

    • Add a version number to released assets

      This will make it easier to add Bud to other package managers like the Arch User Repository (AUR) for Arch Linux users. This feature fixes: https://github.com/livebud/bud/issues/52.

    • Added a background section to the Readme (thanks @thepudds!)

      @thepudds re-wrote the Reddit post, simplifying and condensing it for the Readme. I always like when projects include a "why", so I really appreciate @thepudds adding this for Bud!

    Source code(tar.gz)
    Source code(zip)
    bud_v0.1.4_darwin_amd64.tar.gz(15.21 MB)
    bud_v0.1.4_darwin_arm64.tar.gz(14.43 MB)
    bud_v0.1.4_linux_amd64.tar.gz(15.25 MB)
    checksums.txt(290 bytes)
  • v0.1.3(May 16, 2022)

  • v0.1.1(May 15, 2022)

    • Improve the installation script https://github.com/livebud/bud/pull/34 (thanks @barelyhuman!)

      For cases where /usr/local/bin is not writable, the install script will now prompt you to escalate your privileges.

    • Run Go's formatter on generated template files https://github.com/livebud/bud/pull/28 (thanks @codenoid!)

      Now the Go files generated into bud/ will be formatted with the same formatter as go fmt.

    • Fix bud create when working outside of $GOPATH https://github.com/livebud/bud/pull/31 (thanks @barelyhuman!)

      If you tried created a Bud project outside of $GOPATH, Bud would be unable to infer the Go module path and will prompt you to provide a module path. This prompt was being clobbered by NPM's progress bar. Now the prompt happens before running npm install.

    • Add a Contributor's Guide

      Wrote an initial guide on how to contribute to Bud. Please have a look and let me know if you'd like to see anything else in that guide.

    • Switch the default from 0.0.0.0 to 127.0.0.1 (#35)

      On the latest OSX you'll get a security prompt when you try binding to 0.0.0.0. On WSL, bud will just stall. This release switches the default to localhost (aka 127.0.0.1). Many thanks to @alecthomas, @theEyeD and @kevwan for helping me understand this issue better.

    Source code(tar.gz)
    Source code(zip)
    bud_darwin_amd64.tar.gz(15.27 MB)
    bud_darwin_arm64.tar.gz(14.48 MB)
    bud_linux_amd64.tar.gz(15.31 MB)
    checksums.txt(269 bytes)
  • v0.1.0(May 14, 2022)

  • v0.0.9(May 2, 2022)

  • v0.0.8(May 2, 2022)

  • v0.0.7(Apr 29, 2022)

  • v0.0.6(Apr 29, 2022)

  • v0.0.5(Apr 28, 2022)

  • v0.0.4(Apr 28, 2022)

    • Fix bud run after installing from Github

      When you build the binaries with --trimpath, it removes the import paths stored within the binary. This is preferable because you don't want to see my filepaths within the binary, but it also means that the downloaded binary was no longer able to find where the standard library packages were located. I fixed this by calling go env on boot. This adds about 7ms overhead on boot, so I'd like to find a way to do this without spawning, but we'll leave that as an exercise for the reader :)

      Another problem we encountered was that the runtime was missing some of the necessary embedded assets. I've removed them from .gitignore to fix the problem. Longer-term I think it makes sense to use bindata for this case to turn them into Go files that can be ignored in development but are built into the binary for production.

    • Add back missing node_modules

      I overpruned the dependencies and that was causing failures in CI. I added them back in.

    Source code(tar.gz)
    Source code(zip)
    bud_darwin_amd64.tar.gz(15.26 MB)
    bud_linux_amd64.tar.gz(15.29 MB)
    checksums.txt(179 bytes)
  • v0.0.3(Apr 28, 2022)

    • Bud is finally open source on Github!

      I'm thrilled to finally share my side project with everyone! I first started working on this while in lockdown in Berlin on April 20th, 2019. A co-worker suggested I have a look at the Laracast videos about Laravel. I was just blown away by how productive you can be in Laravel.

      As a former solo developer, I place a lot of weight on having all the tools you need to build, launch and iterate on ideas as quickly as possible. Laravel provides a comprehensive and cohesive toolset for getting your ideas out there quickly.

      With Go being my preferred language of choice these days and a natural fit for building web backends, I started prototyping what a Laravel-like MVC framework would look like in Go.

      At this point, I just had the following goal for Bud:

      • Be just as productive as Laravel in a typed language like Go.

      I got the first version working about 6 months in and I tried building a blog from it. It fell flat. You needed to scaffold all these files just to get started. If you're coming from Rails or Laravel you may shrug, this is pretty normal. Unfortunately, I've been spoiled by the renaissance in frontend frameworks with Next.js. What I love Next is that it starts out barebones and every file you add incrementally enhances your web application. This keeps the complexity under control.

      With these newly discovered constraints, I started working on the next iteration of Bud.

      • Generate files only as you need them. Keep these generated files away from your application code.
      • Should feel like using a modern Javascript framework. This means it should work with modern frontend frameworks like Svelte and React, support live reload and have server-side rendering.

      With these new goals, the Bud you see today started to take shape. But along the way, I discovered a few more project goals:

      • The framework should be extensible from Day 1. Bud is too ambitious for one person. We're going to need an ambitious community behind this framework.
      • Bud should have great performance for the developer using Bud and for the person using websites built with Bud. We have an exciting journey ahead for both of these goals.
      • Bud should compile to a single binary. These days with platforms services like Heroku and Vercel, it's easy to not care about this, but I still cherish the idea that I can build a single binary that contains my entire web app and scp it up to tiny server.

      And this is the Bud you see before you. I have big plans for the framework and I sincerely hope you'll join me on this journey.

    Source code(tar.gz)
    Source code(zip)
    bud_darwin_amd64.tar.gz(15.26 MB)
    bud_linux_amd64.tar.gz(15.29 MB)
    checksums.txt(179 bytes)
  • v0.0.2(Apr 27, 2022)

    Improve test caching

    The tests are slower than they should be. What was curious was that they didn't seem to be doing much during a lot of the test run.

    I dug into why and it turns out the test caching itself can be extremely slow. See this issue for more details: https://github.com/golang/go/issues/26562. It's slated to be fixed in Go 1.19, so I'm going to hold off on a fix for that.

    Additionally, the tests weren't ever being cached. If you'd like to read about the whole debugging saga that took a day to figure out, head over to this issue: https://github.com/golang/go/issues/26562. I've remedied this issue, but it's something to keep an eye on.

    Prep the build script

    I'm in the process of setting up curl -sf https://github.com/livebud/bud/install.sh | sh. In doing that, I'm ironing out the publishing pipeline and install script.

    Source code(tar.gz)
    Source code(zip)
    bud_darwin_amd64.tar.gz(15.25 MB)
    bud_linux_amd64.tar.gz(15.29 MB)
    checksums.txt(179 bytes)
Owner
Live Bud
Live Bud
Elastic Stack Docker + Sample Go AppElastic Stack Docker + Sample Go App

?? Elastic Stack Docker + Sample Go App Test Elastic Stack which includes Elasticsearch, Kibana, Filebeat and Metricbeat. It comes with a very simple

Ruben Delgado 0 Jan 14, 2022
goTempM is a full stack Golang microservices sample application built on top of the Micro platform.

goTempM is a full stack Golang microservices sample application built on top of the Micro platform.

null 26 Jun 13, 2022
stack-rpc 快速开发包

Micro 快速开发工具包 项目进行中 本仓库旨在提供面向 stack-rpc 生产环境的快速开发包。 目录 快速开始示例 控制台示例 以最常见的登录流程为例,实现一个场景简单,但包含微服务各种治理能力的示例 Hipster Shop示例 参考GoogleCloudPlatform/microser

Stack Labs 383 May 31, 2022
micro-draft-manager is a microservice that helps you to manage unstructured data in your application with sorting and full-text search

micro-draft-manager is a microservice that helps you to manage unstructured data in your application with sorting and full-text search. For example, y

Hamed Abdollahpour 1 Nov 24, 2021
Rpcx-framework - An RPC microservices framework based on rpcx, simple and easy to use, ultra fast and efficient, powerful, service discovery, service governance, service layering, version control, routing label registration.

RPCX Framework An RPC microservices framework based on rpcx. Features: simple and easy to use, ultra fast and efficient, powerful, service discovery,

ZYallers 1 Jan 5, 2022
Modern microservice web framework of golang

gogo gogo is an open source, high performance RESTful api framework for the Golang programming language. It also support RPC api, which is similar to

null 40 May 23, 2022
Go Micro is a framework for distributed systems development

Go Micro Go Micro is a framework for distributed systems development. Overview Go Micro provides the core requirements for distributed systems develop

Asim Aslam 18.6k Jun 25, 2022
Micro-service framework in Go

Kite Micro-Service Framework Kite is a framework for developing micro-services in Go. Kite is both the name of the framework and the micro-service tha

Koding, Inc. 3.1k Jun 26, 2022
NewSQL distributed storage database based on micro service framework

QLite 是基于微服务的 NewSQL 型数据库系统,与传统的一体化数据库不同,该系统将本该内置的多种数据结构(STL)拆分成多个服务模块,每个模块都是独立的一个节点,每个节点都与其主网关进行连接,从而形成分布式存储结构。

null 36 Jun 19, 2022
Kratos is a microservice-oriented governance framework implements by golang

Kratos is a microservice-oriented governance framework implements by golang, which offers convenient capabilities to help you quickly build a bulletproof application from scratch.

Kratos 18.2k Jun 29, 2022
RPC explained by writing simple RPC framework in 300 lines of pure Golang.

Simple GoRPC Learning RPC basic building blocks by building a simple RPC framework in Golang from scratch. RPC In Simple Term Service A wants to call

Ankur Anand 542 Jun 17, 2022
a microservice framework for rapid development of micro services in Go with rich eco-system

中文版README Go-Chassis is a microservice framework for rapid development of microservices in Go. it focus on helping developer to deliver cloud native a

null 2.5k Jun 29, 2022
The Go backend framework with superpowers

Encore - The Go backend framework with superpowers https://encore.dev Overview Encore is a Go backend framework for rapidly creating APIs and distribu

Encore 3.1k Jun 28, 2022
🦄🌈 YoyoGo is a simple, light and fast , dependency injection based micro-service framework written in Go.

???? YoyoGo is a simple, light and fast , dependency injection based micro-service framework written in Go. Support Nacos ,Consoul ,Etcd ,Eureka ,kubernetes.

YoyoFx 542 Jun 24, 2022
Kratos is a microservice-oriented governance framework implements by golang,

Kratos is a microservice-oriented governance framework implements by golang, which offers convenient capabilities to help you quickly build a bulletproof application from scratch.

Kratos 18.2k Jun 22, 2022
Fastglue is an opinionated, bare bones wrapper that glues together fasthttp and fasthttprouter to act as a micro HTTP framework.

fastglue Overview fastglue is an opinionated, bare bones wrapper that glues together fasthttp and fasthttprouter to act as a micro HTTP framework. It

Zerodha Technology 71 Jun 14, 2022
Another excellent micro service framework

xservice [WIP] Another excellent micro service framework Features RESTful API (base on echo/v4) gRPC & gRPC gateway service & Swagger document generat

新片场 9 May 28, 2022
Kitex byte-dance internal Golang microservice RPC framework with high performance and strong scalability, customized extensions for byte internal.

Kitex 字节跳动内部的 Golang 微服务 RPC 框架,具有高性能、强可扩展的特点,针对字节内部做了定制扩展。

CloudWeGo 4.6k Jun 30, 2022
Solution & Framework for JSON-RPC over HTTP

JROH Solution & Framework for JSON-RPC over HTTP Why not OpenAPI? OpenAPI addresses the definition of RESTful APIs, when it comes to JSON-RPCs, some i

Go Toolkit 11 Mar 13, 2022