{"id":19866673,"url":"https://github.com/vt-elixir/interactor","last_synced_at":"2025-12-11T23:40:45.532Z","repository":{"id":57507103,"uuid":"55108788","full_name":"vt-elixir/interactor","owner":"vt-elixir","description":"    Interactor provides an opinionated interface for performing complex user interactions.","archived":false,"fork":false,"pushed_at":"2017-11-16T17:30:53.000Z","size":35,"stargazers_count":11,"open_issues_count":4,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-24T22:29:06.713Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/interactor","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vt-elixir.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-31T01:00:22.000Z","updated_at":"2023-09-01T10:45:24.000Z","dependencies_parsed_at":"2022-09-04T13:23:04.623Z","dependency_job_id":null,"html_url":"https://github.com/vt-elixir/interactor","commit_stats":null,"previous_names":["agilionapps/interactor"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/vt-elixir/interactor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vt-elixir%2Finteractor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vt-elixir%2Finteractor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vt-elixir%2Finteractor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vt-elixir%2Finteractor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vt-elixir","download_url":"https://codeload.github.com/vt-elixir/interactor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vt-elixir%2Finteractor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27672245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-11T02:00:11.302Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T15:26:54.115Z","updated_at":"2025-12-11T23:40:45.513Z","avatar_url":"https://github.com/vt-elixir.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Interactor\n\n[![Build Status](https://travis-ci.org/AgilionApps/interactor.svg?branch=master)](https://travis-ci.org/AgilionApps/interactor)\n[![Hex Version](https://img.shields.io/hexpm/v/interactor.svg)](https://hex.pm/packages/interactor)\n\n**Interactor provides an opinionated interface for performing complex user interactions.**\n\n## What this is\n\nThis is a library implementing a simple pattern that encourages modularity and\nthe Single Responsibility Principle around _doing_ things primarially with ecto.\n\nYou can think of this as a second layer of domain modeling that happens in your\napplication. You existing schema (model) layer represents the data itself and\nit's relationships. The new interaction layer represents high level actions or\nevents that happen on your domain. Some good examples in a blog domain might be:\n\n* CreateArticle\n* UpdateArticle\n* DeleteArticle\n* TrackArticleView\n* RegisterUser\n* SpamifyUser\n* ResetUserPassword\n* CreateComment\n* DeleteComment\n\nBy seperating these actions into their own modules you gain smaller \"models\"\nand controllers. The interactors themselves stay extremely focused and the code\neasy to maintain.\n\nInteractor is inspired by CollectiveIdea's Ruby gem Interactors and influenced\nby Ello's async interactor usage and years of working on many MVC apps.\n\n## What this isn't\n\n*Fully baked.*\n\nThis is an experiment in application architectual patterns using the tools\nElixir and Ecto provide. Ecto Changesets and Multi are (relatively) new\nconcepts (to me) and these theories need testing out.\n\nIs this a good idea? A bad one? Open an issue and let me know!\n\n*A lot of code*\n\nThis library really doesn't do much, but it doesn't need to. This is mostly\nabout promoting and enabling a pattern to make Elixir/Phoenix apps even more\nmaintainable then they already are.\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed as:\n\n  1. Add interactor to your list of dependencies in `mix.exs`:\n\n        def deps do\n          [{:interactor, \"~\u003e 0.0.1\"}]\n        end\n\n  2. Ensure interactor is started before your application:\n\n        def application do\n          [applications: [:interactor]]\n        end\n\n## Examples\n\n### A basic 'Article creation' interactor\n\n```elixir\ndefmodule ExampleApp.CreateArticle do\n  use Interactor, repo: ExampleApp.Repo\n  alias ExampleApp.Article\n\n  def handle_call(%{attributes: attrs, author: author}) do\n    cast(%Article{}, attrs, [:title, :body])\n    |\u003e put_change(:author_id, author.id)\n    # validations etc\n  end\nend\n\ndefmodule ExampleApp.ArticleController do\n  use ExampleApp.Web, :controller\n  alias ExampleApp.CreateArticle\n\n  def post(%{assigns: %{user: user}} = conn, %{article: attrs}) do\n    case Interactor.call(CreateArticle, %{attributes: attrs, author: user}) do\n      {:ok, article} -\u003e\n        conn\n        |\u003e put_status(:created)\n        |\u003e put_resp_header(\"location\", article_path(conn, :show, article))\n        |\u003e render(:show, article: article)\n      {:error, changeset} -\u003e\n        conn\n        |\u003e put_status(:unprocessable_entity)\n        |\u003e render(ExampleApp.ChangesetView, :error, changeset: changeset)\n    end\n  end\nend\n```\n\n### Create and update author post count\n\nA more complicated example might involve updating the author as well:\n\n```elixir\ndefmodule ExampleApp.CreateArticle do\n  use Interactor, repo: ExampleApp.Repo\n  alias ExampleApp.Article\n\n  def handle_call(%{attributes: attrs, author: author}) do\n    Multi.new\n    |\u003e Multi.insert(:article, article_changeset(attrs, author))\n    |\u003e Multi.update(:author, author_changset(author))\n  end\n\n  defp post_changeset(attrs, author)\n    cast(%Article{}, attrs, [:title, :body])\n    |\u003e put_change(:author_id, author.id)\n    # validations etc\n  end\n\n  defp author_changeset(author) do\n    case(author, %{posts_count: author.posts_count + 1}, [:posts_count])\n  end\nend\n\ndefmodule ExampleApp.ArticleController do\n  use ExampleApp.Web, :controller\n  alias ExampleApp.CreateArticle\n\n  def post(%{assigns: %{user: user}} = conn, %{article: attrs}) do\n    case Interactor.call(CreateArticle, %{attributes: attrs, author: user}) do\n      {:ok, %{article: article}} -\u003e\n        conn\n        |\u003e put_status(:created)\n        |\u003e put_resp_header(\"location\", article_path(conn, :show, article))\n        |\u003e render(:show, post: post)\n      {:error, _, changeset, _} -\u003e\n        conn\n        |\u003e put_status(:unprocessable_entity)\n        |\u003e render(ExampleApp.ChangesetView, :error, changeset: changeset)\n    end\n  end\nend\n```\n\n## TODO:\n\n* Chainability?\n* Collect feedback\n* Release to hex.pm\n\n## License\n\nThe Interactor source code is released under Apache 2 License. Check LICENSE\nfile for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvt-elixir%2Finteractor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvt-elixir%2Finteractor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvt-elixir%2Finteractor/lists"}