<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="340321" data-post-id="340321">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="D4no0" data-post="21" data-topic="66180">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/d4no0/48/33624_2.png" class="avatar"> D4no0:</div>
<blockquote>
<p>Using <code>with</code> with multiple <code>else</code> clauses is a anti-pattern IMO.</p>
</blockquote>
</aside>
<p>That somebody said something is anti-pattern is not enough to convince me. I’ve seen the alternative way of doing things and spraying many small functions inside your module does not look like an objective improvement to me. Tracking code visually becomes harder and you still have to massage returned error values. For what? To not have <code>else</code>? Why is that a selling point? At least you have explicitly spelled out all error states which is a clear win in dynamic languages.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340321" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-340321" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340321"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="340323" data-post-id="340323">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="D4no0" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/D4no0/120/33624_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  D4no0
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="dimitarvp" data-post="22" data-topic="66180">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>For what? To not have <code>else</code>?</p>
</blockquote>
</aside>
<p>No, to not have to write defensive code. In a lot of cases you don’t care about the error shape, nor you care about handling it, you just care about the happy path.</p>
<p>As it was said countless times before, these anti-patterns are just generic guidelines, the only thing that I value in a codebase is consistency. If you went with an approach, make sure you use it consistently, otherwise this becomes amateur hour.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340323" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-340323" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340323"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="340324" data-post-id="340324">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="D4no0" data-post="23" data-topic="66180">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/d4no0/48/33624_2.png" class="avatar"> D4no0:</div>
<blockquote>
<p>In a lot of cases you don’t care about the error shape, nor you care about handling it, you just care about the happy path.</p>
</blockquote>
</aside>
<p>We’re working on different projects for sure, because in my work letting an error escape means a background job with 15+ dependencies does not get to run [on time] and then you have to go manually and fix things… or buy Oban Pro, which my employer still hasn’t done (because the value proposition for them is not clear).</p>
<p>For a lot of projects you can just indeed leave the happy path only and go fix stuff only when you see a blow-up in your APM system. For those I work on – nope.</p>
<aside class="quote no-group" data-username="D4no0" data-post="23" data-topic="66180">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/d4no0/48/33624_2.png" class="avatar"> D4no0:</div>
<blockquote>
<p>As it was said countless times before, these anti-patterns are just generic guidelines, the only thing that I value in a codebase is consistency. If you went with an approach, make sure you use it consistently, otherwise this becomes amateur hour.</p>
</blockquote>
</aside>
<p>Yeah, I 100% agree with this. Pick a style, stick to it, explain why (document somewhere for bonus points), profit.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340324" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-340324" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340324"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="340410" data-post-id="340410">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Lucassifoni" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Lucassifoni/120/39057_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Lucassifoni
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>If we are at an user-facing edge of the system, the different steps could generate different error messages or even instructions for other flows of the system.. but that also could be handled without this multi-clause else.</p>
<p>Two days ago I tried to see my “self-teaching wallet” status, a French mandatory tax that gets deposited into a state wallet for you to buy overpriced courses by shady organisations afterwards.</p>
<p>I had to change my password as I did not log in for a while.</p>
<p>The password had a restriction of having 12 chars, including symbols. The symbol “greenlight” was represented by an ampersand &amp;. I used Firefox’s “generate a secure password” feature and did not even look at it.</p>
<p>Password gets changed, I get a confirmation e-mail, I try to log in.</p>
<p>“Something wrong happened with a system”. Duh. I open the inspector tab to see that instead of a json response describing the error, I got an HTML response from a WAF with “SQL Injection attempt detected”.</p>
<p>I display the password, and it was generated with “&amp;&amp;” inside it. I remove an “&amp;”, click again, and get an “Incorrect password notice”. Change the password again, without the “&amp;&amp;” that was deemed acceptable by the password change wizard, and I log in <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"> .</p>
<p>My point being, when we’re in a controller meant to be interacted with by a real person, handling all cases with explicit error messages along with error-specific codes to pass around to support is a real benefit.</p>
<p>Multi-clause else can be a pattern to concisely dispatch those situation-specific, user-consumed error payloads. But that depends on the codebase.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340410" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-340410" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340410"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="340413" data-post-id="340413">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="D4no0" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/D4no0/120/33624_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  D4no0
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>There are multiple ways to achieve the same solution. The one I personally like the most is using fallback controller. That one is not only the most readable, but it also separates system errors from user-facing errors.</p>
<p>I think its worth pointing out that there is no universal solution that has no drawbacks ultimately, and if the solution you came with (like <code>with</code> with multiple <code>else</code> clauses) works very well, there is no reason not to use it.</p>
<p>In terms of code styling, I think elixir is very lean (I would say too lean sometimes) and you can see a huge variety of coding styles from people with different backgrounds. I am obviously biased towards one of them.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340413" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-340413" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340413"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="340446" data-post-id="340446">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mpope" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mpope
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>While Elixir folks seem to sometimes balk at the lowly use of chaining together function heads and pattern matching, I like to use them over <code>with</code> in cases like this. Its less compact, but you get flexibility without having to think of tagging or overlapping errors and whatnot:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def onboard(conn, params) do
  handle_verification(verify_zendesk_origin(conn))
end

def handle_verification({:error, _reason}) do
  conn
  |&gt; put_status(:forbidden)
  |&gt; json(%{error: "Invalid origin"})
  |&gt; halt()
end

def handle_verification({:ok, origin}) do
  user_params = params["user"]

  organisation_attrs = %{
    subdomain: params["subdomain"],
    name: params["name"],
    public_key: params["public_key"]
  }

  handle_org_upsert(Organisations.upsert(organisation_attrs), user_params)
end

def handle_org_upsert({:error, changeset}, _) do
  IO.inspect(changeset.errors, label: "organisation upsert (onboard) changeset errors")

  conn
  |&gt; put_status(:unprocessable_entity)
  |&gt; json(%{
    error: "invalid organisation data",
    details: changeset_error_to_string(changeset)
  })
  |&gt; halt()
end

def handle_org_upsert({:ok, organisation}, user_parms) do
  user_attrs = %{
    external_id: to_string(user_params["id"]),
    name: user_params["name"],
    role: user_params["role"],
    avatar_url: user_params["avatarUrl"],
    organisation_id: organisation.id
  }

  handle_user_upsert(ExternalAccounts.upsert_user(user_attrs))
end

def handle_user_upsert({:error, changeset}) do
  IO.inspect(changeset.errors, label: "user upsert (onboard) changeset errors")

  conn
  |&gt; put_status(:unprocessable_entity)
  |&gt; json(%{
    error: "invalid user data",
    details: changeset_error_to_string(changeset)
  })
  |&gt; halt()
end

def handle_user_upsert({:ok, user}) do
  conn
  |&gt; put_status(:ok)
  |&gt; json(%{user_id: user.id})
  |&gt; halt()
end
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340446" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-340446" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340446"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="340450" data-post-id="340450">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="derek-zhou" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/derek-zhou/120/19943_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  derek-zhou
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Actually, I think your current code is just fine. Real world business logic is messy by nature and constantly evolving; abstractions will make later modifications unnecessarily hard. I will just confine the mess in a few known “messy” modules and call it a day.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340450" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-340450" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340450"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="340509" data-post-id="340509">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Sorc96" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Sorc96/120/28361_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Sorc96
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I really don’t like  this, because in order to get a high level understanding of what steps happen as part of onboarding, I have to read everything including all the details.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340509" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-340509" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340509"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="340795" data-post-id="340795">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="wpiekutowski" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  wpiekutowski
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here’s another take how to improve this without changing the interface of your functions. It uses a result type <code>{:ok, any()} | {:error, :invalid_origin | %Ecto.Changeset.t()}</code> to handle errors:</p>
<ul>
<li><code>and_then(result, fun)</code> when result is <code>{:ok, ok_value}</code>, calls the function with an <code>ok_value</code>. Otherwise it passes through the error result. Function is supposed to return a result type.</li>
<li><code>map_error(result, fun)</code> when result is <code>{:error, error_value}</code>, calls the function with an error value or passes through the ok result. Function is supposed to return a value.</li>
</ul>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def onboard(conn, params) do
    verify_zendesk_origin(conn)
    |&gt; map_error(fn _reason -&gt; :invalid_origin end)
    |&gt; and_then(fn _origin -&gt; params_to_org_upsert(params) end)
    |&gt; and_then(&amp;Organisations.upsert/1)
    |&gt; map_error(fn changeset -&gt;
      ChangesetError.new!(
        changeset,
        label: "organisation upsert (onboard) changeset errors",
        message: "invalid organisation data"
      )
    end)
    |&gt; and_then(&amp;params_and_org_to_upsert_user(params, &amp;1))
    |&gt; and_then(&amp;ExternalAccounts.upsert_user/1)
    |&gt; map_error(fn changeset -&gt;
      ChangesetError.new!(
        changeset,
        label: "user upsert (onboard) changeset errors",
        message: "invalid user data"
      )
    end)
    |&gt; case do
      {:ok, %User{} = user} -&gt;
        conn
        |&gt; put_status(:ok)
        |&gt; json(%{user_id: user.id})
        |&gt; halt()

      {:error, :invalid_origin} -&gt;
        conn
        |&gt; put_status(:forbidden)
        |&gt; json(%{error: "Invalid origin"})
        |&gt; halt()

      {:error, %ChangesetError{} = e} -&gt;
        IO.inspect(e.changeset.errors, label: e.label)

        conn
        |&gt; put_status(:unprocessable_entity)
        |&gt; json(%{
          error: e.message,
          details: changeset_error_to_string(e.changeset)
        })
        |&gt; halt()
    end
  end

  def and_then({:ok, value}, fun), do: fun.(value)
  def and_then({:error, _} = error, _fun), do: error
  def map_error({:ok, _} = ok, _fun), do: ok
  def map_error({:error, error_value}, fun), do: {:error, fun.(error_value)}

  defmodule ChangesetError do
    @keys [:changeset, :label, :message]
    @enforce_keys @keys
    defstruct @keys

    def new!(%Ecto.Changeset{} = changeset, label: label, message: message)
        when is_binary(label) and is_binary(message) do
      %__MODULE__{changeset: changeset, label: label, message: message}
    end
  end

  defp params_to_org_upsert(params) do
    {:ok, %{
      subdomain: params["subdomain"],
      name: params["name"],
      public_key: params["public_key"]
    }}
  end

  defp params_and_org_to_upsert_user(params, organisation) do
    user_params = params["user"]

    {:ok, %{
      external_id: to_string(user_params["id"]),
      name: user_params["name"],
      role: user_params["role"],
      avatar_url: user_params["avatarUrl"],
      ogranisation_id: organisation.id
    }}
  end
</code></pre>
<p>Consider modifying <code>verify_zendesk_origin</code> to only have what it actually needs from <code>conn</code>, instead of the whole thing.</p>
<p>Depending on personal taste, you might prefer to not have <code>params_*_to_*</code> and do the mapping inside an anonymous function.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">    verify_zendesk_origin(conn)
    |&gt; map_error(fn _reason -&gt; :invalid_origin end)
    |&gt; and_then(fn _origin -&gt;
      %{
        subdomain: params["subdomain"],
        name: params["name"],
        public_key: params["public_key"]
      }
    end)
    |&gt; and_then(&amp;Organisations.upsert/1)
</code></pre>
<p>You might also consider moving everything about orgranisation upsert and user upsert into separate functions:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def onboard(conn, params) do
    verify_origin(conn)   
    |&gt; and_then(&amp;upsert_organisation(&amp;1, params))
    |&gt; and_then(&amp;upsert_user(&amp;1, params))
    |&gt; case do
      {:ok, %User{} = user} -&gt;
        conn
        |&gt; put_status(:ok)
        |&gt; json(%{user_id: user.id})
        |&gt; halt()

      {:error, :invalid_origin} -&gt;
        conn
        |&gt; put_status(:forbidden)
        |&gt; json(%{error: "Invalid origin"})
        |&gt; halt()

      {:error, %ChangesetError{} = e} -&gt;
        IO.inspect(e.changeset.errors, label: e.label)

        conn
        |&gt; put_status(:unprocessable_entity)
        |&gt; json(%{
          error: e.message,
          details: changeset_error_to_string(e.changeset)
        })
        |&gt; halt()
    end
  end

  def verify_origin(conn) do
    verify_zendesk_origin(conn)
    |&gt; map_error(fn _reason -&gt; :invalid_origin end)
  end
  
 def upsert_organisation(_, params) do
    %{
      subdomain: params["subdomain"],
      name: params["name"],
      public_key: params["public_key"]
    }
    |&gt; Organisations.upsert()
    |&gt; map_error(fn changeset -&gt;
      ChangesetError.new!(
        changeset,
        label: "organisation upsert (onboard) changeset errors",
        message: "invalid organisation data"
      )
    end)
  end

def upsert_user(organisation, params) do
    user_params = params["user"]

    %{
      external_id: to_string(user_params["id"]),
      name: user_params["name"],
      role: user_params["role"],
      avatar_url: user_params["avatarUrl"],
      ogranisation_id: organisation.id
    }
    |&gt; ExternalAccounts.upsert_user()
    |&gt; map_error(fn changeset -&gt;
      ChangesetError.new!(
        changeset,
        label: "user upsert (onboard) changeset errors",
        message: "invalid user data"
      )
    end)
  end
</code></pre>
<p>This way the next developer coming to see what <code>onboard</code> actually does, clearly sees what are the major steps. Of course it makes sense to put</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">    verify_origin(conn)   
    |&gt; and_then(&amp;upsert_organisation(&amp;1, params))
    |&gt; and_then(&amp;upsert_user(&amp;1, params))
</code></pre>
<p>into an application service module. It’s best not to pass all <code>params</code> or whole <code>conn</code>, but ideally a struct with only the required data.</p>
<p>Debugging this kind of pipelines is easy with Elixir’s <code>dbg</code> function. You can clearly see what each step returned.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340795" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-340795" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340795"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="340875" data-post-id="340875">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="camstuart" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/camstuart/120/18856_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  camstuart
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks for explaining that <a class="mention" href="/u/wpiekutowski" rel="nofollow">@wpiekutowski</a> ! I had hoped that there was a pipeline style approach, but I had not been able to see how to handle errors. But your examples clearly show that.</p>
<p>Sometimes Elixir reminds me of my Perl days. There is more than one way to do it!<br>
I will give your design a try, it seems the most “Elixir-ish” so far.</p>
<p>Good point about not using all of <code>conn</code> and <code>params</code> thats just a bit of laziness on my part <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340875" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-with-idiomatic-elixir-style-when-dealing-with-logic-flow/66180/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-340875" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340875"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/66180/load_more?page=4">Load more posts (1 remaining)</a>
</div></template></turbo-stream>