Building a Phonegap app with Laravel and Angular - Part 1
Published by Matthew Daly at 11th September 2016 6:33 pm
A lot of my work over the last few years has been on Phonegap apps. Phonegap isn't terribly hard to use, but the difference in context between that and a more conventional web app means that you have to move a lot of functionality to the client side, and unless you've used client-side Javascript frameworks before it can be a struggle.
In this series of tutorials I'll show you how I might build a Phonegap app. The work involved will include:
- Building a REST API using Laravel to expose the data
- Building an admin interface to manage the data
- Building a Phonegap app using Angular.js
- Testing and deploying it
In the process we'll cover issues like authentication, authorisation, real-time notifications and working with REST APIs. Note that we won't cover the app submission process - you can find plenty of resources on that. We will, however, be using Phonegap Build to build the app.
The brief
Let's say our new client is an animal shelter. The brief for the app is as follows:
My New Animal Friend will be an app for finding a new pet. Once a user signs in, they'll be able to choose what type of pet they're looking for, then look through a list of pets available to adopt. They can reject them by swiping left or save them by swiping right. They can see more about the ones they swipe right on, and arrange to meet them, from within the app. Users can also message the staff to ask questions about a pet.
Nice idea, but there's a lot of work involved! Our very first task is to build the REST API, since everything else relies on that. Before starting, make sure you have the following installed:
- PHP (I'm using PHP 7, but 5.6 should be fine)
- Composer
- Git
- A compatible relational database (I use PostgreSQL)
- Redis
- Your usual text editor
- Node.js
As long as you have this, you should be ready to go. Using Homestead is the simplest way to get started if you don't have all this stuff already.
Starting the API
To start building our REST API, run the following command from the shell:
$ composer create-project --prefer-dist laravel/laravel mynewanimalfriend-backend
We also have some other dependencies we need to install, so switch into the new directory and run the following command:
$ composer require barryvdh/laravel-cors tymon/jwt-auth predis/predis
Next, we need to add the new packages to the Laravel config. Open up config/app.php
and add the following to the providers
array:
1 Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,2 Barryvdh\Cors\ServiceProvider::class,
And the following to the aliases
array:
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
We also need to ensure that the CORS middleware is applied to all API routes. Open up app/Http/Kernel.php
and under the api
array in protected $middlewareGroups
paste the following:
\Barryvdh\Cors\HandleCors::class,
Now that the packages are included, we can publish the files for them:
$ php artisan vendor:publish
Next, we need to set a key for our API authentication:
$ php artisan jwt:generate
And set a custom namespace:
$ php artisan app:name AnimalFriend
You'll also want to set up the .env
file with the configuration settings for your application. There's one at .env.example
by default that you can copy and customise. Then run the following command to generate the application key:
$ php artisan key:generate
I had to change the namespace for the user model in config/jwt.php
as well:
'user' => 'AnimalFriend\User',
I also tend to amend the settings in phpunit.xml
as follows so that it uses an in-memory SQLite database for tests:
1 <env name="APP_ENV" value="testing"/>2 <env name="SESSION_DRIVER" value="array"/>3 <env name="QUEUE_DRIVER" value="sync"/>4 <env name="CACHE_DRIVER" value="redis"/>5 <env name="DB_CONNECTION" value="sqlite"/>6 <env name="DB_DATABASE" value=":memory:"/>
Also, delete tests/ExampleTest.php
and amend tests/TestCase.php
as follows in order to use database migrations in tests:
1<?php23use Illuminate\Foundation\Testing\DatabaseMigrations;45abstract class TestCase extends Illuminate\Foundation\Testing\TestCase6{7 use DatabaseMigrations;89 /**10 * The base URL to use while testing the application.11 *12 * @var string13 */14 protected $baseUrl = 'http://localhost';1516 /**17 * Creates the application.18 *19 * @return \Illuminate\Foundation\Application20 */21 public function createApplication()22 {23 $app = require __DIR__.'/../bootstrap/app.php';2425 $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();2627 return $app;28 }29}
With that in place, we can start work on our API proper.
Authenticating our API
We're going to start out with a very limited subset of our API. First, we'll implement the authentication for our app, then we'll add the facility to view a list of pets or an individual pet. Other functionality will come later. This will be sufficient to get the app working.
First, we need to create our user model. As we'll be practising TDD throughout, we write a test for the user model first. Save the following as tests/UserModelTest.php
:
1<?php23use AnimalFriend\User;45class UserModelTest extends TestCase6{7 /**8 * Test creating a user9 *10 * @return void11 */12 public function testCreatingAUser()13 {14 // Create a User15 $user = factory(AnimalFriend\User::class)->create([16 'name' => 'bobsmith',17 'email' => 'bob@example.com',18 ]);19 $this->seeInDatabase('users', ['email' => 'bob@example.com']);2021 // Verify it works22 $saved = User::where('email', 'bob@example.com')->first();23 $this->assertEquals($saved->id, 1);24 $this->assertEquals($saved->name, 'bobsmith');25 }26}
If we run the tests:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34. 1 / 1 (100%)56Time: 169 ms, Memory: 12.00MB78OK (1 test, 3 assertions)
We already have a perfectly good User
model and the appropriate migrations, so our test already passes.
Next, we need to implement the authentication system. Save this as tests/AuthTest.php
:
1<?php23use Illuminate\Foundation\Testing\DatabaseMigrations;45class AuthTest extends TestCase6{7 use DatabaseMigrations;89 /**10 * Test the auth11 *12 * @return void13 */14 public function testAuth()15 {16 // Create a User17 $user = factory(AnimalFriend\User::class)->create([18 'name' => 'bobsmith',19 'email' => 'bob@example.com',20 'password' => bcrypt('password')21 ]);2223 // Create request24 $data = array(25 'email' => $user->email,26 'password' => 'password',27 );28 $response = $this->call('POST', 'api/authenticate', $data);29 $this->assertResponseStatus(200);30 $content = json_decode($response->getContent());31 $this->assertTrue(array_key_exists('token', $content));32 }3334 /**35 * Test the auth when user does not exist36 *37 * @return void38 */39 public function testAuthFailure()40 {41 // Create data for request42 $data = array(43 'email' => 'user@example.com',44 'password' => 'password',45 );46 $response = $this->call('POST', 'api/authenticate', $data);4748 // Check the status code49 $this->assertResponseStatus(401);50 }51}
The first test creates a user and sends an authentication request, then confirms that it returns the JSON Web Token. The second checks that a user that doesn't exist cannot log in.
Let's run the tests:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34FF. 3 / 3 (100%)56Time: 328 ms, Memory: 14.00MB78There were 2 failures:9101) AuthTest::testAuth11Expected status code 200, got 404.12Failed asserting that 404 matches expected 200.1314/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:64815/home/matthew/Projects/mynewanimalfriend-backend/tests/AuthTest.php:2916172) AuthTest::testAuthFailure18Expected status code 401, got 404.19Failed asserting that 404 matches expected 401.2021/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:64822/home/matthew/Projects/mynewanimalfriend-backend/tests/AuthTest.php:492324FAILURES!25Tests: 3, Assertions: 5, Failures: 2.
With a failing test in place, we can implement login. First let's create our controller at app/Http/Controllers/AuthenticateController.php
:
1<?php23namespace AnimalFriend\Http\Controllers;45use Illuminate\Http\Request;67use AnimalFriend\Http\Requests;8use AnimalFriend\Http\Controllers\Controller;9use JWTAuth;10use Tymon\JWTAuth\Exceptions\JWTException;11use AnimalFriend\User;12use Hash;1314class AuthenticateController extends Controller15{16 private $user;1718 public function __construct(User $user) {19 $this->user = $user;20 }2122 public function authenticate(Request $request)23 {24 // Get credentials25 $credentials = $request->only('email', 'password');2627 // Get user28 $user = $this->user->where('email', $credentials['email'])->first();2930 try {31 // attempt to verify the credentials and create a token for the user32 if (! $token = JWTAuth::attempt($credentials)) {33 return response()->json(['error' => 'invalid_credentials'], 401);34 }35 } catch (JWTException $e) {36 // something went wrong whilst attempting to encode the token37 return response()->json(['error' => 'could_not_create_token'], 500);38 }3940 // all good so return the token41 return response()->json(compact('token'));42 }43}
And we need to set up the route in routes/api.php
:
1<?php23use Illuminate\Http\Request;45/*6|--------------------------------------------------------------------------7| API Routes8|--------------------------------------------------------------------------9|10| Here is where you can register API routes for your application. These11| routes are loaded by the RouteServiceProvider within a group which12| is assigned the "api" middleware group. Enjoy building your API!13|14*/1516Route::post('authenticate', 'AuthenticateController@authenticate');
Note that because it's an API route, it's automatically prefixed with api/
without us having to do anything.
Now if we run our tests, they should pass:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34... 3 / 3 (100%)56Time: 402 ms, Memory: 14.00MB78OK (3 tests, 6 assertions)
Now we can obtain a JSON Web Token to authenticate users with. To start with we'll only support existing users, but later we'll add a method to sign up. However, we need at least one user to test with, so we'll create a seeder for that at database/seeds/UserTableSeeder.php
:
1<?php23use Illuminate\Database\Seeder;4use Carbon\Carbon;56class UserTableSeeder extends Seeder7{8 /**9 * Run the database seeds.10 *11 * @return void12 */13 public function run()14 {15 // Add user16 DB::table('users')->insert([17 'name' => 'bobsmith',18 'email' => 'bob@example.com',19 'created_at' => Carbon::now(),20 'updated_at' => Carbon::now(),21 'password' => Hash::make("password")22 ]);23 }24}
You can run php artisan make:seeder UserTableSeeder
to generate the file, or just paste it in. You also need to amend database/seeds/DatabaseSeeder.php
as follows:
1<?php23use Illuminate\Database\Seeder;45class DatabaseSeeder extends Seeder6{7 /**8 * Run the database seeds.9 *10 * @return void11 */12 public function run()13 {14 $this->call(UserTableSeeder::class);15 }16}
This ensures the seeder will actually be called. Then, run the following commands:
1$ php artisan migrate2$ php artisan db:seed
That sets up our user in the database.
Adding the Pets endpoint
Our next step is to add the pets model and endpoint. Our Pet
model should have the following fields:
- ID
- Timestamps (
created_at
andupdated_at
) - Name
- Path to photo
- Availability
- Type (eg cat, dog)
Let's create a test for that model:
1<?php23use AnimalFriend\Pet;45class PetModelTest extends TestCase6{7 /**8 * Test creating a pet9 *10 * @return void11 */12 public function testCreatingAPet()13 {14 // Create a Pet15 $pet = factory(AnimalFriend\Pet::class)->create([16 'name' => 'Freddie',17 'type' => 'Cat',18 ]);19 $this->seeInDatabase('pets', ['type' => 'Cat']);2021 // Verify it works22 $saved = Pet::where('name', 'Freddie')->first();23 $this->assertEquals($saved->id, 1);24 $this->assertEquals($saved->name, 'Freddie');25 $this->assertEquals($saved->type, 'Cat');26 $this->assertEquals($saved->available, 1);27 $this->assertEquals($saved->picture, '1.jpg');28 }29}
Save this as tests/PetModelTest.php
. Then run the tests:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34..E. 4 / 4 (100%)56Time: 414 ms, Memory: 16.00MB78There was 1 error:9101) PetModelTest::testCreatingAUser11InvalidArgumentException: Unable to locate factory with name [default] [AnimalFriend\Pet].1213/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:12614/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:228015/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:13916/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:10617/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:8418/home/matthew/Projects/mynewanimalfriend-backend/tests/PetModelTest.php:161920ERRORS!21Tests: 4, Assertions: 6, Errors: 1.
First we need to create a factory for creating a pet in database/factories/ModelFactory.php
:
1$factory->define(AnimalFriend\Pet::class, function (Faker\Generator $faker) {2 return [3 'name' => $faker->firstNameMale,4 'type' => 'Cat',5 'available' => 1,6 'picture' => '1.jpg'7 ];8});
Then, we create the model:
$ php artisan make:model Pet
Next, we create a migration for the Pet
model:
1$ php artisan make:migration create_pets_table2Created Migration: 2016_09_11_145010_create_pets_table
And paste in the following code:
1<?php23use Illuminate\Support\Facades\Schema;4use Illuminate\Database\Schema\Blueprint;5use Illuminate\Database\Migrations\Migration;67class CreatePetsTable extends Migration8{9 /**10 * Run the migrations.11 *12 * @return void13 */14 public function up()15 {16 Schema::create('pets', function (Blueprint $table) {17 $table->increments('id');18 $table->string('name');19 $table->string('type');20 $table->string('available');21 $table->string('picture')->nullable();22 $table->timestamps();23 });24 }2526 /**27 * Reverse the migrations.28 *29 * @return void30 */31 public function down()32 {33 Schema::drop('pets');34 }35}
Time to run the tests again:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34.... 4 / 4 (100%)56Time: 412 ms, Memory: 16.00MB78OK (4 tests, 12 assertions)
With that done, we can start work on implementing the endpoint. We need to check that unauthorised users cannot retrieve the data, and that authorised users can. First, let's create tests/PetControllerTest.php
:
1<?php23use Illuminate\Foundation\Testing\DatabaseMigrations;45class PetControllerTest extends TestCase6{7 use DatabaseMigrations;89 /**10 * Test fetching pets when unauthorised11 *12 * @return void13 */14 public function testFetchingPetsWhenUnauthorised()15 {16 // Create a Pet17 $pet = factory(AnimalFriend\Pet::class)->create([18 'name' => 'Freddie',19 'type' => 'Cat',20 ]);21 $this->seeInDatabase('pets', ['type' => 'Cat']);2223 // Create request24 $response = $this->call('GET', '/api/pets');25 $this->assertResponseStatus(400);26 }2728 /**29 * Test fetching pets when authorised30 *31 * @return void32 */33 public function testFetchingPets()34 {35 // Create a Pet36 $pet = factory(AnimalFriend\Pet::class)->create([37 'name' => 'Freddie',38 'type' => 'Cat',39 ]);40 $this->seeInDatabase('pets', ['type' => 'Cat']);4142 // Create a User43 $user = factory(AnimalFriend\User::class)->create([44 'name' => 'bobsmith',45 'email' => 'bob@example.com',46 ]);47 $this->seeInDatabase('users', ['email' => 'bob@example.com']);4849 // Create request50 $token = JWTAuth::fromUser($user);51 $headers = array(52 'Authorization' => 'Bearer '.$token53 );5455 // Send it56 $this->json('GET', '/api/pets', [], $headers)57 ->seeJsonStructure([58 '*' => [59 'id',60 'name',61 'type',62 'available',63 'picture',64 'created_at',65 'updated_at'66 ]67 ]);68 $this->assertResponseStatus(200);69 }70}
First, we create a pet, make an HTTP request to /api/pets
, and check we are not authorised. Next, we do the same, but also create a user and a JSON Web Token, and pass the token through in the request. Then we verify the response data and that it was successful.
Let's run the tests:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34..FF.. 6 / 6 (100%)56Time: 509 ms, Memory: 16.00MB78There were 2 failures:9101) PetControllerTest::testFetchingPetsWhenUnauthorised11Expected status code 400, got 404.12Failed asserting that 404 matches expected 400.1314/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:64815/home/matthew/Projects/mynewanimalfriend-backend/tests/PetControllerTest.php:2516172) PetControllerTest::testFetchingPets18Failed asserting that null is of type "array".1920/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:29521/home/matthew/Projects/mynewanimalfriend-backend/tests/PetControllerTest.php:672223FAILURES!24Tests: 6, Assertions: 17, Failures: 2.
That looks correct, so we can start building our endpoint. We can generate a boilerplate for it as follows:
$ $ php artisan make:controller PetController --resource
Note the --resource
flag - this tells Laravel to set it up to be a RESTful controller with certain predefined functions. Next, let's amend the new file at app\Http\Controllers/PetController.php
as follows:
1<?php23namespace AnimalFriend\Http\Controllers;45use Illuminate\Http\Request;67use AnimalFriend\Http\Requests;8use AnimalFriend\Pet;910class PetController extends Controller11{12 private $pet;1314 public function __construct(Pet $pet) {15 $this->pet = $pet;16 }1718 /**19 * Display a listing of the resource.20 *21 * @return \Illuminate\Http\Response22 */23 public function index()24 {25 // Get all pets26 $pets = $this->pet->get();2728 // Send response29 return response()->json($pets, 200);30 }31}
This implements an index route that shows all pets. Next, we hook up the route in routes/api.php
:
1// Auth routes2Route::group(['middleware' => ['jwt.auth']], function () {3 Route::resource('pets', 'PetController');4});
Note that we wrap this resource in the jwt.auth
middleware to prevent access by unauthorised users. Implementing this as middleware makes it very easy to reuse. Also note that we can specify it as a resource, meaning we don't have to explicitly hook up each route to a controller method.
Let's run the tests again:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34..EE.. 6 / 6 (100%)56Time: 511 ms, Memory: 16.00MB78There were 2 errors:9101) PetControllerTest::testFetchingPetsWhenUnauthorised11ReflectionException: Class jwt.auth does not exist1213/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Container/Container.php:73414/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Container/Container.php:62915/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:70916/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:17317/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:51718/home/matthew/Projects/mynewanimalfriend-backend/tests/PetControllerTest.php:2419202) PetControllerTest::testFetchingPets21ReflectionException: Class jwt.auth does not exist2223/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Container/Container.php:73424/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Container/Container.php:62925/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:70926/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:17327/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:51728/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:7229/home/matthew/Projects/mynewanimalfriend-backend/tests/PetControllerTest.php:563031ERRORS!32Tests: 6, Assertions: 15, Errors: 2.
Looks like JWT isn't configured correctly. We can fix that in app/Http/Kernel.php
by adding it to $routeMiddleware
:
1 'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',2 'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
And run the tests again:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34...... 6 / 6 (100%)56Time: 514 ms, Memory: 16.00MB78OK (6 tests, 25 assertions)
Our final task for today on the API is building a route for fetching a single pet. Our tests need to handle three situations:
- An unauthorised request
- A request for a pet that does not exist
- A request for a pet that does exist
Add these methods to tests/PetControllerTest.php
:
1 /**2 * Test fetching pet when unauthorised3 *4 * @return void5 */6 public function testFetchingPetWhenUnauthorised()7 {8 // Create a Pet9 $pet = factory(AnimalFriend\Pet::class)->create([10 'name' => 'Freddie',11 'type' => 'Cat',12 ]);13 $this->seeInDatabase('pets', ['type' => 'Cat']);1415 // Send request16 $response = $this->call('GET', '/api/pets/'.$pet->id);17 $this->assertResponseStatus(400);18 }1920 /**21 * Test fetching pet which does not exist22 *23 * @return void24 */25 public function testFetchingPetDoesNotExist()26 {27 // Create a User28 $user = factory(AnimalFriend\User::class)->create([29 'name' => 'bobsmith',30 'email' => 'bob@example.com',31 ]);32 $this->seeInDatabase('users', ['email' => 'bob@example.com']);3334 // Create request35 $token = JWTAuth::fromUser($user);36 $headers = array(37 'Authorization' => 'Bearer '.$token38 );3940 // Send it41 $this->json('GET', '/api/pets/1', [], $headers);42 $this->assertResponseStatus(404);43 }4445 /**46 * Test fetching pet when authorised47 *48 * @return void49 */50 public function testFetchingPet()51 {52 // Create a Pet53 $pet = factory(AnimalFriend\Pet::class)->create([54 'name' => 'Freddie',55 'type' => 'Cat',56 ]);57 $this->seeInDatabase('pets', ['type' => 'Cat']);5859 // Create a User60 $user = factory(AnimalFriend\User::class)->create([61 'name' => 'bobsmith',62 'email' => 'bob@example.com',63 ]);64 $this->seeInDatabase('users', ['email' => 'bob@example.com']);6566 // Create request67 $token = JWTAuth::fromUser($user);68 $headers = array(69 'Authorization' => 'Bearer '.$token70 );7172 // Send it73 $this->json('GET', '/api/pets/'.$pet->id, [], $headers)74 ->seeJsonStructure([75 'id',76 'name',77 'type',78 'available',79 'picture',80 'created_at',81 'updated_at'82 ]);83 $this->assertResponseStatus(200);84 }
Let's check our tests fail:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34.....FE.. 9 / 9 (100%)56Time: 974 ms, Memory: 16.00MB78There was 1 error:9101) PetControllerTest::testFetchingPet11PHPUnit_Framework_Exception: Argument #2 (No Value) of PHPUnit_Framework_Assert::assertArrayHasKey() must be a array or ArrayAccess1213/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:30414/home/matthew/Projects/mynewanimalfriend-backend/tests/PetControllerTest.php:1451516--1718There was 1 failure:19201) PetControllerTest::testFetchingPetDoesNotExist21Expected status code 404, got 400.22Failed asserting that 400 matches expected 404.2324/home/matthew/Projects/mynewanimalfriend-backend/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:64825/home/matthew/Projects/mynewanimalfriend-backend/tests/PetControllerTest.php:1122627ERRORS!28Tests: 9, Assertions: 31, Errors: 1, Failures: 1.
Now, we already have the show()
method hooked up by default, so we just have to implement it in app/Http/Controllers/PetController.php
:
1 /**2 * Display the specified resource.3 *4 * @param int $id5 * @return \Illuminate\Http\Response6 */7 public function show($id)8 {9 // Get pet10 $pet = $this->pet->findOrFail($id);1112 // Send response13 return response()->json($pet, 200);14 }
And let's run our tests again:
1$ vendor/bin/phpunit2PHPUnit 5.5.4 by Sebastian Bergmann and contributors.34......... 9 / 9 (100%)56Time: 693 ms, Memory: 16.00MB78OK (9 tests, 39 assertions)
Now we have all the endpoints we need to get started with the app. You can find the source code for this backend on Github - check out the lesson-1
tag.
That seems like a good place to stop for now. We have our first pass at the back end. It's not complete by any means, but it's a good start, and is sufficient for us to get some basic functionality up and running in the app. In the next instalment we'll start working with Phonegap to build the first pass at the app itself. Later instalments will see us working with both the app and backend to build it into a more useful whole.