2

I am using a route /news/{news} and the controller public function show(News $news). When I supply the route with a valid ID, it all works fine and dandy. However, when the ID isn't found, Laravel returns a 404-page. I would rather handle that case myself, since I am using it as an API.

My question resembles this one, but I want to use Dependency Injection, if at all possible. I know I can do a normal News::where(), but that is not how I'd like to solve this. The question, therefor, is; How do I handle a not found case when using Laravel Dependency Injection?

I am building a private API so what I'd like to achieve is to return a JSON value when the news isn't found.

Fredrik
  • 3,027
  • 8
  • 33
  • 66

2 Answers2

2

veNuker's option 2 is a way to go if you would like to customize the resolution logic of your Route Model Binding.

But for a 4th option, why not give Middlewares a try? Let's say you have a

class NewsIsExist
{
    public function handle($request, Closure $next) {
        $news_id = $request->route('news_id');
        $news = News::find($news_id);

        if($news) {
            $request->merge(['news' => $news]);
            return $next($request);
        } else {
            return response()->json([
                'error' => "News not found."
            ], 404);
        }
    }
}

Tweek your routes to use the middleware

Route::get('news/{news_id}', [
    'uses' => "NewsController@show", 
    'middleware' => 'news-exists'
]);

Then you can easily access your News instance in your controller

use Illuminate\Http\Request;

public function show(Request $request) {
    $news = $request->get('news');
}
plmrlnsnts
  • 1,644
  • 12
  • 10
1

New answer

So after updating your question, now we know, you want to simply return JSON value when the news is not found. In this case, I would use route fallback method, which is executed when Laravel catches 404 exceptions. Good thing is, you need to implement this only once, and it will work for news/comments/users and all other things you have in your API. Add this code to your routes file:

Route::fallback(function(){
    return response()->json(['message' => 'Not Found!'], 404);
});

More info - https://themsaid.com/laravel-55-better-404-response-20170921

===========================================================

Previous answer

Since you didn't specify what exactly you want to do, here are a couple of options:

Option 1 - custom error page

https://laravel.com/docs/5.5/errors#custom-http-error-pages

Option 2 - display default item

It will pass another object of News type to your controller

<?php

namespace App\Providers;

use App\News;
use Illuminate\Support\Facades\Route;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // 'news' comes from your route param name
        Route::bind('news', function ($value) {
            $news = News::where('id', $value)->first();
            if ( ! $news) {
                //assuming here the first item is the default one
                $news = News::first();
            }
            return $news;
        });
    }
}

Option 3 - catch all 404s

You can catch all 404 errors and return whatever you want as described here How do I catch exceptions / missing pages in Laravel 5?

lchachurski
  • 1,770
  • 16
  • 21
  • You are right, I did not specify what I actually want to achieve. I have updated the question now. – Fredrik Nov 28 '17 at 20:00