In this post, we'll walk through how to access Google Calendar events using Elixir and Phoenix, leveraging the Req
HTTP client and Goth
for authentication with Google APIs.
My first approach was to use the raw ICS file, but that turned out to be quite tricky to parse (especially with repeating events).
Add the required dependencies
To get started, open your mix.exs
file and add these dependencies:
defmodule MyApp.MixProject do
use Mix.Project
defp deps do
[
{:req, "~> 0.5.0"},
{:goth, "~> 1.4"}
]
end
end
Don't forget to run mix deps.get
to install them.
Setting up Google Calendar API access
Before you can query a Google Calendar, you need to create service account credentials:
- Go to Google Cloud Console.
- Create a new project (or select an existing one).
- Navigate to APIs & Services > Credentials.
- Click Create Credentials > Service Account.
- After creating the service account, go to Manage Keys and create a JSON key.
This will download a JSON file containing your credentials.
Save it somewhere accessible in your Phoenix project, for example at config/gcp-creds.json
.
Still in the Cloud Console:
- Go to APIs & Services > Library.
- Search for Google Calendar API and enable it for your project.
The service account email (from the credentials JSON) must have access to the calendar (unless it is a public calendar):
- Go to Google Calendar.
- Open the calendar settings.
- Under Share with specific people, add the service account email and give it at least See all event details permission.
Authenticating with Goth
Use the Goth
library to authenticate with Google APIs. Configure it in your lib/my_app/application.ex
:
defmodule MyApp.Application do
use Application
# Read in the credentials file
@google_credentials File.read!("config/gcp-creds.json") |> Jason.decode!()
@impl true
def start(_type, _args) do
children = [
MyAppWeb.Telemetry,
MyApp.Repo,
{DNSCluster, query: Application.get_env(:my_app, :dns_cluster_query) || :ignore},
{Phoenix.PubSub, name: MyApp.PubSub},
# Start the Finch HTTP client for sending emails
{Finch, name: MyApp.Finch},
# Add Goth as a child
{Goth,
name: MyApp.Goth,
source:
{:service_account, @google_credentials,
scopes: ["https://www.googleapis.com/auth/calendar.readonly"]}},
# Start to serve requests, typically the last entry
MyAppWeb.Endpoint
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
Goth will fetch and cache access tokens for the service account automatically.
Get the calendar ID for your Google Calendar
The calendar ID is a required parameter when accessing Google Calendar events through the API, and here's how you can find it:
-
Go to Google Calendar.
-
On the left under My calendars, hover over the calendar you want to use.
-
Click the three dots (โฎ) next to the calendar name and choose Settings and sharing.
-
Scroll down to the Integrate calendar section.
-
You'll see the Calendar IDโit looks something like:
yourname@gmail.com
or for shared/team calendars:
abcd1234@group.calendar.google.com
Fetching events with Req
The function below fetches calendar events for a given year:
def get_events(calendar_id, year, opts \\ []) do
# First get an authentication token using Goth
{:ok, token} = get_token()
# Get the event using the Google Calendar API
get_events_from_calendar(calendar_id, year, token)
end
defp get_token() do
Goth.fetch(YellowduckBe.Goth)
end
defp get_events_from_calendar(calendar_id, year, token) when is_integer(year) do
{:ok, resp} =
Req.get("https://www.googleapis.com/calendar/v3/calendars/#{calendar_id}/events",
headers: [
Authorization: "Bearer #{token.token}",
Accept: "application/json"
],
params: [
timeMin: "#{year}-01-01T00:00:00Z",
timeMax: "#{year + 1}-01-01T00:00:00Z",
singleEvents: true,
maxResults: 2500,
orderBy: "startTime",
timeZone: "Europe/Brussels"
]
)
resp.body["items"]
end
Parameters Explained
timeMin
,timeMax
: Define the date range. Use RFC3339 format (YYYY-MM-DDTHH:MM:SSZ
). Only events that start within this range are returned.singleEvents: true
: Expands recurring events into individual instances.maxResults
: Maximum number of events to return (max is 2500).orderBy: "startTime"
: Orders results chronologically.timeZone
: Sets the time zone used for interpretingtimeMin
/timeMax
.
Summary
Using Elixir, Goth
, and Req
, you can easily integrate Google Calendar into your Phoenix app. Just set up service account credentials, grant access to the calendar, and use Req.get/2
to query the Google Calendar API with the appropriate parameters.
For more details, refer to the Google Calendar API reference.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.