Skip to content
This repository has been archived by the owner on Apr 23, 2023. It is now read-only.

Laravel API Ressources

Notifications You must be signed in to change notification settings

cba85/laravel5-7-api-resources

Repository files navigation

API Resources

Basic

  1. Install authentification

    $ php artisan make:auth
    $ php artisan migrate
    • Restart php artisan serve

    • In database/seed/DatabaseSeeder.php:

      https://laravel.com/docs/5.7/seeding

      DB::table('users')->insert([
              'name' => str_random(10),
              'email' => str_random(10).'@gmail.com',
              'password' => bcrypt('secret'),
          ]);
  2. Create a route

    • In routes/web.php:

      Route::get('/user/{user}', function (\App\User $user) {
          return $user;
      });
    • In app/User.php:

      protected $appends = ['humanCreatedAt'];
      
      public function getHumanCreatedAtAttribute()
      {
          return $this->created_at->diffForHumans();
      }
  3. Create a resource

    $ php artisan make:resource UserResource
    • In routes/web.php:
    Route::get('/user/{user}', function (\App\User $user) {
        return new \App\Http\Resources\UserResource($user);
    });
    • In app/Http/Resources/UserResource.php:

      public function toArray($request)
      {
          //return parent::toArray($request);
          return [
              'id' => $this->id,
              'email' => $this->email
          ];
      }

Static collection method

  1. Create model and factory
$ php artisan make:model Topic -mf
  1. Create table in database

    • In database/migrations:

      public function up()
      {
          Schema::create('topics', function (Blueprint $table) {
              $table->increments('id');
              $table->integer('user_id');
              $table->string('title');
              $table->timestamps();
          });
      }
      $ php artisan migrate
    • [WORK] In database/seeders/DatabaseSeeder.php:

      foreach(range(1, 10) as $i) {
          $topic->create([
              'title' => $faker->sentence(),
              'user_id' => 1
          ]);
      }
      foreach(range(1, 10) as $i) {
          $topic->create([
              'title' => $faker->sentence(),
              'user_id' => 2
          ]);
      }
    • [DOESN'T WORK] In database/factories/TopicFactory.php:

      $factory->define(\App\Topic::class, function (Faker $faker) {
          return [
              'title' => $faker->sentence,
              'user_id' => 1,
          ];
      });
      $ php artisan tinker
      factory(\App\Topic::class, 10)->create()
  2. Create resource

    • In routes/web.php:

      Route::get('/topics', function () {
          return new \App\Http\Resources\TopicResource(\App\Topic::get());
      });
      $ php artisan make:resource TopicResource
    • In app/Http/Resources/TopicResource.php:

      public function toArray($request)
      {
          return [
              'id' => $this->id,
              'title' => $this->title
          ];
      }
      public function toArray($request) {
          dd($this->collection);
          dd($this->resource);
      ...
      }
    • In routes/web.php:

      Route::get('/topics', function () {
          return \App\Http\Resources\TopicResource::collection(\App\Topic::get());
      });

Resource collections

  1. Create collection

    $ php artisan make:resource TopicCollection
    # or
    $ php artisan make:resource TopicResourceC --collection
  2. Modify collection

    • In App/Http/Resources/TopicCollection.php:

      public function toArray($request)
      {
          return [
              'id' => $this->id,
              'title' => $this->title
          ];
      }
    • In routes/web.php:

      Route::get('/topics', function () {
          return new \App\Http\Resources\TopicCollection(\App\Topic::get());
      });
    • In App/Http/Resources/TopicCollection.php:

      public function toArray($request)
      {
          //dd($this->collection);
          return [
              'data' => $this->collection,
              'meta' => [
                  'total' => $this->collection->count()
              ]
          ];
      }
      public function toArray($request)
          {
          return [
                  'data' => TopicResource::collection($this->collection),
                  'meta' => [
                      'total' => $this->collection->count()
                  ]
              ];
      }

Another way to add meta

  • In routes/web.php:

    Route::get('/u', function () {
        return new \App\Http\Resources\UserResource(\App\User::find(1));
    });
    Route::get('/u', function () {
        return (new \App\Http\Resources\UserResource(\App\User::find(1)))->additional([
            'meta' => [
                'token' => '123456789'
            ]
        ]);
    });

Pagination

  • In routes/web.php:

    Route::get('/topics', function () {
        return \App\Http\Resources\TopicResource::collection(\App\Topic::paginate(3));
    });
        Route::get('/topics', function () {
        return new \App\Http\Resources\TopicCollection(\App\Topic::paginate(3));
    });

Relationships

  • Create a new Model:

    $ php artisan make:model Post -mf
  • Migration in database/migrations:

    Schema::create('posts', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id');
        $table->integer('topic_id');
        $table->text('body');
        $table->timestamps();
    });
    $ php artisan migrate
  • Seed database:

    • In database/seeds/DatabaseSeeder.php:

      foreach(range(1, 10) as $i) {
          $post->create([
              'topic_id' => 1,
              'body' => $faker->sentence(),
              'user_id' => 1
          ]);
      }
    • In routes/web.php:

      Route::get('/topics', function () {
          return new \App\Http\Resources\TopicCollection(\App\Topic::get());
      });
    • In App/Http/Resources/TopicResource:

      public function toArray($request)
      {
          return [
              'id' => $this->id,
              'title' => $this->title,
              'posts' => $this->posts,
          ];
      }
    • Create a Post resource:

      $ php artisan make:resource PostResource
    • In App/Http/Resources/TopicResource.php:

      public function toArray($request)
      {
          return [
              'id' => $this->id,
              'title' => $this->title,
              'posts' => PostResource::collection($this->posts),
          ];
      }
    • In App\Http\Resource\PostResource.php:

      public function toArray($request)
      {
          return [
              'id' => $this->id,
              'body' => $this->body,
              'user' => new UserResource($this->user)
          ];
      }
    • In App\Post.php:

      public function user()
      {
          return $this->belongsTo(User::class);
      }
    • In App/Http/Resources/TopicResource.php:

      public function toArray($request)
      {
          return [
              'id' => $this->id,
              'title' => $this->title,
              'posts' => PostResource::collection($this->posts),
              'user' => new UserResource($this->user)
          ];
      }
    • In App\Topic.php:

      public function user()
      {
          return $this->belongsTo(User::class);
      }

N+1 problem

  • In routes/web.php:

    DB::listen(function ($query) {
        dump($query->sql);
    });
    Route::get('/topics', function () {
        return new \App\Http\Resources\TopicCollection(\App\Topic::with(['user', 'posts'])->get());
    });

Conditionals

  • In App/Http/Resources/TopicRessource.php:

    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'posts' => PostResource::collection($this->whenLoaded('posts')),
            'user' => new UserResource($this->user)
        ];
    }
  • In routes/web.php:

    return new \App\Http\Resources\TopicCollection(\App\Topic::with(['user'])->get());
  • In App/Http/Resources/TopicRessource.php:

    public function toArray($request)
    {
        $return [
            'id' => $this->id,
            'secret' => 'abc',
            'title' => $this->title,
            'posts' => PostResource::collection($this->whenLoaded('posts')),
            'user' => new UserResource($this->user)
        ];
    }
    public function toArray($request)
    {
        $data = [
            'id' => $this->id,
            'secret' => 'abc',
            'title' => $this->title,
            'posts' => PostResource::collection($this->whenLoaded('posts')),
            'user' => new UserResource($this->user)
        ];
    
        if ($this->user_id == 1) {
            $data['secret'] = 'abc';
        }
    
        return $data;
    }
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'secret' => $this->when($this->user_id == 1, ['abc']),
            'title' => $this->title,
            'posts' => PostResource::collection($this->whenLoaded('posts')),
            'user' => new UserResource($this->user)
        ];
    }
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            $this->mergeWhen($this->user_id == 1, [
                'secret' => 'abc'
            ]),
            'title' => $this->title,
            'posts' => PostResource::collection($this->whenLoaded('posts')),
            'user' => new UserResource($this->user)
        ];
    }

Unit tests

  • Create unit test:

    $ php artisan make:test TopicResourceTest --unit
  • In tests/Unit/TopicResource.php:

    public function testReturnsCorrectData()
    {
        $resource = new \App\Http\Resources\TopicResource($topic = factory(\App\Topic::class)->create());
        dd($resource);
    }
    public function testReturnsCorrectData()
    {/
        $resource = (new \App\Http\Resources\TopicResource($topic = factory(\App\Topic::class)->create()))->jsonSerialize();
        dd($resource);
    }
    public function testReturnsCorrectData()
    {
        $resource = (new \App\Http\Resources\TopicResource($topic = factory(\App\Topic::class)->create()))->jsonSerialize();
        $this->assertArraySubset([
            'id' => $topic->id,
            'title' => $topic->title
        ], $resource);
    }