Getting Google Drive Images: Google Drive API with Elixir

Alvin Rapada
3 min readJan 27, 2022

I’m creating a website for our wedding and my fiance wants to have a public google drive where people can upload their images with us and show them on our site. Seems pretty easy to do (which it was) but while doing it, there are not many resources/documentation on how to do it, so here I am again making one 😂

Setting up service account/google drive

  1. Follow this tutorial on How to create Google Oauth2 Service account credentials, what’s important here is the JSON file which has the keys that we need on the backend.
  2. Next, you have to share the drive containing your images to the email generated by your newly created service account.
Copy the service account email
Add the email here

After all these are done, we can now jump into coding.

Coding in Elixir

For our dependencies, we will be using google_api_drive and goth. To install, add these on your mix.exs

defp deps do
[
{:google_api_drive, "~> 0.25.0"},
{:goth, "~> 1.2.0"}
]
end

Configure goth to use your JSON credential file in config.exs. Make sure to add the JSON file inside your project and in the right directory.

config :goth,
json: Path.expand("./your_json_file.json") |> File.read!()

LiveView
In this code, I’m using the drive_files_list(conn, optional_params \\ [], opts \\[]) to get all the files I need. For more details check the documentation here.

I’m also only getting the files with the type "image/jpeg”from the drive (because that's all I need), then take the id and name because that’s all I need to show.

I like separating my htmls on /template folder, that’s why I'm doing the render with a Phoenix.View.render.

defmodule MyApp.HomeLive do
@moduledoc "Home Live"
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, %{token: token}} = Goth.Token.for_scope("https://www.googleapis.com/auth/drive")
conn = GoogleApi.Drive.V3.Connection.new(token) {:ok, %{files: files} = _file_list} =
GoogleApi.Drive.V3.Api.Files.drive_files_list(
conn,
includeItemsFromAllDrives: true,
supportsAllDrives: true,
corpora: "allDrives"
)
data =
files
|> Enum.filter(&(&1.mimeType == "image/jpeg"))
|> Enum.map(&Map.take(&1, [:id, :name]))
socket =
assign(socket,
page_title: "Home",
data: data
)
{:ok, socket}
end
def render(assigns) do
Phoenix.View.render(MyAppWeb.HomeView, "index.html", assigns)
end
end

Bonus: Showing Images in Front-end

Of course, we all want to show these images in a nice way, so worry no more, here’s a sample template if you want a responsive grid gallery. Thank me later 😉

Template:
A simple loop with an image tag inside, I also added onerror with a display none style attribute, just in case images from the API corrupted (It happens and we don't want to show them right?).

<div id="photo-gallery">
<%= for a <- @data do %>
<img class="thumbnail" src="<%= parse_link(a.id) %>" alt="<%= a.name %>" onerror="this.style.display='none'" />
<% end %>
</div>

View:
As you noticed, I’m manually parsing the file id to a link to show the image because I’m not getting any field/URL for that on the google API response. This link only shows the thumbnail of my images but if you want to show the original file, change the thumbnail? to uc?

defmodule MyAppWeb.HomeView do
use MyAppWeb, :view
def parse_link(id), do: "https://drive.google.com/thumbnail?id=#{id}"
end

CSS:
Adding CSS for a responsive and clean-looking grid.

#photo-gallery{
-webkit-column-count:4;
-moz-column-count:4;
column-count:4;

-webkit-column-gap:20px;
-moz-column-gap:20px;
column-gap:20px;
}
@media (max-width:1200px){
#photo-gallery{
-webkit-column-count:3;
-moz-column-count:3;
column-count:3;

-webkit-column-gap:20px;
-moz-column-gap:20px;
column-gap:20px;
}
}
@media (max-width:800px){
#photo-gallery{
-webkit-column-count:2;
-moz-column-count:2;
column-count:2;

-webkit-column-gap:20px;
-moz-column-gap:20px;
column-gap:20px;
}
}
@media (max-width:600px){
#photo-gallery{
-webkit-column-count:1;
-moz-column-count:1;
column-count:1;
}
}
#photo-gallery img.thumbnail{
width:100%;
height:auto;
margin: 4% auto;
cursor: pointer;
-webkit-transition: all 0.2s;
transition: all 0.2s;
}

Final result 🎉 🎊

Let me know if it works for you and If you find this helpful, I’d appreciate a coffee 😊

Happy Coding !!!

--

--