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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’ve not used it myself, but the tarams library looks like it might handle your use case if you want to go with a library instead of a custom solution <a href="https://github.com/bluzky/tarams" class="inline-onebox" rel="noopener nofollow ugc">GitHub - bluzky/tarams: Cast and validate external data and request parameters for Elixir and Phoenix · GitHub</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="233429" data-batch-url="/posts/batch_likers">
                        3
                      </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/how-to-normalize-function-params/44091/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-233429" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="233429"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-solved cat-solved" title="Marked as solution"></div>
  </section>
</div>
    <div class="postbit" id="233439" data-post-id="233439">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="fceruti" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/fceruti/120/28850_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  fceruti
                    <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! This seems to be exactly what I was looking for. I’ll test it and possibly mark it as the solution. The quest of building/understanding this was an interesting one thou.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="233439" 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/how-to-normalize-function-params/44091/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-233439" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="233439"
                     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 #12"></div>
  </section>
</div>
    <div class="postbit" id="233441" data-post-id="233441">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>if you want to use something more standards-compliant, I have this library which does compile-time generation of strictly validation functions from Jsonschemas:</p>
<aside class="onebox allowlistedgeneric" data-onebox-src="https://exonerate.hexdocs.pm/Exonerate.html">
  <header class="source">

      <a href="https://exonerate.hexdocs.pm/Exonerate.html" target="_blank" rel="noopener nofollow ugc">exonerate.hexdocs.pm</a>
  </header>

  <article class="onebox-body">
    

<h3><a href="https://exonerate.hexdocs.pm/Exonerate.html" target="_blank" rel="noopener nofollow ugc">Exonerate — exonerate v1.2.1</a></h3>



  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>

<p>It doesn’t normalize your parameters, though, so if you need a translation layer between things with different “names” (e.g. camelCase → snake_case) you might have to cook up something on your own.  We do this at work with a “Codec” module which I may do a webcast on sometime.</p>
<p>With Ecto, though, you can just peddle in strings and it figures out the pesky strings/atoms stuff for you.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="233441" 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/how-to-normalize-function-params/44091/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-233441" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="233441"
                     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 #13"></div>
  </section>
</div>
    <div class="postbit" id="233470" data-post-id="233470">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sasajuric" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/120/991_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sasajuric
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Elixir In Action</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="LostKobrakai" data-post="11" data-topic="44091" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>I’d be intersted in how you handled the return value of the core, especially for errors. It might be easy if db schema and normalized schema are similar, but becomes tricky when that’s not the case.</p>
</blockquote>
</aside>
<p>IMO, the thing we’re validating is the input itself. In the simplest case (which is in my experience also the most frequent one), we can do most of the validations before even hitting the database, so that’s simple. Occasionally I may need to hit the database to validate some constraint (most often uniqueness). In most cases I’ve had this is also simple, since the field being validated usually directly corresponds to the input field. Combining these two, in most cases all I needed was a single validation+store changeset where all possible field errors corresponded to the input fields.</p>
<p>I can’t recall a single situation where this didn’t fit the bill, but vaguely speaking the options I’d consider in such cases would be:</p>
<ol>
<li>Separate input validation changeset from db store, performing most of validations on the input.</li>
<li>On db store error, take the errors, change the keys if needed (e.g. replace db field <code>:foo</code> with input field <code>:bar</code>).</li>
</ol>
<p>It would help if you had some specific situation in mind, then we could discuss it.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="233470" 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/how-to-normalize-function-params/44091/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-233470" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="233470"
                     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 #14"></div>
  </section>
</div>
    <div class="postbit" id="233480" data-post-id="233480">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>If you are up to a declarative approach and dependency inversion towards your application core’s data types, you can use <a href="https://hex.pm/packages/domo" rel="nofollow">Domo library</a>. That generates validators and constructor functions from a <code>t()</code> type spec of the struct, and the type spec is validated for syntax correctness by elixir during the compilation.</p>
<p>So the request can be accepted into the struct that looks like the following:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Request do
  use Domo, ensure_struct_defaults: false

  defstruct [:email, :password, :date_of_birth]

  @type t :: %__MODULE__{
    email: email(),
    password: password(),
    date_of_birth: Date.t() | nil
  }

  @type email :: String.t()
  precond email: &amp;String.match?(&amp;1, ~r|.+\@.+\..+|)

  @type password :: String.t()
  precond password: &amp;String.length(&amp;1) &gt; 7

  # Domo adds new/1, new!/1, ensure_type/1, ensure_type!/1 here automatically
end
</code></pre>
<p>And the validation can be done like that:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex(1)&gt; Request.new(%{email: "user@test.com", password: "some_password"})
{:ok, %Request{date_of_birth: nil, email: "user@test.com", password: "some_password"}}

iex(2)&gt; Request.new(%{email: "usertestcom", date_of_birth: "none"})      
{:error,
 [
   password: "Invalid value nil for field :password of %Request{}. Expected the value matching the &lt;&lt;_::_*8&gt;&gt; type.",
   email: "Invalid value \"usertestcom\" for field :email of %Request{}. Expected the value matching the &lt;&lt;_::_*8&gt;&gt; type. And a true value from the precondition function \"&amp;String.match?(&amp;1, ~r|.+\\\\@.+\\\\..+|)\" defined for Request.email() type.",
   date_of_birth: "Invalid value \"none\" for field :date_of_birth of %Request{}. Expected the value matching the %Date{} | nil type."
 ]}
</code></pre>
<p>The dependency inversion can be done by sharing <code>email()</code> and <code>password()</code> in the shared module to have the same rules for emails and passwords across the whole app.</p>
<p>Domo plays nicely with Ecto schemas because they are structs too. See <a href="https://hexdocs.pm/domo/Domo.Changeset.html#validate_type/2" rel="noopener nofollow ugc">Domo.Changeset</a> for this kind of integration.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="233480" 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/how-to-normalize-function-params/44091/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-233480" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="233480"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>