How to create a enum with mime types?

I wanted to provide a list of mime types supported in GraphQL, so I tried using the enum type. However, it doesn’t support strings with symbols such as the forward slash in mime type strings “image/png”. I looked into custom scalars, but it doesn’t have the same rich documentation as the enum field, so I wanted to extend the enum to support my use case. I then tried reading the library’s implementation of enum, but I’m still too new to Elixir to comprehend everything. Could anyone point me in the right direction please?

Hey @dagumak, unfortunately it won’t be possible to create a GraphQL Enum that looks literally like "image/png". Your options are to make it a simple string type with validations, an enum type like IMAGE_PNG that you map to a proper string, or a custom scalar that accepts string inputs and validates that they are one of a set of allowed values.

4 Likes

Thank you for taking the time to reply! I ended up with this implementation for the time being.

  scalar :mime_type, name: "MimeType" do
    description("""
    Currently support mimetypes:\n
      "image/gif"\n
      "image/png"\n
      "image/jpeg"\n
    """)

    serialize(fn value -> value end)
    parse(&allowed_mime_types/1)
  end

  defp allowed_mime_types(%Absinthe.Blueprint.Input.String{value: value}) do
    result = value in ["image/gif", "image/png", "image/jpeg"]

    case result do
      true -> {:ok, value}
      false -> :error
    end
  end

Maybe my library could help you : SimpleEnum - Use Enumerations in Elixir.

The equivalent of your current implementation would be :

# my_app/types.ex
defmodule MyApp.Types do
  import SimpleEnum

  defenum :mime_type_enum,
    image_gif: "image/gif",
    image_png: "image/png",
    image_jpeg: "image/jpeg"
end

# my_app/schema.ex
import MyApp.Types

scalar :mime_type, name: "MimeType" do
  description("""
  Currently support mimetypes:\n
    - #{mime_type_enum(:__values__) |> Enum.join("\n  - ")}
  """)

  serialize(fn
    value when value in mime_type_enum(:__values__) -> value
    key when key in mime_type_enum(:__keys__) -> mime_type_enum(key, :value)
    _ -> :error
  end)

  parse(fn
    %Absinthe.Blueprint.Input.String{value: value} when value in mime_type_enum(:__values__) ->
      {:ok, mime_type_enum(value, :key)}

    _ ->
      :error
  end)
end

With this implementation :

  • Adding an Enum is very simple, you just have to add the values in the defenum/2
  • It will automatically update description and the serialize/1 and parse/1 functions of your scalar
  • Once the scalar is parsed, you can use the image_gif, image_png and image_jpeg atoms in Elixir for processing
2 Likes