Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support higher order functions instead of receivers #8

Open
crhntr opened this issue Aug 22, 2024 · 1 comment
Open

Support higher order functions instead of receivers #8

crhntr opened this issue Aug 22, 2024 · 1 comment
Labels
enhancement New feature or request go-to-go

Comments

@crhntr
Copy link
Owner

crhntr commented Aug 22, 2024

The syntax for template names is kind of like a single method interface.
The method parameter types are based on known identifiers.
The method signature itself can be a call on an interface but instead of methods on an interface, we can generate calls to functions that return a method.
The returned function could be expected to match the method signature.

Given a template has name `GET / F() as Index`
When `must generate` is executed
Then a function with signature `func Index() http.HandlerFunc` should be generated
And it instead of using a function literal the `routes` function should invoke `mux.HandleFunc` like so: `mux.HandleFunc("GET /", Index())`

Many Gophers (myself included) often prefer to write higher order functions for handlers instead of methods (see https://changelog.com/gotime/322). So we should support that.
I suspect a decent experience would be to have the handler method invoked in the generated http.HandlerFunc refer to the higher order function name. The first order parameters should be sorted by name and added to the routes function and the result signature should be invoked like we invoke receivers. This behavior effectively adds dependency injection for better ∨ worse.

So given a go and template source files:

package hypertext

import (
	"net/http"
	"example.com/models"
)

func Welcome(db models.Querier) func(context.Context, int) any { return nil }
{{define "GET /welcome/{userID} Welcome(ctx, userID)"}}Hello, {{.Name}}!{{end}}

Then the generated routes function should be:

// Code generated by muxt. DO NOT EDIT.

package main

import (
	"context"
	"net/http"
	"strconv"
	"bytes"
)

func routes(mux *http.ServeMux, db models.Querier) {
	mux.HandleFunc("GET /welcome/{userID}", func(response http.ResponseWriter, request *http.Request) {
		ctx := request.Context()
		userIDParsed, err := strconv.ParseInt(request.PathValue("userID"), 10, 64)
		if err != nil {
			http.Error(response, err.Error(), http.StatusBadRequest)
			return
		}
		userID := int(userIDParsed)
		data := Welcome(db)(ctx, userID)
		execute(response, request, true, "GET /welcome/{userID} Welcome(ctx, userID)", http.StatusOK, data)
	})
}

func execute(response http.ResponseWriter, request *http.Request, writeHeader bool, name string, code int, data any) {
	buf := bytes.NewBuffer(nil)
	if err := templates.ExecuteTemplate(buf, name, data); err != nil {
		http.Error(response, err.Error(), http.StatusInternalServerError)
		return
	}
	if writeHeader {
		response.WriteHeader(code)
	}
	_, _ = buf.WriteTo(response)
}
@crhntr crhntr added the enhancement New feature or request label Aug 22, 2024
@crhntr
Copy link
Owner Author

crhntr commented Aug 30, 2024

I might want to call Welcome once outside of the call scope. This would be adding logic to the routes function (currently it only registers routes). This would then allow each handler to do its setup once before returning the method.

@crhntr crhntr changed the title Allow template Names to specify a function name Support higher order functions instead of receivers Aug 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request go-to-go
Projects
None yet
Development

No branches or pull requests

1 participant