Custom Made Dakboard Alternative for Raspberry Pi — Part 2
Part 2 — Dropbox HTTP Requests with Golang
Part 4 — Custom Calendar for Custom Dakboard (coming soon)
In part 1, we registered an app with Dropbox in order to make HTTP requests to retrieve image URLs stored in our project folder. In this section, we are going to cover making the HTTP requests to retrieve and parse needed data (image URLs) to render to our custom web page. Dropbox actually has a pretty comprehensive API documentation for making requests. They even have an API “explorer” where you can test making HTTP requests for each endpoint they support.
You can play around in this explorer if you’d like, but we are going to let Golang do the heavy lifting. The first thing we need to do is create a configurations file to save credentials, parameters, metadata, etc, etc. If you’re familiar with go, then go ahead and create a project folder within the src folder of your $GOPATH. In this folder, create a yaml file called conf.yml. Yaml (Yaml. Ain’t. Markup. Language) is
a human friendly data serialization
standard for all programming languages.
If you’ve ever used Docker and created a Dockerfile, then Yaml will feel right at home for you.
Remember the token I had you save from part 1? Well this is where we are going to put it. We are also going to store two URL endpoints in this file as well. The reason for this is because we want to avoid hard coding any variables that could possibly change in the future. By storing variables in a config file, you’ll never have to sift through hundreds, maybe even thousands of lines of code looking for all the hard coded variables that you need to update.
First, replace the ******* with your token that was generated from your registered app. Second, DO NOT remove the “Bearer” prefix. This is needed in the request to Dropbox (That part took way too long for me to figure out initially). You’ll also notice the “get_link_api_url” and “list_link_api_url” parameters in the conf.yml. These are the Dropbox endpoints for…you guessed it….getting a link and listing items from a Dropbox folder. These can be found in the documentation I referenced earlier. These could possibly change in any future updates Dropbox may make. Therefore, I’m storing them here in the conf.yml.
So why the two links if we just need to get an image URL? Dropbox is kind of funny in that, we can’t just ask for it to give us an image URL for every item in our “images” folder. We must specify to Dropbox which image we want a URL for by giving it the image path AND name. This can be seen in the API explorer
When I make a request to the get_link_api_url (which is just the HTTP request to get a temporary url link for a file) with the path parameter set as our “images” folder, we get an error response. But when I pass our images folder plus the name of an actual image I have in the folder, we get the following response
This highlights the given point. In order for Dropbox to give us an image link to use, we must first supply Dropbox with the desired image path and name. Since we could potentially have hundreds to thousands of images within our images folder, we definitely don’t want to code out a request manually for every image. It would also be too tedious of a task to manually code the name of every image in the folder. This is where the list_link_api_url endpoint comes in. As you can see below, when making a request to this endpoint, Dropbox responds with all images contained in the folder (plus some metadata).
The server clearly is responding with a JSON object containing a lot of information for each image. We can parse this data using Golang, extracting only what we need (image names) and pass those to Dropbox to get a link for rendering our images on a web page. So let’s do that now.
Back in our project folder, create the following files
Really, you could do everything that we are about to do in main.go. But I’m separating them out for readability and manageability. httprequests.go will be our source for all things HTTP related. configs.go will be the home for all yaml configurations logic and parsing. main.go, is just main lol. and htmlscript.go will handle the templating for our custom web page. Finally, add a “static” folder to your project folder as well. This will house all the html, css, js scripts that we serve up for the web page. Your project folder should look like the following (excluding .gitignore and README.md):
The first thing we need to do is parse the conf.yml and store the parameters to exported variables to be used throughout the code base. In configs.go, type the following :
In the script above, we’ve:
- imported the “io/ioutil” and “gopkg.in/yaml.v2” packages.
- Initialized some variables — notice the Capital letters meaning these variables are exported
- Created a “Yaml” struct which is just a struct of the exact parameters we have in the conf.yml to be deserialized from the yml file.
- Created a “getConf()” method for the “Yaml” struct that reads in the conf.yml and unmarshalls the bytes into the Yaml struct.
- Created a “Getconfigs()” function that makes use of the “Yaml” struct and its “GetConf()” method and then references the declared variables to the parameters in the conf.yml — again, notice the capital letter of the function.
This takes care of the configurations parsing. In the event that anything ever changes with our conf.yml, we can simply come to configs.go and make the appropriate changes. Next up, we will handle the HTTP requests and response parsing.
In httprequests.go, add the following 103 lines of code:
3–8) Import the required packages
16–18) Create a struct to handle the response from Dropbox when listing the images in our image folder. Refer to Fig 5 and notice that the response contains an array index of “entries” that contains all the files in the folder.
23–26) Create a struct to handle the nested data under “entries” from the response. Extract only “path_lower” and “name” from the response
29–31) Create struct to unmarshal the temporary link reponse from Dropbox. Refer to Fig 4.
37–76) Create function that makes HTTP POST request to Dropbox to list all images in the folder. The request body is made, followed by a request constructor. The headers for the request are then set. Next, send the request and unmarshal the response. Each individual entry (image) is then sent across a channel for another function to handle the next step. Also notice the length of Entries is sent across another channel at line 66. This will be used to kill the channel later.
79–103) Create a HTTP POST request to send the image paths and names to Dropbox to create a temporary link. The results are then sent across another channel to be handled later.
A few things to note, you’ll notice at various place in the code
This is a defined function in main.go (not shown yet) for standardized error handling. You’ll also notice that the two functions mentioned above take in channels. This is a bit of a spoiler, but we will be using these functions as go routines for concurrency patterns. Concurrency is out of scope for this read, but the following image should help illustrate what it is. I leave it to the reader to research more into concurrency vs parallelism vs sequential execution.
The tl;dr explanation of what we just did is, a request is made to Dropbox to give us all the images in the image folder. Dropbox responds with a lot more information than we need. So we parse out what is desired (image name and path), and trash the rest. That info will then be passed to another function that will take the image paths and name, create another request to Dropbox to get a temporary link (URL) that we can use to render in our html. Those links are then sent across another channel to be picked up and used by another function (not shown yet).
To test our functionality (assuming you have images in your image folder), open up main.go and insert the following:
Here, you can see what the
function is doing. We are also creating the channels that the data will be sent across for each function. Don’t worry about what the imgLinks channel is just yet. That will come later. Just remove that line from your test script so the code will execute. Finally, in main, we are calling our Getconfigs() function that reads in the parameters from conf.yml. We are also calling our two HTTP POST functions. Notice the prefixed “go” before each of them. This is creating the go routines for concurrency. And finally, we are creating an infinite loop to dump the final outputting channels from each function. In Golang, channels are blocking by nature. So if nothing is receiving the data put on a channel, that channel will block the execution of further code until its data has been dumped. One final thing, we want to see some output written to std.out to view what our functions are returning. To do this, I just simply added some
calls before data is being sent across channels in the functions contained in the httprequests.go script.
Now all we have to do is open up a command prompt and type
go run *.go
You should see something like the following
Notice next to “Data:” prefix, we get a path and a name; exactly what we parsed out from ListImagesFromDropbox function. And next to the “Temporary Link (URL)” prefix, we have a very long url link starting with https://….. You can actually click this link.
Coming up next, we will walk through how we take all these links, embed them in html and serve our web page on a localhost server.