24 July 2020

How to download files from Google Drive using Elixir

The documentation around downloading a file from a Google Drive account is a bit spread out, so i figured i could make a mini tutorial on how to do this.

The scenario is having a CSV file in a folder on my Google Drive and being able to read it from Elixir. Here's the setup:

  • Setup a service account using the Google Developer Console Dashboard (there are plenty tutorials on the web how to setup service accounts), and save the .json credentials file in your Elixir project somewhere.
  • Make sure the service account has access to all accounts in your domain (unsure this step is necessary, TBH).
  • The service account will have an email associated with it (something along the lines of service_account_name@yourproject.iam.gserviceaccount.com). Share the folder you want to read the files from with that email in your Google Drive interface.
  • Now we are ready to move to Elixir.
  • Install the following two dependencies in mix.exs:
{:google_api_drive, "~> 0.15.0"},
{:goth, "~> 1.2.0"},
  • Configure goth to use your .json credentials file in config.exs (you can also do it programmatically, just look at goth's docs):
config :goth,
json: “google_service_account.json” |> File.read!
  • Finally, the following snippet will take the first CSV file it finds and read its contents:
{: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"
)
[first | _rest] = files 
|> Enum.filter(&(&1.mimeType == "text/csv"))
|> Enum.map(&(Map.take(&1, [:id, :name])))
{:ok, %{body: body}} = GoogleApi.Drive.V3.Api.Files.drive_files_get(
conn,
first.id,
[
mimeType: "text/csv",
alt: "media"
],
[
decode: false
]
)
body

Happy Elixir'ing

<< back to posts