Courses

Vue Inertia + Laravel 11: From Scratch

Protect Your Inertia Data with API Resources

Summary of this lesson:
- Implementing API Resources with Inertia
- Managing data transformation
- Securing frontend data exposure
- Formatting response data structure

In this lesson, I want to show that you can still use API resources or Eloquent API resources to transform that data, although you don't use API directly.


Why Use API Resources?

For example, in the initial project, using Vue.js with API, the content was stripped to 50 symbols and the created at date was formatted as a date time string. For that, the API Eloquent resources were used. API resources can also be used with Inertia.

Why do you need to do that? There are two reasons:

  1. Format the data however you want.
  2. Limiting data that is passed to the front-end.

Keep in mind that all that data is passed to the front-end if you are dealing with a web project without API, Inertia, view, or anything that is on the back end. So, in the front-end, the user doesn't see all that data unless it is shown in the blade.

But in the Vue.js and Inertia case, everything is seen on the front end. Everything can be seen if you pass posts as Post:all() to the front end. If you open the network tab in the developer tools in the data-page, all the data is JSON.

You may not want to pass all that, or you may want some things to be hidden. For example, although you don't show some columns in the Vue.js, they are still shown here, which may, again, be a security issue, especially if you're working with user data.

So, you may accidentally pass some token or some hidden field. For both of those reasons, I suggest transforming your data. Of course, you could manually select all fields, but I would still suggest using API Resource.


How To Use API Resources

You can create the API Resource using an Artisan command.

php artisan make:resource PostResource

app/Http/Resources/PostResource.php:

class PostResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => substr($this->content, 0, 50) . '...',
'created_at' => $this->created_at->toDateString(),
];
}
}

Now, API Resources can be used in the Controller.

app/Http/Controllers/PostController.php:

use App\Models\Post;
use Inertia\Inertia;
use Inertia\Response;
use App\Http\Resources\PostResource;
use Illuminate\Http\Resources\Json\JsonResource;
 
class PostController extends Controller
{
public function index(): Response
{
$posts = Post::all();
$posts = PostResource::collection(Post::all());
 
return Inertia::render('Posts/Index', compact('posts'));
}
}

The difference is that API Resource now wraps returned data with a data key. There are two ways to fix it.

The first option is to disable wrapping in the AppServiceProvider.

app/Providers/AppServiceProvider.php:

use Illuminate\Http\Resources\Json\JsonResource;
 
class AppServiceProvider extends ServiceProvider
{
// ...
 
public function boot(): void
{
JsonResource::withoutWrapping();
}
}

Or, when iterating posts, add the data key.

resources/js/Pages/Posts/Index.vue:

// ...
 
<tr v-for="post in posts">
<tr v-for="post in posts.data">
 
// ...

On the posts page, content is now only 50 symbols and created_at as a string.

Previous: From Vue + API to Vue Inertia: Table of Data
avatar

If don't have the Api directory inside the controllers because I am not building an API. Is still recommended to create it for the api resources and to customize the pass values to Inertia? Or just use the get->fields?

avatar

If you mean API resource, It is not necessary but it is good to do. Because you can specify column instead of using Post::all();

For others, I don't know.

avatar
You can use Markdown
avatar
You can use Markdown