ON Golang

Creating an IOS shortcut to open my door with Golang and Vercel

How I used Golang and Vercel to create an IOS Shortcut that allows me to open my front door.

1. Introduction

My apartment building is using an automated system to unlock the front door. We have to use a proprietary app (AlphaTouch) and unlock the door by sliding a toggle. It takes time because the app is slow. Let’s find a way to make this easier!

Goal

Let’s have an iOS Shortcut instead! I will just have to press it on my phone home page. It’s possible to create a Shortcut that execute a http request
I would like to have a simple endpoint (http://myendpoint.something/unlock_door)

2. Let’s find a way to open my door without the App

Alphatouch provides an APP and a Website. When we open the website, we can see a “Trigger Open Door” button. Let’s click on it and check the network calls open door network calls

We can see that clicking this button fire a network call that I suppose open the door (the url is .../trigger_pin.php)

Before going further, let’s copy this command call as cURL (using the DevTools again) and let’s fire this CURL call again while I am in front of my door.
Success! The door open!

This network call contains tons of headers + query params + a body. We could just fire it from our iOS shortcut, but let’s make things easier and play with serverless functions instead!

3. A Go program triggering our cURL code

I chose to use Go because this is what I am using every day. We could use Python or JS, both are supported by serverless functions and may be faster to write, but I like Go syntax.

Let’s create a new folder/repository for our program. First, we need a simple function that triggers our http call.

To convert our complex cURL call to Go code, we can use this website: https://mholt.github.io/curl-to-go/

internal/open_door_entry/open_door.go
package open_door_entry
 
import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"strings"
)
 
// By looking at the response from the HTTP Call, we can see that we get a JSON object contain a "success" variable
// Let's declare this object in Go in order to parse the reponse and monitor error/success
// It's easy to do with Jetbrains IDE, especially Goland. You can do "CMD+N" and "Type from JSON"
type openDoorResponse struct {
	Success bool `json:"success"`
}
 
func createReq() (*http.Request, error) {
    // generate this code using https://mholt.github.io/curl-to-go/
	req, err := ...
	return req, nil
}
 
// the function that will open our Door.
func OpenDoor() error {
	req, err := createReq()
	if err != nil {
		return err
	}
 
    // let's execute the query
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	
	if resp.StatusCode != 200 {
		return errors.New(resp.Status)
	}
	
	
	// reading the body...
	defer resp.Body.Close()
	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}
 
	// parsing the body
	var openDoorResp openDoorResponse
	err = json.Unmarshal(b, &openDoorResp)
	if err != nil {
		return err
	}
 
    // Checking response success
	if openDoorResp.Success {
		return nil
	}
	return errors.New("error success=false from response")
}
 

4. Let’s deploy this to Vercel

This piece of code is very small and fast to execute (~1sec, most of the time is spent in the http call) I plan to trigger this ~5 times a day (everytime I want to open my front door).

I found that the cheapest way to host this is to use serverless tech.
There are multiple offerings here, the most popular are:

I heard good things about Vercel and I wanted to try them for a while. They are supposed to deliver the best dev experience.

Let’s try this out!
After looking at their website, they offer Serverless Functions. As a part of their Free plan, you have access to:

  • 100GB-Hours
  • 10s function timeout

That’s perfect for our use case! Let’s set this up.

  • Create an account on Vercel
  • Install their CLI (yarn global add vercel) (you will need nodejs + yarn installed for this)
  • Login with their CLI vercel login
  • Create an empty package.json at the root of your folder/repository (echo '{}' > package.json)
  • Link this repository to your vercel account vercel link (you can delete the package.json after this step!)
  • Then let’s refactor our repository to support their architecture! We just need a api folder at the root!
  • This api folder will contain all our “functions entrypoint”

Every function with a specific signature in this folder will be a Serverless Function. Let’s create ours!

// api/open_door.go
package handler
 
import (
	"net/http"
 
    // the func we just made before
	"dimitriwyzlic.com/serverless_functions/internal/open_door_entry"
)
 
// Any function using this signature will be a Serverless Func
func OpenDoor(w http.ResponseWriter, r *http.Request) {
	err := open_door_entry.OpenDoor()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(err.Error()))
	} else {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Success!"))
	}
}
  • Once this is done, just run vercel dev
  • You will be able to query localhost:3000/api/[your_file_name_without_extension]
  • If it’s working, just run vercel prod
  • Now, go to the Vercel website and select your project. Get your prod url by looking at the following image vercel deployment
  • Click on Logs then on the left panel, expand Function and select your function.
  • Open a new tab and call [your prod url]/api/open_door (replace open_door with whatever your file under api is named)
  • If you go back to the previous tab containing your logs, you should see your call in real time!

vercel logs

5. Conclusion

Congratulation! You now have a working Go function hosted on the cloud that should be free forever!

I wanted to have an iOS shortcut that will allow me to open my door. The last step is just to create a shortcut with the Open URL or Get contents of action!

Final thoughts

This was a fun little side project — if you're building cooler things than most people, I'd love to hear about it.

You're building cooler things
than most people think.

Let's connect
24 6