Answers.Body: <p>Sure – the <code>element-api.php</code> config file is just plain ol' PHP, and the functions that make up the individual endpoints (e.g. <code>'news.json' =&gt; function () { ...</code>) doesn't necessarily have to be declared inside that file.</p>
  
  <p>One way to split up the file would be to create one PHP class per element type or section. You could compose these classes however you'd like, but something like the below would work (this is an example file containing two endpoints for the <code>news</code> section, and the example assumes that the file is saved under <code>/config/endpoints/News.php</code>):</p>
  
  <pre><code>&lt;?php
  
  namespace config\endpoints;
  
  use craft\elements\Entry;
  use craft\helpers\UrlHelper;
  
  class News {
  
      public static function index()
      {
          return [
              'elementType' =&gt; Entry::class,
              'criteria' =&gt; ['section' =&gt; 'news'],
              'transformer' =&gt; function(Entry $entry) {
                  ...
              }
          ];
      }
  
      public static function view($entryId)
      {
          return [
              'elementType' =&gt; Entry::class,
              'criteria' =&gt; ['id' =&gt; $entryId],
              'one' =&gt; true,
              'transformer' =&gt; function(Entry $entry) {
                   ...
              }
          ];
      }
  }
  </code></pre>
  
  <p>The next step is to make the file available to the <code>element-api.php</code> config file. One way to do it, is to simply <code>include()</code> it at the top of the <code>element-api.php</code> file:</p>
  
  <pre><code>include __DIR__ . '/endpoints/News.php';
  </code></pre>
  
  <p>Then, you can add the endpoints from the <code>News</code> endpoint class to the config in <code>element-api.php</code>, i.e.:</p>
  
  <pre><code>&lt;?php
  
  include __DIR__ . '/endpoints/News.php';
  
  use config\endpoints\News;
  
  return [
      'endpoints' =&gt; [
          // use an anonymous function to prevent errors when running via cli
          'news.json' =&gt; function () {
              return News::index();
          },
          'news/&lt;entryId:\d+&gt;.json' =&gt; function ($entryId) {
              return News::view($entryId);
          },
      ],
  ];
  </code></pre>
  
  <p>If you want to take this a step further, a much nicer approach than using <code>include()</code> is to have Composer autoload your endpoint classes by adding the below to your <code>composer.json</code> file (again, this assumes that the custom endpoint classes live under <code>/config/endpoints/</code>):</p>
  
  <pre><code>"autoload": {
      "psr-4": {
          "config\\endpoints\\": "config/endpoints"
      }
  },
  </code></pre>
  
  <p>After editing your <code>composer.json</code> file, make sure to regenerate the autoloader by running the following from your command line (root of project, same directory where you keep your <code>composer.json</code>:</p>
  
  <pre><code>composer dump-autoload -o
  </code></pre>
  
  <p>Then, you can strip out the <code>include()</code> statement(s) in your <code>element-api.php</code> file, because Composer will autoload all the classes under <code>/config/endpoints</code>.</p>
  
  <p>Finally, to make things super clean you could of course <a href="https://nystudio107.com/blog/enhancing-a-craft-cms-3-website-with-a-custom-module" rel="nofollow noreferrer">create a custom Yii Module</a> (or a Craft plugin) to contain your endpoint classes. This would also avoid having to manually add the classpath to the <code>composer.json</code> file, for the autoloading.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-08-22T09:32:29.917Z
Answers.Text: I've given it a try as you've described but for some reason the slug / entry ID don't get passed through to the view function at all so it just returns the most recent entry every time. So you have any idea why this wouldn't be working?
Answers.UserDisplayName: George Feast-Parker
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-08-22T09:52:42.060Z
Answers.Text: @GeorgeFeast-Parker Yeah, I took another look at it, and I messed up the original  example. Check out the latest edit; it should work.
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-11-12T19:15:03.943Z
Answers.Text: Wonderful, thanks a lot for that! 
  
  One question: why does it need the anonymous function when a parameter is passed, what is the reason `'news/<entryId:\d+>.json' => News::view($entryId);` won't work?
Answers.UserDisplayName: Urs
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-11-24T08:39:19.467Z
Answers.Text: And here's the answer to that from Pixel&Tonic: "make sure all of your endpoint config are inside an anonymous function. Doing so will ensure your endpoint config will only be generated when the endpoint is actually requested, rather than on every web & console request". When element-api was triggerd by cli, I got many errors. I'll edit above.
Answers.UserDisplayName: Urs
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-08-03T09:42:53.090Z
Answers.LastActivityDate: 2019-11-25T19:08:05.037Z
Answers.LastEditDate: 2019-11-25T19:08:05.037Z
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Body: <p>Is there some way I can split the element-api.php file into separate files and import them all? It's getting quite long and unwieldy.</p>
  
Tags: <plugin-elementapi>
Title: Is there a way to split the element-api.php file?
ThreadText: # Is there a way to split the element-api.php file?
  
  (Asked by: username_0 on 2018-08-03)
  
  Is there some way I can split the element-api.php file into separate files and import them all? It's getting quite long and unwieldy.
  
  **Tags:** plugin-elementapi
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2018-08-03. Score: 7
  
  Sure – the `element-api.php` config file is just plain ol' PHP, and the functions that make up the individual endpoints (e.g. `'news.json' => function () { ...`) doesn't necessarily have to be declared inside that file.
  
  One way to split up the file would be to create one PHP class per element type or section. You could compose these classes however you'd like, but something like the below would work (this is an example file containing two endpoints for the `news` section, and the example assumes that the file is saved under `/config/endpoints/News.php`):
  
  ```
  <?php
  
  namespace config\endpoints;
  
  use craft\elements\Entry;
  use craft\helpers\UrlHelper;
  
  class News {
  
      public static function index()
      {
          return [
              'elementType' => Entry::class,
              'criteria' => ['section' => 'news'],
              'transformer' => function(Entry $entry) {
                  ...
              }
          ];
      }
  
      public static function view($entryId)
      {
          return [
              'elementType' => Entry::class,
              'criteria' => ['id' => $entryId],
              'one' => true,
              'transformer' => function(Entry $entry) {
                   ...
              }
          ];
      }
  }
  
  ```
  
  The next step is to make the file available to the `element-api.php` config file. One way to do it, is to simply `include()` it at the top of the `element-api.php` file:
  
  ```
  include __DIR__ . '/endpoints/News.php';
  
  ```
  
  Then, you can add the endpoints from the `News` endpoint class to the config in `element-api.php`, i.e.:
  
  ```
  <?php
  
  include __DIR__ . '/endpoints/News.php';
  
  use config\endpoints\News;
  
  return [
      'endpoints' => [
          // use an anonymous function to prevent errors when running via cli
          'news.json' => function () {
              return News::index();
          },
          'news/<entryId:\d+>.json' => function ($entryId) {
              return News::view($entryId);
          },
      ],
  ];
  
  ```
  
  If you want to take this a step further, a much nicer approach than using `include()` is to have Composer autoload your endpoint classes by adding the below to your `composer.json` file (again, this assumes that the custom endpoint classes live under `/config/endpoints/`):
  
  ```
  "autoload": {
      "psr-4": {
          "config\\endpoints\\": "config/endpoints"
      }
  },
  
  ```
  
  After editing your `composer.json` file, make sure to regenerate the autoloader by running the following from your command line (root of project, same directory where you keep your `composer.json`:
  
  ```
  composer dump-autoload -o
  
  ```
  
  Then, you can strip out the `include()` statement(s) in your `element-api.php` file, because Composer will autoload all the classes under `/config/endpoints`.
  
  Finally, to make things super clean you could of course [create a custom Yii Module](https://nystudio107.com/blog/enhancing-a-craft-cms-3-website-with-a-custom-module) (or a Craft plugin) to contain your endpoint classes. This would also avoid having to manually add the classpath to the `composer.json` file, for the autoloading.
  
  > **Comments:**
  > **username_0**: I've given it a try as you've described but for some reason the slug / entry ID don't get passed through to the view function at all so it just returns the most recent entry every time. So you have any idea why this wouldn't be working?  
  > **username_1**: @username_0 Yeah, I took another look at it, and I messed up the original  example. Check out the latest edit; it should work.  
  > **username_2**: Wonderful, thanks a lot for that!   One question: why does it need the anonymous function when a parameter is passed, what is the reason `'news/<entryId:\d+>.json' => News::view($entryId);` won't work?  
  > **username_2**: And here's the answer to that from Pixel&Tonic: "make sure all of your endpoint config are inside an anonymous function. Doing so will ensure your endpoint config will only be generated when the endpoint is actually requested, rather than on every web & console request". When element-api was triggerd by cli, I got many errors. I'll edit above.  
  
  ---
  
  