Overview
Golang 1.16 new package embed
helps you manage static assets, embedding them in the application binary and making them easy to use. Any files from a package or package subdirectory can be embedded and retrieved as a variable of type string
or bytes[]
.
import _ "embed"
//go:embed hello.txt
var s strings
//go:embed hello.txt
var b []bytes
Besides, you can also retrieve your embedded files with a variable of type FS
. You can even define which file needs to be embedded in your application using a glob pathname.
import "embed"
//go:embed assets/*
var f embed.FS
Use case: Using embed in a SlackBot
Given how easy it is to create and edit your messages using Block-kit Builder, I believe that the most convenient method to design and maintain your SlackBot is to save the design created with Block-kit as a json
payload. The new embed
package is the perfect feature for This case.
In terms of design pattern, those json
payloads represent the View in a classical MVC application. Besides, we can send those messages as is or use some templating to include any data.
In my tutorial series Slackbot in Golang with Socket Mode, I have used this method in all my Views
in combination with go markup language. In this section, I will be demonstrating how to manage a greeting message designed with Block-kit. I will only focus on the View
part of the application, ignoring the implementation of Model
and Controller
along. Nevertheless, feel free to peak at them in my git repository; Also, I am writing a set of articles covering those details.
Create a Message with Block-kit
In this step, no code required! Go to Block Kit Builder, customize the template, copy the json
payload and, save it into a file. In my case: greeting.json.
Next, edit this template to make it customizable using go markup language. For instance, I want to add the name of the user that recieve the message, then the text for the message will likke like this:
Hi {{ .User }} :wave:
After rendering the template, I would expect (if my user is called David)
Hi David :wave:
Render the Message
First, let's use embed
and declare a variable greetingAssets
that refers to our asset folder.
import (
"embed"
)
//go:embed greetingViewsAssets/*
var greetingAssets embed.FS
Second, let's create a function that takes the user
name as a string and returns a slice of slack.Block
. Those slack.Block(s) represent the blocks we have created with Block-kit and saved into the file greetingViews/greeting.json
. You can use them with the PostEphemeral
function to send the greeting message to a user.
func GreetingMessage(user string) []slack.Block {
// [TODO]: parse the template `greetingViews/greeting.json`
view := slack.Msg{}
// [TODO]: unmarshal the template into slack.Msg{}
return view.Blocks.BlockSet
}
Next, we want to render greetingViews/greeting.json
using greetingAssets
and the user name provided as input for our function. To do so, I created a small utility function because we might reuse it across our application. This function takes as arguments a variable of type fs.FS
such as greetingAssets
, the path of the file to use as a template and, a variable of type interface{}
that represents any struct that contains data to interpolate in the template.
func renderTemplate(fs fs.FS, file string, args interface{}) bytes.Buffer {
var tpl bytes.Buffer
// read the block-kit definition as a go template
t, err := template.ParseFS(fs, file)
if err != nil {
panic(err)
}
// render the template using provided datas
err = t.Execute(&tpl, args)
if err != nil {
panic(err)
}
return tpl
}
Finally, we put all the pieces together:
- read the block-kit definition as a go template and interpolate data
- unmarshal the template into slack.Msg{}
func GreetingMessage(user string) []slack.Block {
// we need a stuct to hold template arguments
type args struct {
User string
}
tpl := renderTemplate(greetingAssets, "greetingViews/greeting.json", args{User: user})
// we convert the view into a message struct
view := slack.Msg{}
str, _ := ioutil.ReadAll(&tpl)
json.Unmarshal(str, &view)
// We only return the block because of the way the PostEphemeral function works
// we are going to use slack.MsgOptionBlocks in the controller
return view.Blocks.BlockSet
}
Conclusion
The new Golang v1.16 embed
directive lets us keep a single binary and bundle out static content. I like the convenience it offers when designing SlackBot using Block-kit.
The source code of the use case can be found here, as well as more use cases and work in progress ideas around creating SlackBots.
Interesting Articles tackling embed
in a different context
- Working with Embed in Go 1.16 Versions
- Golang embed static assets in binary (with React build example)
- How to Use //go:embed
Top comments (0)