Photo by Heliberto Arias on Unsplash
Some time ago I wrote an article on how to run gRPC through a web application without Envoy. I’m going to use the project in this article, and embed the web application into a binary. If you’re not familiar with the project I suggest reading part one.
But if you only want to learn how to use the embed package in Go you should be able to follow this article without prior knowledge.
Why would we want to include things like an web application in a binary?
For me, it’s all about the deployment. Being able to just send a single binary to a server is a big time saver.
Before Golang 1.16 (this is when the embed package was released), we would need to deploy the binary, and the web application, or any other files we needed that wasn’t compiled code.
But, lets be honest, sometimes it would make much more sense with a binary than a docker.
Lets get started setting the project up
Before we start coding lets grab the project that we will modify.
mkdir embedding && cd embedding git init git pull https://github.com/percybolmer/grpcexample
Its a super simple gRPC API that has an Ping function, and a React application that is hosted on localhost:8080 which will call the Ping function each third second. This is not important for the tutorial, you can use any other web application. If your interested in reading more about the project, see part one of this series.
If you are using the project you need to generate certificates, if you haven’t already. Go into the cert folder and run the certgen.sh script. This will require you to have openssl installed.
cd cert bash certgen.sh
We will also need to compile the react application that we are embedding. The application is located inside the ui folder.
Before running the build commands make sure you add two lines to the package.json file. We need to tell the React application that these files will be served without a server.
Add the two lines below to
“homepage”: “.”, ”proxy”: “https://localhost:8080",
Run the following commands.
npm install npm run build
npm install will download any needed dependencies, and
npm run build will build a static application located inside a new folder called build. This is the folder that we will embed later.
You will also need to run at least Golang 1.16. Test your installation by running
Once your all setup, open main.go.
You can read about the embed package here.
What we need is to embed our build folder and embed that into our binary as an filesystem. I recommend reading the linked package docs, its really short and explains everything very well.
The embed package differs from the rest of the packages I’ve seen before. We will actually use comments to tell the compiler what action to perform.
The syntax is short and concise.
//go:embed $PATH var content $WANTED_DATA_TYPE
There is 2 lines of code, one comment and one variable declaration. They have to be directly after each other, starting with the comment.
$WANTED_DATA_TYPE? Those needs to be replace.
$PATH should be replaced with the path to the files or directories you want to include. A side note is that if you use the data type
embed.FS, it accepts multiple paths in one comment, and also many comments at the same time.
$WANTED_DATA_TYPE is to be replaced with the any of the available data types:
- String = Accepts a single file and upon building will read the content of that file into the variable as a string
- Byte = Same as String, but as a Byte
- embed.FS (Short for filesystem) = Now this is where embed gets exciting for me. We are allowed to embed multiple directories and files. And the best part, they are part of the io/FS interface. This means net/http package can use this out of the box.
With this new knowledge, lets update
main.go to embed the build folder at
In the old
main.go the path is hard coded, that needs to be changed into an embedded filesystem. Lets build the binary and run it
go1.16beta1 build -o api . && ./api
Visit localhost:8080 and watch the status change from false to true after 3 seconds!
That’s it! I’ve gotta hand it to the team at Golang, they’ve made this super simple. We have in just 2 new lines of code added a embedded web application to our binary.
If your interested, feel free to read Part 2 about implementing gRPC interceptors.
Email : firstname.lastname@example.org
Website : https://programmingpercy.tech