DEV Community

Cover image for File Upload using Elixir, Phoenix, Absinthe and ExAws
Bervianto Leo Pratama
Bervianto Leo Pratama

Posted on

File Upload using Elixir, Phoenix, Absinthe and ExAws

Hello, I'm quite new in the elixir world. I want to write some notes so it will help me for later if I want to try this again. This guide will not really details. I will assume that you familiar enough to know about Elixir, Phoenix, Absinthe or ExAws itself. I will assume you are also familiar with AWS especially S3.

Alternative library that you might be interested: https://github.com/stavro/arc

Preparation

  • Make sure you are already install Elixir in your computer/PC.
  • Generate new Phoenix Project. (If you are already have the Phoenix Project, you can skip this step).

mix archive.install hex phx_new

mix phx.new elixir_exploration

Note:

  1. Phoenix Installation Documentation
  2. Phoenix Generate Project
  3. Make sure you are already have PostgreSQL, if you not want to use database, please refer to note number 2, how to generate without Ecto which handle the database side.
  • Add Absinthe and ExAWS as Dependencies. Add these to mix.exs
defp deps do
    [
      ... # rest of dependencies, please not input this too
      {:absinthe, "~> 1.6"},
      {:absinthe_plug, "~> 1.5"},
      {:absinthe_phoenix, "~> 2.0"},
      {:ex_aws, "~> 2.2"},
      {:ex_aws_s3, "~> 2.0"},
      {:poison, "~> 3.0"},
      {:hackney, "~> 1.9"},
      {:sweet_xml, "~> 0.6"},
    ]
  end
Enter fullscreen mode Exit fullscreen mode
  • Download all deps, use mix deps.get

  • Prepare your AWS S3. :) Please read more in their documentation. https://aws.amazon.com/s3/

  • Prepare your account, we will use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Please visit here for more information about ExAWS: https://github.com/ex-aws/ex_aws

Let's Code

My code structure will be like this:

- root
-- elixir_exploration
-- elixir_exploration_web
--- resolvers # store all GraphQL resolvers
--- schema # store all GraphQL schemas
-- schema.ex # store all GraphQL query/mutations
Enter fullscreen mode Exit fullscreen mode
  • I will code at GraphQL side first (Absinthe). Please setup the Absinthe first.

You can refer this guide: https://hexdocs.pm/absinthe/plug-phoenix.html

I really love most of popular library, they bring us a nice guide. :)

  • Write the resolver, I will put in elixir_exploration_web/resolvers/uploads.ex
defmodule ElixirExplorationWeb.Resolvers.Uploads do
  alias ExAws.S3

  def upload_to_aws(_, %{input: input}, _) do
    IO.inspect(input.file)
    request = input.file.path
      |> S3.Upload.stream_file()
      # take care the filename, you should validate this
      |> S3.upload("upload-test-berv", "uploads/#{input.file.filename}")
      |> ExAws.request()
    case request do
      {:ok, _} -> {:ok, "Success"}
      {:error, _} -> {:error, "Please try again"}
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Don't forget to update the bucket name. In that example, I use upload-test-berv as the bucket name. I use uploads/#{input.file.filename} as the target file location.

  • Write the schema, I will put in elixir_exploration_web/schema/upload_types.ex
defmodule ElixirExplorationWeb.Schema.UploadTypes do
  use Absinthe.Schema.Notation

  alias ElixirExplorationWeb.Resolvers
  import_types(Absinthe.Plug.Types)

  object :upload_file do
    @desc """
      Upload a file
    """
    field :upload_file, :string do
      arg(:input, non_null(:file_input))
      resolve(&Resolvers.Uploads.upload_to_aws/3)
    end
  end

  input_object :file_input do
    field :file, non_null(:upload)
  end
end
Enter fullscreen mode Exit fullscreen mode
  • Import those files into elixir_exploration_web/schema.ex
defmodule ElixirExplorationWeb.Schema do
  use Absinthe.Schema

  alias ElixirExplorationWeb.Schema

  import_types(Schema.UploadTypes)

  query do

  end

  mutation do
    import_fields(:upload_file)
  end
end
Enter fullscreen mode Exit fullscreen mode
  • Update config, I want to setup the default region. Currently I update to config/config.exs, but feel free to add different approach for different env.
config :ex_aws,
  region: {:system, "AWS_DEFAULT_REGION"}
Enter fullscreen mode Exit fullscreen mode
  • Write the env.sh, this for setup our environment variable in our system.
export AWS_ACCESS_KEY_ID=<your_access_key_id>
export AWS_SECRET_ACCESS_KEY=<your_secret_access_key>
export AWS_DEFAULT_REGION=ap-southeast-1
Enter fullscreen mode Exit fullscreen mode

Feel free to use another region. :)

  • Apply the environment, you can use source env.sh.

  • Run your Phoenix Server. mix phx.server

  • Test your API. Because my API locate at localhost:4000/api/graphql, so I will use that. If you set another path, please update it from my script below.

curl -X POST -F query="mutation { uploadFile(input: {file: \"my_data\"})}" -F my_data=@mix.exs -H "Accept:application/json" localhost:4000/api/graphql
Enter fullscreen mode Exit fullscreen mode

Elixir Test

  • Check your S3

S3

My Repo

You also can visit my repositories. I will write more in there if I have any updates.

GitHub logo berviantoleo / elixir-exploration

Explore more about elixir

ElixirExploration

codecov

To start your Phoenix server:

  • Install dependencies with mix deps.get
  • Create and migrate your database with mix ecto.setup
  • Start Phoenix endpoint with mix phx.server

Now you can visit localhost:4000 from your browser.

Ready to run in production? Please check our deployment guides.

Learn more

Congrats

Yey! Congrats! You've implemented file upload and upload the file to AWS S3. In the next section, maybe I will write to show the result after you upload the file. The approach I will use:

  1. Use database as the listing
  2. Call AWS S3 API Directly to get the list

I hope I will write in the next month and write each approach in different article.

Thank you. :)

Thank you image

The city at night via unsplash

Discussion (0)