Return error response from custom api endpoint

Hello dear kirby friends,

I was just working on some api-endpoints for my plugin. In certain cases, I’d like to return an error response, so I can handle them a bit better in the panel. In my routes, I can use something like:

return new Response($string, 'text/xml');

I’d like to do something like that in my api-routes, too:

    'api' => [
        'routes' => [
          [
            'pattern' => 'podcaster/stats/(:any)/year/(:num)/month/(:num)',
            'action'  => function ($podcast, $year, $month) {
                $errorMessage = 'U-oh!';
                return new Response($errorMessage, 'application/json', 501);
…
            }
        ],
…

But it doesn’t seem to work, testing in postman returns:

{
    "status": "error",
    "route": "podcaster/stats/([a-zA-Z0-9\\.\\-_%= \\+\\@\\(\\)]+)/month/(-?[0-9]+)/(-?[0-9]+)",
    "exception": "Kirby\\Exception\\NotFoundException",
    "message": "The object \"response\" cannot be resolved",
    "key": "0",
    "file": "by/src/Api/Api.php",
    "line": 395,
    "details": [],
    "code": 404
}

What am I doing wrong? Or isn’t this possible in the api-routes (it works in my “regular” routes)?

Thank you!

Okay, I just got it…

For other looking for a solution:

do not use return, but echo the response:

echo new Response($errorMessage, 'application/json', 501);

you could also throw an exception

[
   'pattern' => 'podcaster/stats/(:any)/year/(:num)/month/(:num)',
   'action'  => function ($podcast, $year, $month) {
      $errorMessage = 'U-oh!';
      throw new Exception($errorMessage, 501);
   }
],

and then catch it in the panel

this.$api
    .get(this.podcaster_stats_url)
    .then(response => {
        console.log(response);
    })
    .catch(error => {
        console.log(error);
    });

I opened an issue and returning Response will be supported in Kirby 3.2.5. Check this commit.

Do you know how to show this error(s) as validation error message in the panel (e.g. in the dialog?)

I want to show the error for the title inside the dialog:

<k-dialog ref="dialog" @submit="$refs.form.submit()">
            <k-form 
                ref="form" 
                v-model="addPageModel" 
                :fields="{
                    title: {
                        label: 'Title',
                        type: 'text',
                        required: true,
                        minlength: 3
                    },
                    ...
                }" 
                @submit="submit" 
            />
        </k-dialog>

You can call the error message like in this example in the docs: Dialog | Kirby CMS

In my template I use the following:

<k-dialog ref="dialog" @submit="$refs.form.submit()" size="medium">
            <k-form 
                ref="form" 
                v-model="addPageModel" 
                :fields="{
                    title: {
                        label: 'Title',
                        type: 'text',
                        required: true,
                        minlength: 3
                    },
                    template: {
                        label: 'Vorlage',
                        type: 'select',
                        options: templates,
                        empty: false
                    },
                    page: {
                        type: 'hidden',
                    }
                }" 
                @submit="submit" 
            />
        </k-dialog>
methods: {
        submit() {
            
            this.$api
                .post(
                    'page-tree/add', 
                    { 
                        title: this.addPageModel.title,
                        template: this.addPageModel.template,
                        fieldValue: this.pages
                    }
                )
                .then((response) => {
                    console.log(response);
                    //this.$refs.dialog.close();
                })
                .catch((error) => {
                    //console.log(error);
                    this.error('hahaha');
                });
        }
    }

It says, that this.error is not a function.