Demo application for talking with Withings API. It is written in Go with few dependencies, and uses PostgreSQL as a database. The code is organized using DDD-ish / Clean Architecture-ish principles, based on the book and articles by https://threedots.tech/.
- Lets users log in with Withings OAuth and stores their access token in the database.
- Lets users subscribe to notifications from Withings.
- Stores received notifications in the database.
- Downloads available data relevant to the received notifications and stores it in the database.
- Forward received notifications and their payloads to webhooks, IFTTT, Dropbox, Google Drive, etc.
- Download historical data, not just data corresponding to notifications.
Withoutings uses a pragmatic stack that is simple to maintain and deploy:
- Go
- PostgreSQL
- Server-side rendering with Go's html/template
- No JavaScript so far. But might add HTMX.
- Redis (unlogged tables are good enough)
- ORM (sqlc is superior)
- Dedicated queue/pubsub (Postgres all the way!)
The application serves a website and runs services that talk with the Withings API. Therefore it must have a public URL that can receive webhooks sent by the Withings Notification service.
Go to the Withings Developer Dashboard. Create a new application.
See env.example.sh. Make a copy of it named env.dev.sh
and fill in the values.
source env.sh && go run cmd/main.go
The webhook secret must be added in the registered callback path in the Withings Developer Dashboard.
See env.example.sh
.
To receive webhooks in your development environment, you can forward a remote port to your local port.
Withings calls https://withings.mywebsite.com/auth/callback
which is
forwarded to port 3628 on the server (e.g. using Caddy or nginx), which
is again forwarded to port 3628 in your development environment.
# Using SSH
ssh -R 3628:127.0.0.1:3628 -N -f myuser@withings.mywebsite.com
Set up Tailscale on your development machine and the server. Then add the following to your Caddyfile:
withings-dev.example.com {
reverse_proxy /* <dev-machine-name>:3628 {
}
}
The server must also listen on the Tailscale interface. Configure that in env.dev.sh
.
export WOT_LISTEN_ADDR='<dev-machine-tailscale-ip>:3628';
Migrations are managed using golang-migrate. The library is embedded in the build, so you can run migrations using withoutings migrate
.
Append a new migration file in the migration
directory.
source env.sh && withoutings migrate
Manually revert by executing the down
SQL from the migration file.
Remember to also decrement the migration version in the schema_migrations
table.
Go code is generated from SQL queries using sqlc. The schema is inferred using the migration files.
brew install sqlc
# or
go install github.com/kyleconroy/sqlc/cmd/sqlc@latest
Mocks are generated using mockery.
Install mockery
brew install mockery
For now, you have to generate mocks using go generate.