<p>It depends on the module handle you chose in <em>config/app.php</em> (the module handle is the key affected to your module in the <code>modules</code> array).</p>
<p>If you want the URL to be <code>/business-logic/example/example-route</code>, the module key must be <code>business-logic</code>:</p>
<pre class="lang-php prettyprint-override"><code>use modules\businesslogic\BusinessLogic;

return [
    'modules' =&gt; [
        'business-logic' =&gt; BusinessLogic::class,
    ],
    'bootstrap' =&gt; [
        'business-logic',
    ]
];
</code></pre>

CC BY-SA 4.0
2021-03-03T11:10:44.887Z
2021-03-03T11:10:44.887Z
nstCactus
<p>Whenever I'm using controllers for direct URL access (e.g. from JavaScript via an XHR or fetch request), I've accessed them using a query string rather than relying on rewritten URLs. So, like this:</p>
<pre><code>https://my-craft-site/index.php?p=actions/business-logic/example/example-route
</code></pre>
<p>If the controller method is intended to be triggered from a form submit, you can just use the <code>actionInput</code> Twig function:</p>
<pre><code>&lt;form method=&quot;post&quot;&gt;
   {{ actionInput('business-logic/example/example-route') }}

   {# Some form input fields here... #}

    &lt;button type=&quot;submit&quot;&gt;
&lt;/form&gt;
</code></pre>

CC BY-SA 4.0
2021-03-03T09:50:30.080Z
2021-03-03T09:50:30.080Z
Martin Spain
<p>The cause of the issue turned out to be an incorrect controllerNamespace reference in the <a href="https://github.com/doublesecretagency/craft-businesslogic" rel="nofollow noreferrer">Business Logic Template</a> example. If anyone else is using the example project to jumpstart a Craft module, be aware of the following:</p>
<p>In that example, the ExampleController.php controller specifies this namespace...</p>
<pre><code>namespace modules\businesslogic\controllers;
</code></pre>
<p>...but BusinessLogic.php sets the controllerNameSpace like this, (note that it's missing <strong>modules\</strong>)...</p>
<pre><code>// Adjust controller namespace for console requests
if (Craft::$app-&gt;getRequest()-&gt;getIsConsoleRequest()) {
    $this-&gt;controllerNamespace = 'businesslogic\\console\\controllers';
}
</code></pre>
<p>...it worked for me after I changed it to match the ExampleController namespace, (note the addition of <strong>modules\</strong> as well as handling both console and web requests)...</p>
<pre><code>// Adjust controller namespace for console requests
if (Craft::$app-&gt;getRequest()-&gt;getIsConsoleRequest()) {
    $this-&gt;controllerNamespace = 'modules\\businesslogic\\console\\controllers';
} else {
    $this-&gt;controllerNamespace = 'modules\\businesslogic\\controllers';
}
</code></pre>
<p><strong>EDIT</strong></p>
<p>To answer my own original question, the correct way to call the module action is:</p>
<pre><code>http://my-craft-site/actions/businesslogic/example/example-route
</code></pre>
<p>Note that <strong>/actions</strong> precedes the <em>module/controller/action</em> portion of the URL, and that the controller and action are <a href="https://en.wiktionary.org/wiki/kebab_case" rel="nofollow noreferrer">kebab-cased</a>. As @nstCactus points out, the module is the module handle defined in <em>config/app.php</em>.</p>

CC BY-SA 4.0
2021-03-03T16:37:01.903Z
2021-03-03T20:57:44.870Z
2021-03-03T20:57:44.870Z
Dan Madoni
<p>Consider the following Craft 3 example module structure:</p>
<pre><code>modules/
    businesslogic/
        controllers/ExampleController.php
        BusinessLogic.php
</code></pre>
<p>...and consider the following action in ExampleController.php:</p>
<pre><code>public function actionExampleRoute()
{
    die('in example-route action');
}
</code></pre>
<p>Assuming everything is set up and configured correctly, is this the correct URL for triggering the action in ExampleController.php?</p>
<pre><code>http://my-craft-site/business-logic/example/example-route
</code></pre>
<p>If so, this is not working for me; it instead results in a 404/Template not found error. I'm not sure if I misunderstand how to determine the correct URL or if I set up something incorrectly.</p>
<p>I am working with the example provided <a href="https://github.com/doublesecretagency/craft-businesslogic" rel="nofollow noreferrer">here</a> and I believe I have followed the <a href="https://doublesecretagency.github.io/craft-businesslogic/installation" rel="nofollow noreferrer">instructions</a> correctly. The instructions include a simple test of the module, and the test succeeds--I'm just not able to get the controller action to work as expected.</p>

<modules>
What is the correct way to format a module controller action URL?
# What is the correct way to format a module controller action URL?

(Asked by: username_0 on 2021-03-02)

Consider the following Craft 3 example module structure:
modules/
    businesslogic/
        controllers/ExampleController.php
        BusinessLogic.php

...and consider the following action in ExampleController.php:
public function actionExampleRoute()
{
    die('in example-route action');
}

Assuming everything is set up and configured correctly, is this the correct URL for triggering the action in ExampleController.php?
http://my-craft-site/business-logic/example/example-route

If so, this is not working for me; it instead results in a 404/Template not found error. I'm not sure if I misunderstand how to determine the correct URL or if I set up something incorrectly.
I am working with the example provided here and I believe I have followed the instructions correctly. The instructions include a simple test of the module, and the test succeeds--I'm just not able to get the controller action to work as expected.

**Tags:** modules

---

## 3 answers

### Answer by username_0 on 2021-03-03. Score: 4 | Accepted answer

The cause of the issue turned out to be an incorrect controllerNamespace reference in the Business Logic Template example. If anyone else is using the example project to jumpstart a Craft module, be aware of the following:
In that example, the ExampleController.php controller specifies this namespace...
namespace modules\businesslogic\controllers;

...but BusinessLogic.php sets the controllerNameSpace like this, (note that it's missing modules\)...
// Adjust controller namespace for console requests
if (Craft::$app->getRequest()->getIsConsoleRequest()) {
    $this->controllerNamespace = 'businesslogic\\console\\controllers';
}

...it worked for me after I changed it to match the ExampleController namespace, (note the addition of modules\ as well as handling both console and web requests)...
// Adjust controller namespace for console requests
if (Craft::$app->getRequest()->getIsConsoleRequest()) {
    $this->controllerNamespace = 'modules\\businesslogic\\console\\controllers';
} else {
    $this->controllerNamespace = 'modules\\businesslogic\\controllers';
}

EDIT
To answer my own original question, the correct way to call the module action is:
http://my-craft-site/actions/businesslogic/example/example-route

Note that /actions precedes the module/controller/action portion of the URL, and that the controller and action are kebab-cased. As @nstCactus points out, the module is the module handle defined in config/app.php.


---

### Answer by username_1 on 2021-03-03. Score: 4

It depends on the module handle you chose in config/app.php (the module handle is the key affected to your module in the modules array).
If you want the URL to be /business-logic/example/example-route, the module key must be business-logic:
use modules\businesslogic\BusinessLogic;

return [
    'modules' => [
        'business-logic' => BusinessLogic::class,
    ],
    'bootstrap' => [
        'business-logic',
    ]
];


---

### Answer by username_2 on 2021-03-03. Score: 2

Whenever I'm using controllers for direct URL access (e.g. from JavaScript via an XHR or fetch request), I've accessed them using a query string rather than relying on rewritten URLs. So, like this:
https://my-craft-site/index.php?p=actions/business-logic/example/example-route

If the controller method is intended to be triggered from a form submit, you can just use the actionInput Twig function:

   {{ actionInput('business-logic/example/example-route') }}

   {# Some form input fields here... #}


---

