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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="wojtekmach" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/wojtekmach/120/999_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  wojtekmach
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Hex Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I agree that around 4 or more function arguments, things start to become dicey.</p>
<p>I also agree that depending on situation, Ecto changesets might feel like an overkill.</p>
<p>Here’s a couple options below.</p>
<p><a href="https://hexdocs.pm/elixir/Keyword.html#validate!/2" rel="noopener nofollow ugc"><code>Keyword.validate!</code></a> is a built-in way to ensure proper key names and you can even set defaults.</p>
<p>For doing a bit more validations, a good old recursive function that parses the keyword list key/value pairs is often enough. Or do it inline and even convert to a map right away (to later use the assertive <code>map.field</code> syntax):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Map.new(options, fn
  {:host, host} when is_binary(host) -&gt; {:host, host}
  {:port, port} when is_integer(port) -&gt; {:port, port}
end)
</code></pre>
<p>Beyond that, <a href="https://hexdocs.pm/nimble_options/NimbleOptions.html" class="inline-onebox" rel="noopener nofollow ugc">NimbleOptions — NimbleOptions v1.1.1</a> is a great option as it’s super easy to define basic validations, defaults, and it can ever create docs 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="321206" data-batch-url="/posts/batch_likers">
                        5
                      </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/best-way-to-pass-many-arguments-to-a-function/62325/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-321206" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="321206"
                     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 #11"></div>
  </section>
</div>
    <div class="postbit" id="321207" data-post-id="321207">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kccarter" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kccarter
                    <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>We’re able to use <code>structs</code> in some places where we have deterministic fields for a given response. An address is a good example.</p>
<p>But we find ourselves “having” to use normal maps with string keys more often than not because of the amount of JSON data we work with that isn’t easily defined ahead of time. (This is equally problematic in something like TypeScript.)</p>
<p>An example might be running a report that aggregates a bunch of values for every SKU in a system, with the results being returned in the format:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{
 "sku_001": { "title": "value", "color", "value", ... },
 "sku_002": { "title": "value", "price", "value", ... },
 "sku_003": { "width": "value", "height", "value", ... },
}
</code></pre>
<p>We also do a layout of layout in HEEX templates where we don’t know the “keys” ahead of time, and structs don’t allow fetching a field based on a key-string.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="321207" 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/best-way-to-pass-many-arguments-to-a-function/62325/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-321207" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="321207"
                     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="321212" data-post-id="321212">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I guess you store by key so you can do fast look up?</p>
<p>If you were able to store as structs then you can still do look up by string with <code>Keyword.get/fetch</code> and is fine to convert string to atom there since you already have the atom.  I’m getting a bit too much into your business though.  And ya, agreed this is a place dynamic languages are nice.  I did work with data like this once where we’re just getting all this random JSON data and I almost thought it would be a good use-case for <a href="https://hexdocs.pm/explorer/Explorer.html" rel="noopener nofollow ugc">Explorer</a>.  I didn’t last long enough to validate that, though.  We were rife with <code>nil</code> errors, though, so that’s where my suggestions come from.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="321212" 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/best-way-to-pass-many-arguments-to-a-function/62325/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-321212" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="321212"
                     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="321215" data-post-id="321215">
  <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">
								<p>In that case you should use recursive parsing as <a class="mention" href="/u/wojtekmach" rel="nofollow">@wojtekmach</a> suggested because it’s indifferent to the order of keys and if you have all keys covered in the separate function clauses then you’ll always arrive at the right parsed data.</p>
<p>Or – something I would do because I am paranoid and always will be when it comes to programming – create a JSON Schema and then use it to validate your assembled records. Or, even better, create several JSON Schemas for each of the responses that you’re getting (you mentioned that the final record requires assembly of results coming from several different 3rd party API calls).</p>
<p>…Or if it’s not a JSON Schema (it can sometimes be an outsized amount of work), at least have a bunch of e.g. <code>ApiFoo.new_response</code> and <code>ApiBar.new_response</code> and <code>ApiBaz.new_response</code> etc. functions that crash and burn if an expectation about shape of data, type of field or contents of a value is violated. Though you have to make sure you have a proper APM (monitoring) system in place so you can iterate quickly – as you’re discovering the actual rules of the response data you’ll have to introduce new / relax old constraints.</p>
<p>I plan on doing the last option in my greenfield project that relies on an external API that lacks proper OpenAPI / Swagger docs and relies strictly on institutional knowledge, for the same reason: I am afraid writing my own JSON Schema(s) might take too much time.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="321215" 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/best-way-to-pass-many-arguments-to-a-function/62325/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-321215" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="321215"
                     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>