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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Eiji" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Eiji/120/36743_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Eiji
                    <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">
								<aside class="quote no-group" data-username="tmbb" data-post="32" data-topic="6877">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>Lol, my work on Makeup is not “awesome”. It’s literally just writing a grammar for 2 programming languages and steal the Pygments styles to render it <img src="https://forum.elixirforum.com/images/emoji/apple/stuck_out_tongue.png?v=15" title=":stuck_out_tongue:" class="emoji" alt=":stuck_out_tongue:" loading="lazy" width="20" height="20"></p>
</blockquote>
</aside>
<p>Yes it is! You spend your time and your result looks great and finally we can use results of your work for free. Who wants more?<br>
<img src="https://forum.elixirforum.com/uploads/default/original/2X/2/20c9c52366de24191270f0b11311379ce60ac82d.gif?v=15" title=":077:" class="emoji emoji-custom only-emoji" alt=":077:" loading="lazy" width="20" height="20"><br>
Of course many thanks to all that made dependencies that we are using in our libraries, but anyway we are doing good work and it’s awesome! <img src="https://forum.elixirforum.com/images/emoji/apple/smiley.png?v=15" title=":smiley:" class="emoji" alt=":smiley:" 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="46732" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/33">Post #32</a>
	                </div>
	            </div>
              <div id="likers-container-46732" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="46732"
                     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 #32"></div>
  </section>
</div>
    <div class="postbit" id="46738" data-post-id="46738">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I think we can collect ideas, what is possible with this library at all.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="46738" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/34">Post #33</a>
	                </div>
	            </div>
              <div id="likers-container-46738" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="46738"
                     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 #33"></div>
  </section>
</div>
    <div class="postbit" id="46785" data-post-id="46785">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Eiji" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Eiji/120/36743_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Eiji
                    <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><a class="mention" href="/u/shalokshalom" rel="nofollow">@ShalokShalom</a>: In short it’s for defining apis of all 3rd-party apps, libraries and services.</p>
<p>I created this library to declare unique apis of multiple sources where each implementation could not support some part(s) of that api or is just partially implemented.</p>
<p>Also this library could be used as an alternative when you want to use <code>Bahaviour</code> and <code>Protocol</code>, but you don’t have a data that could be passed to each function - again see REST 3rd-party api services. Sometimes you prefer to write <code>MyImpl.get_all()</code> instead of <code>MyImpl.get_all(%MyEmptyStruct{})</code> + you can dynamically list all implementations (which is not supported in plain <code>Behaviour</code>).</p>
<p>Another helpful thing is that your implementations are identified by <code>{group, id}</code> (both atoms), so you can group implementations and identify them simply by atom. Imagine that you want to create protocol that declares unique code hosting api for <code>bitbucket</code>, <code>github</code>, <code>gitlab</code> and other services. You could pass empty struct or struct with base url, but why do you need to pass anything when you want simply fetch all issues for <code>github</code> implementation?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="46785" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/35">Post #34</a>
	                </div>
	            </div>
              <div id="likers-container-46785" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="46785"
                     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 #34"></div>
  </section>
</div>
    <div class="postbit" id="46788" data-post-id="46788">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Eiji" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Eiji/120/36743_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Eiji
                    <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>For all interested: I pushed new commit to master (not next rc yet).<br>
This version has support for <code>Phoenix.PubSub</code>. I also updated validation part - they are used before calling or casting server + I added specs for all methods that used <code>cast</code> function. Now they returns: <code>{:ok, server_pid}</code> or <code>{:error, error_struct}</code> instead of <code>:ok</code>.<br>
I’m want to add more things before next release candidate. I plan to release it tomorrow or in Monday.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="46788" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/36">Post #35</a>
	                </div>
	            </div>
              <div id="likers-container-46788" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="46788"
                     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 #35"></div>
  </section>
</div>
    <div class="postbit" id="46829" data-post-id="46829">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Eiji" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Eiji/120/36743_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Eiji
                    <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>Just pushed new change to master. From now each api will use <code>GenServer</code>. Currently there is one async function <code>feature_for/4</code>.<br>
This is introduced, because now you can call each feature asynchronously (using implementation api) or synchronously (using just implementation).</p>
<p>For example after you compile code like it:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def_api MyApi do
  @moduledoc "Example api"

  @doc "Do something really long"
  @spec feature_name(term) :: term
  def_feature feature_name(first_argument)

  def_impl :my_impl do
    def_feature_impl feature_name(first_argument) do
      Process.sleep(1000)
      "result: " &lt;&gt; to_string(first_argument)
    end
  end
end

# config for auto load:
use Mix.Config

config :ex_api, apis: %{MyApi =&gt; [MyApi.MyImpl]}
</code></pre>
<p>you can call <code>feature_name</code> asynchronously like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># Note: no need to implement error callback if you don't expect and/or want catch errors
MyApi.feature_for({nil, :my_impl}, :feature_name, ["sample"], fn result -&gt; IO.puts result end)
</code></pre>
<p>or you can also call it synchronously like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># Note: if not specified group name is nil by default
{:ok, impl} = ExApi.get_impl(MyApi, {nil, :my_impl})
impl.module.feature_name("sample")
# or using module name:
MyApi.MyImpl.feature_name("sample")
</code></pre>
<p>I want to implement two more features (fallback implementation for api if no other implementations are registered and checking feature support, so you can firstly check support and then call feature). I plan to implement them tomorrow.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="46829" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/37">Post #36</a>
	                </div>
	            </div>
              <div id="likers-container-46829" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="46829"
                     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 #36"></div>
  </section>
</div>
    <div class="postbit" id="47165" data-post-id="47165">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Eiji" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Eiji/120/36743_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Eiji
                    <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>I just published second release candidate for <code>ExApi</code>!</p>
<p>ping: <a class="mention" href="/u/overminddl1" rel="nofollow">@OvermindDL1</a>,</p>
<p>You can find docs <a href="https://hexdocs.pm/ex_api/1.0.0-rc.2/" rel="noopener nofollow ugc">here</a>. Please let me know if something is still unclear.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="47165" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/38">Post #37</a>
	                </div>
	            </div>
              <div id="likers-container-47165" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="47165"
                     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 #37"></div>
  </section>
</div>
    <div class="postbit" id="47219" data-post-id="47219">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="Eiji" data-post="38" data-topic="6877">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/eiji/48/36743_2.png" class="avatar"> Eiji:</div>
<blockquote>
<p>You can find docs here.</p>
</blockquote>
</aside>
<p>s/implmentations/implementations/  <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>A question, is it suitable for a plugin system like, say, Firestorm forum or so?  Where they could setup an ‘api’ with a set of hookpoints, and they call those hooks to have plugins do things like run some code or add something to the display or so?  And if so, what would that look like?  Say for these use-cases:</p>
<ol>
<li>Rendering a post so it calls the hook for that, one of the hooks wants to add a thumbs-up button to the bottom of the post, and another hook wants to take that post and change github links to contain inline content from the github link (so it needs to take the existing template and return a mutated version while all other hooks have their own chances to do the same).</li>
<li>Hooking into when a post is saved so it can sanitize words or throw an error and another wants to take a post when it is saved so it can scan it for indexing purposes (it needs to take the post content and probably should return a mutated version of it that).</li>
</ol>
<p>Things like that…</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="47219" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/39">Post #38</a>
	                </div>
	            </div>
              <div id="likers-container-47219" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="47219"
                     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 #38"></div>
  </section>
</div>
    <div class="postbit" id="47230" data-post-id="47230">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Eiji" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Eiji/120/36743_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Eiji
                    <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">
								<aside class="quote no-group" data-username="OvermindDL1" data-post="39" data-topic="6877">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>s/implmentations/implementations/  <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>
</blockquote>
</aside>
<p>Ooops, thanks <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>
<aside class="quote no-group" data-username="OvermindDL1" data-post="39" data-topic="6877">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>A question, is it suitable for a plugin system like, say, Firestorm forum or so?  Where they could setup an ‘api’ with a set of hookpoints, and they call those hooks to have plugins do things like run some code or add something to the display or so?  And if so, what would that look like?</p>
</blockquote>
</aside>
<p>Firstly, I need to say that I don’t wrote any forums and plug-ins for them, so maybe someone could correct me. Here is one possible solution:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># in your code
import ExApi.Api

def_api Firestorm.Hooks.Api do
  @moduledoc "Hooks API for Firestorm forum."

  # @doc "Hook description goes here ..."
  # @spec first_hook_name(...)
  def_feature first_hook_name(arg1, arg2, ...)

  # other feature implementations, declare no support or simply don't implement
end

# in plug-in code:
import ExApi.Implementation

def_api_impl Firestorm.Hooks.Api, :overmind_dl1_hooks, OvermindDL1.Firestorm.HooksImplementation do
  def_feature_impl first_hook_name(arg1, arg2, ...) do
    # hook implementation
  end

  # other feature definitions
end

# main hooks module:
defmodule Firestorm.Hooks do
  alias Firesotrm.Hooks.Api

  def call(name, args, finish_callback, failure_callback) when is_atom(name) and is_list(args) and is_function(finish_callback) and is_function(failure_callback) do
    func_call = {name, Enum.count(args} # {name, arity}
    {:ok, hooks_api_impls} = ExApi.get_impls(Api)
    # here `hooks_api_impls` is a map %{group_name =&gt; impls}
    # you could get hooks for specified group
    # or get map values and flatten result
    # for example, you want to declare `def core_call(name, args)`
    # and fetch impls like: `hooks_api_impls[:firestorm_core]`
    choosed_hooks = # ...
    for impl &lt;- choosed_hooks, is_supported_hook(impl, func_call) do
      # here you could call hook asynchronously like:
      {:ok, _pid} = impl.api.feature_for(impl, name, args, &amp;finish_callback/1, &amp;failure_callback/1)
      # or synchronously like:
      case apply(impl.module, name, args) do
        {:ok, result} -&gt; apply(&amp;finish_callback(result))
        {:error, error} -&gt; apply(&amp;failure_callback(result))
      end
    end
  end

  defp is_supported_hook(impl, func_call) do
    {:ok, result} = ExApi.get_feature_support(impl, func_call)
  end
end
</code></pre>
<p>Of course you need to implement something like <code>Firesotrm.Hooks.Loader</code>.</p>
<aside class="quote no-group" data-username="OvermindDL1" data-post="39" data-topic="6877">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>Rendering a post so it calls the hook for that, one of the hooks wants to add a thumbs-up button to the bottom of the post, and another hook wants to take that post and change github links to contain inline content from the github link (so it needs to take the existing template and return a mutated version while all other hooks have their own chances to do the same).</p>
</blockquote>
</aside>
<p>Hmm, how about that these hooks will use <a href="https://hex.pm/packages/drab" rel="nofollow">drab library</a>?</p>
<aside class="quote no-group" data-username="OvermindDL1" data-post="39" data-topic="6877">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>Hooking into when a post is saved so it can sanitize words or throw an error and another wants to take a post when it is saved so it can scan it for indexing purposes (it needs to take the post content and probably should return a mutated version of it that).</p>
</blockquote>
</aside>
<p>Hmm, my idea is to do something like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Firestorm.Article do
  @moduledoc "Article context"

  alias Firestorm.Article.Post
  alias Firestorm.{Hooks, Repo}

  @doc "Validates, call hooks and saves post data into database"
  def save_post(input_data) do
    changeset = Post.changeset(input_data)
    Hooks.call(:before_save_post, [changeset], &amp;on_before_save_post_finish/1, &amp;on_before_save_post_failure/1)
  end

  defp on_before_save_post_failure(error) do
    # format error and show user, auto-submit bug, or just do nothing :-)
  end

  defp on_before_save_post_finish(result) do
    Repo.insert(result)
  end

  # other context functions ...
end
</code></pre>
<p>I wrote this response quickly so there could be errors/mistakes/typos, but this answer firstly comes to my mind. Let me think what do you think about 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="47230" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/40">Post #39</a>
	                </div>
	            </div>
              <div id="likers-container-47230" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="47230"
                     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 #39"></div>
  </section>
</div>
    <div class="postbit" id="47234" data-post-id="47234">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Well that looks awesome!  That is what I was most curious about, an example I could digest to see how it works (I need to dedicate some time to read your extensive thoughts, I keep getting distracted at work so cannot keep my mind on them long enough for it to soak in ^.^;).</p>
<p>Looks quite cool!  <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="47234" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/41">Post #40</a>
	                </div>
	            </div>
              <div id="likers-container-47234" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="47234"
                     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 #40"></div>
  </section>
</div>
    <div class="postbit" id="47393" data-post-id="47393">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Hey, thanks for mentioning the Firestorm forum, this will be interesting for a friend of mine ^-^</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="47393" 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/exapi-a-library-for-creating-and-managing-apis-and-their-implementations/6877/42">Post #41</a>
	                </div>
	            </div>
              <div id="likers-container-47393" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="47393"
                     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 #41"></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/6877/load_more?page=5">Load more posts (1 remaining)</a>
</div></template></turbo-stream>