gin gonic nested templates - go

Go base lib's template has method Execute which allows to reference another template in order to use template nesting, like follows:
template.Template.Execute("base", data)
Also see this SO question.
How can I achieve the same but inside gin tonic's http response handler? Typically it looks like this
func about(c *gin.Context) {
c.HTML(http.StatusOK, "about.tmpl", gin.H{})
}
Which leaves no way to reference another template like with execute.

Related

Why should I make a copy of a context for goroutines inside handlers?

I recently started rewriting some of my Python services in Go to speed them up and came across this section of the gin documentation:
https://github.com/gin-gonic/gin#goroutines-inside-a-middleware
So I understand the instructions, but I'm trying to understand why? What is the significance of making a copy, and what problem is introduced if I do not make a copy of context for goroutines within handlers?
Gin-gonic is async itself which makes it great.
If you are using concurrency within your handlers it's very likely you will face situation when Context, which is struct goes
outdated since it's holding the data from each request (parameters, keys protected by mutex)
empty, which will cause a fallback to default Context
here's how it looks like:
type Context struct {
writermem responseWriter
Request *http.Request
Writer ResponseWriter
Params Params
handlers HandlersChain
index int8
fullPath string
engine *Engine
params *Params
skippedNodes *[]skippedNode
// This mutex protects Keys map.
mu sync.RWMutex
// Keys is a key/value pair exclusively for the context of each request.
Keys map[string]any
// Errors is a list of errors attached to all the handlers/middlewares who used this context.
Errors errorMsgs
// Accepted defines a list of manually accepted formats for content negotiation.
Accepted []string
// queryCache caches the query result from c.Request.URL.Query().
queryCache url.Values
// formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,
// or PUT body parameters.
formCache url.Values
// SameSite allows a server to define a cookie attribute making it impossible for
// the browser to send this cookie along with cross-site requests.
sameSite http.SameSite
}
In order to foresee such issues and race conditions - you must use Copy whenever your handlers are using go concurrency
here's a quote from gin-gonic repository:
// Copy returns a copy of the current context that can be safely used outside the request's scope.
// This has to be used when the context has to be passed to a goroutine.

How can I use the bot composer to dynamically configure the body part of a HTTP REQUEST

I am using Bot Composer to publish my first chatbot. I need to construct the chatbot to send out an HTTP POST request to fetch external resources from a remote website. As specified by the composer interface, I can embed JSON, form data, or string in the body of the HTTP POST request. Instead of hard-coding the body part of the POST request, I need to pass in one or multiple properties (chatbot's variable) to generate the body of the HTTP POST dynamically. Here are my questions:
(1) can I pass a variable to the body part of the HTTP REQUEST (such as POST)? can I embed a property such as $(user. name) in the HTTP POST body?
For example, can I embed a property such as $(user.name) in a string or form data (such as fname=$(user. name) to construct the body part of the HTTP POST REQUEST?
(2) The document specifies that there is a pre-build function JSON to serialize data. If I understand correctly, I can't pass a variable (such as $(user. name) to the JSON pre-built function. Therefore, I will probably need to embed an expression in the body to pass the variable. Yet, I couldn't find any detailed information. Is there anywhere I can find a good example showing how to write an expression inside the body part of the HTTP REQUEST
Thanks for any information/assistance.
Yes, you can do this. The simplest way is to set the body to Object and then put in your structured json, something similar to:
{
"userinfo": {
"username": "${user.username}",
"name": "${user.personalname}",
"favoritecolor": "${user.favcolor}",
"profileupdated":"${dialog.userprofileuptodate}"
}
}
I am trying to figure out how to set it up in an adaptive expression in LG, and then be able to refrence it with something like:
# APIBodyTemplate()
-```
{
"userinfo": {
"username": "${user.username}",
"name": "${user.personalname}",
"favoritecolor": "${user.favcolor}",
"profileupdated":"${dialog.userprofileuptodate}"
}
}
```
And then using something like the following in an expression in the body field:
=json(APIBodyTemplate()), but that is not quite working yet. Might be a bug. I will update when I have more info.

path param in URL in GO without any web framework

While developing a REST api in Go, how can we use path params? meaning to say what will be the format of the URI?
http://localhost:8765/myapp/{param1}/entries/{param2}
I tried using something like this to create the route but the handler function is not getting invoked.
Please note that, i intent to use only the net/http package , not any other web framework like gorilla mux.
What I tend to do is nested handlers. "/" is handled by the root handler. It pops the first part of the path, assigns the rest back to req.URL.Path (effectively acting like StripPrefix), determines which handler handles routes by that prefix (if any), then chains the appropriate handler. If that handler needs to parse an ID out of the path, it can, by the same mechansim - pop the first part of the path, parse it as necessary, then act.
This not only has no external dependencies, but it is faster than any router could ever be, because the routing is hard-coded rather than dynamic. Unless routing changes at runtime (which would be pretty unusual), there is no need for routing to be handled dynamically.
Well this is why people use frameworks like gin-gonic because this is not easy to do this in the net/http package IIUC.
Otherwise, you would need to strings.Split(r.URL.Path, "/") and work from those elements.
With net/http the following would trigger when calling localhost:8080/myapp/foo/entries/bar
http.HandleFunc("/myapp/", yourHandlerFunction)
Then inside yourHandlerFunction, manually parse r.URL.Path to find foo and bar.
Note that if you don't add a trailing / it won't work. The following would only trigger when calling localhost:8080/myapp:
http.HandleFunc("/myapp", yourHandlerFunction)

Variables for goroutines

Im currently making a web app using Go. I want to know on my templates when the user is logged in or not and I am currently making it using this approach
response := &viewCharacter{true}
template.Renderer.ExecuteTemplate(w, "character_search.html", response)
As you see I am passing a viewCharacter struct that only contains a bool Logged then on a template I can do the following
{{ if .Logged }}
Is there any other approach to do this? instead of passing on each template a logged bool?
Maybe setting a variable for each goroutine of the http handler that saves if the user is logged or not?
There are only two ways that I know to communicate between the go code and the template.
The first one is the one you use. By passing a struct to the ExecuteTemplate function you can access all its field in the template.
The second one is to register other functions using:
func (t *Template) Funcs(funcMap FuncMap) *Template
See documentation for more information. The funcMap is a simple map[string]interface{}, you can register any function and call it in the template by using its name (the key of the map).

GoLang Gin Framework Status Code Without Message Body

I'm using GoLang and Gin Framework.
I need to respond for REST API call with 204 response code without message body.
How it is to do properly?
What I could find by digging the source code
c.JSON(204, "")
But server throws error at such case:
Error #01: http: request method or response status code does not allow body
Meta: []
Any ideas?
You could use c.AbortWithStatus(204), with the one caveat that when you use abort, the rest of pending handlers will never be called for that request.
Or, you could do:
c.Writer.WriteHeader(204)
and let your program continue normally (but making sure not to write out anything else)
adding on #depado comments,
c.Status(http.StatusNoContent) is the simplest way to achieve this.
Works with gin v1.6.3
up to now, the function Abort's prototype is
func (c *Context) Abort()
you can use AbortWithStatus instead c.AbortWithStatus(204), whose prototype is
func (c *Context) AbortWithStatus(code int)

Resources