'Use same method for inertia response and json response Laravel Jetstream

I have been using Laravel powered API and VueJS powered frontend, two separate projects for single page application. Now I want to switch to Laravel Jetstream with Inertia.js as I can create SPA in a single project. Here is an example how inertia works-

class UsersController extends Controller

{
    public function index()
    {
        $users = User::active()
            ->orderByName()
            ->get(['id', 'name', 'email']);

        return Inertia::render('Users', [
            'users' => $users
        ]);
    }
}

Now we can define Route::get('users',['UserController::class','index']); and get user list going to localhost:8000/users and see the user list in the web page.

My question is, can I use the same controller and method for API response to use in Mobile App?

I have to build web application and mobile application with same features. For web, I need inertia response and for mobile app, I need json response. For showing the user list in Laravel project, I can use the code above. But how do I return the same response as JSON like return response($users); for mobile application? I can create API routes in api.php and make separate controller or method or add condition for API or Inertia response, but I think there might be a better way to handle both Inertia and JSON response using same controller and method.



Solution 1:[1]

Yes, you can totally do that by checking wether or not request wants a json response. Something like this:

public function index()
{
    $users = User::active()
        ->orderByName()
        ->get(['id', 'name', 'email']);

    if (request()->wantsJson()) {
        return $users;
    }

    return Inertia::render('Users', [
        'users' => $users
    ]);
}

Solution 2:[2]

Being honest here, partial reloads doesn't always cut it. The reason I'm not a big fan is because most things I personally work with are Promise based. With partial reloads, you would be using a callback. I'll show both ways you can do it since recently this has piqued my interest.

If you want to go about doing it yourself via axios for example:

<script>
import { usePage } from '@inertiajs/inertia-vue3';

const { version } = usePage();

export default {
    name: 'Users',
    props: {
        users: Object,
    },
    data() {
        return {
            userObj: [],
            loading: false,
        };
    },
    methods: {
        customReload() {
            this.loading = true;

            this.axios.get('/users', {
                headers: {
                    'X-Inertia': true,
                    'X-Inertia-Partial-Component': 'Users',
                    'X-Inertia-Partial-Data': 'users',
                    'X-Inertia-Version': version.value,
                }
            }).then(({data}) => {
                console.log(data.props.users);
                this.userObj = data.props.users;
            })
            .catch(console.error)
            .then(() => {
                this.loading = false;
            });
        },
    },
};
</script>

Pros

  • Access ANY endpoint and get it's props
  • You can access the data and manipulate it however you like
  • Props are untainted(if you'd like to reference to a previous version)

Cons

  • Does not update props
  • Adds more code complexity
  • Storing multiple objects isn't the best use of ram

Now this other approach, we can look into partial reloads. You can call a partial reload by calling this.$inertia.reload({ only: ['PROP_NAME_HERE'] }), but this isn't all the parameters you can insert.

<script>
export default {
    name: 'Users',
    props: {
        users: Object,
    },
    data() {
        return {
            loading: false,
        };
    },
    methods: {
        partialReload() {
            this.loading = true;
            this.$inertia.reload({
                only: ['users'],
                onSuccess() {
                    // Print new props!
                    console.log(this.users);
                },
                onBefore(PendingVisit) {},
                onError(Errors) {},
                onStart() {},
                onProgress() {},
                onComplete() {},
                onAbort() {},
                onCancel() {},
                onFinish(ActiveVisit) {
                    this.loading = false;
                },
            });
        },
    },
};
</script>

Pros

  • Refresh data in props as per documentation
  • Less memory overhead

Con

  • (bias)Callbacks

I do certainly see a point where both of these can be used. Storing the data you get from your custom axios call, may not be necessary, you could be using it for a small object prop. But point is, the option is yours!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cdruc
Solution 2