Shopifex

A simple boilerplate package for creating Shopify embedded apps with the Elixir Phoenix framework. https://hexdocs.pm/shopifex

Installation

The package can be installed by adding shopifex to your list of dependencies in mix.exs:

def deps do
  [
    {:shopifex, "~> 0.1.0"}
  ]
end

Quickstart

Add the :shopifex config settings to your config.ex. More config details here

config :shopifex,
  app_name: "MyApp",
  shop_schema: MyApp.Shop,
  repo: MyApp.Repo,
  redirect_uri: "https://myapp.ngrok.io/auth/install",
  webhook_uri: "https://myapp.ngrok.io/webhook",
  scopes: "read_inventory,write_inventory,read_products,write_products,read_orders",
  api_key: "shopifyapikey123",
  secret: "shopifyapisecret456",
  webhook_topics: ["app/uninstalled"]

Update your endpoint.ex to include the custom body parser. This is necessary for HMAC validation to work.

plug Plug.Parsers,
  parsers: [:urlencoded, :multipart, :json],
  pass: ["*/*"],
  body_reader: {MyAppWeb.CacheBodyReader, :read_body, []},
  json_decoder: Phoenix.json_library()

Update your router.ex to include the Shopifex plugs

# Make sure the app can load inside of an iFrame
pipeline :browser do
  ...
  plug Shopifex.Plug.LoadInIframe
end

# Ensures that a valid store is currently loaded in the session and is accessible in your controllers/templates as `conn.private.shop`
pipeline :shopify_session do
  plug Shopifex.Plug.ShopifySession
end

# Make sure the incoming requests from Shopify are valid. For example, when the app is being installed, or the initial loading of your App inside of the Shopify admin panel.
pipeline :shopify_entrypoint do
  plug Shopifex.Plug.ShopifyEntrypoint
end

# Ensures that the connection has a valid Shopify webhook HMAC token
pipeline :shopify_webhook do
  plug Shopifex.Plug.ShopifyWebhook
end

Now add this basic example of these plugs in action in router.ex

scope "/auth", MyAppWeb do
  pipe_through [:browser, :shopify_entrypoint]
  get "/", AuthController, :auth
  get "/install", AuthController, :install
end

scope "/", MyAppWeb do
  pipe_through [:browser, :shopify_session]

  get "/", PageController, :index
end

scope "/webhook", MyAppWeb do
  pipe_through [:shopify_webhook]

  post "/", WebhookController, :action
end

Create a new controller called auth_controller.ex to handle the initial iFrame load and installation

defmodule MyAppWeb.AuthController do
  use MyAppWeb, :controller
  use ShopifexWeb.AuthController

  # Thats it! Validation, installation are now handled for you :)
end

create another controller called webhook_controller.ex to handle incoming Shopify webhooks

defmodule MyAppWeb.WebhookController do
  use MyAppWeb, :controller
  use ShopifexWeb.WebhookController

  # add as many handle_topic/3 functions here as you like! This basic one handles app uninstallation
  def handle_topic(conn, shop, "app/uninstalled") do
    Shopifex.Shops.delete_shop(shop)

    conn
    |> send_resp(200, "success")
  end
end