SlideShare une entreprise Scribd logo
1  sur  53
Télécharger pour lire hors ligne
REST API 
Development and 
Testing 101 
By Samantha Geitz
A bit about me 
• 3 years of experience in web development 
• Now work for Packback 
• Background mostly in WordPress, a little bit of 
Rails, now use Laravel full-time 
• About 1 year experience building APIs
What we’re going to talk 
about tonight 
• “Typical” Laravel application / MVC 
• What is an API, and why should you care? 
• Shitty way to structure an API 
• Better way to structure an API 
• Demonstration of interacting with API
Our Application 
• Packback 
• Digital textbook rentals for 
college students 
• Resources: Users, Books 
• Users need to be able to “rent” 
books 
• https://github.com/samanthamic 
hele7/packback-rest-api-101 
• Two branches: master and 
api_with_fractal
Anatomy of the“Typical” 
Laravel Application 
• Model (Eloquent) + database 
• Controller + routes 
• View (Blade)
Problems! 
• What happens if we want to build an iOS/Android 
application with our data? 
• What happens if we want to use AngularJS or 
EmberJS? 
• What happens when we want to rebuild the front-end 
in a few years? 
• What happens if we want to let other companies work 
with our data? (Twitter API, Facebook API, etc.)
Solution: 
Let’s build an API! 
(Application Programming Interface)
What the hell does that even mean? 
• APIs only care about data - not what things look like 
• Data in, data out 
• JSON is what most of the cool kids are using 
• Keeps data types intact 
• You can also use XML if you like typing a lot 
• Turns everything into a string
<book> 
<id>1</id> 
<title>The Lord of the Rings</title> 
<author>J. R. R. Tolkien</author> 
</book> 
XML Example 
{ 
"book": { 
"id" : 1, 
"title": "The Lord of the Rings", 
"author": "J. R. R. Tolkien" 
} 
} 
JSON Example
Laravel makes it really easy 
• The client can access routes (which are basically just URLs) 
• Controllers handle logic (or call other classes to handle it for 
them) 
• Get data from or store data in database (via models) 
• ????? 
• PROFIT!!! 
• Return data as JSON
Stuff that we need to do 
• /createUser 
• /fetchUser 
• /setUserPassword 
• /updatePaymentInfo 
• /addBook 
• /getBook 
• /deleteBook 
• /addBooktoUser 
• /removeBook
Okay, this is getting 
kind of confusing
REST to the Rescue! 
• Representational State Transfer 
• Hopefully not what you’re doing if I’m boring you
It does CRUD 
• C - Create (POST) 
• R - Read (GET) 
• U - Update (PATCH/PUT) 
• D - Destroy (DELETE)
Stuff that we need to do 
(the RESTful way) 
• POST /users - Create a new user 
• GET /users - Get all users 
• GET /users/{id} - Get one user by ID 
• PATCH /users/{id} - Update a user by ID 
• DELETE /users/{id} - Delete a user by ID 
• POST /users/{id}/books/{id} - Add a book (or books) to a user 
• GET /users/{id}/books/ - Get a list of books for a specific user 
• etc.
Cool story, bro, but how 
do I actually build an API?
Step 1: Create Databases 
• Run database migrations (the same way as in a regular 
Laravel application) 
• Books, users, pivot 
php artisan migrate
app/database/migrations/2014_11_18_024437_create_users_table.<?php 
use IlluminateDatabaseSchemaBlueprint; 
use IlluminateDatabaseMigrationsMigration; 
class CreateUsersTable extends Migration { 
/** 
* Run the migrations. 
* 
* @return void 
*/ 
public function up() 
{ 
Schema::create('users', function(Blueprint $table) { 
$table->increments('id'); 
$table->string('email'); 
$table->string('name'); 
$table->string('password'); 
$table->timestamps(); 
}); 
} 
/** 
* Reverse the migrations. 
* 
* @return void 
*/ 
public function down() 
{ 
Schema::drop('users'); 
} 
}
app/database/migrations/2014_11_18_024939_create_books_table.<?php 
use IlluminateDatabaseSchemaBlueprint; 
use IlluminateDatabaseMigrationsMigration; 
class CreateBooksTable extends Migration { 
/** 
* Run the migrations. 
* 
* @return void 
*/ 
public function up() 
{ 
Schema::create('books', function(Blueprint $table) { 
$table->increments('id'); 
$table->string('isbn13'); 
$table->string('title'); 
$table->string('author'); 
$table->float('price'); 
$table->timestamps(); 
}); 
} 
/** 
* Reverse the migrations. 
* 
* @return void 
*/ 
public function down() 
{ 
Schema::drop('books'); 
} 
}
database/migrations/2014_11_18_025038_create_books_users_<?php 
use IlluminateDatabaseSchemaBlueprint; 
use IlluminateDatabaseMigrationsMigration; 
class CreateBooksUsersTable extends Migration { 
/** 
* Run the migrations. 
* 
* @return void 
*/ 
public function up() 
{ 
Schema::create('books_users', function(Blueprint $table) { 
$table->increments('id'); 
$table->integer('user_id')->unsigned(); 
$table->foreign('user_id')->references('id')->on('users'); 
$table->integer('book_id')->unsigned(); 
$table->foreign('book_id')->references('id')->on('books'); 
$table->timestamps(); 
}); 
} 
/** 
* Reverse the migrations. 
* 
* @return void 
*/ 
public function down() 
{ 
Schema::table('books_users', function(Blueprint $table) { 
$table->dropForeign('books_users_user_id_foreign'); 
$table->dropForeign('books_users_book_id_foreign'); 
}); 
Schema::drop('books_users'); 
}
Step 2: Seed data 
• Your life will be much easier if you fill your database with fake 
data 
• Faker is easy to use and has realistic fake data: 
https://github.com/fzaninotto/Faker 
• I generally do one seed file per table 
• Hook in database/seeds/DatabaseSeeder.php 
• Make sure you truncate every time the seeder is run or you will 
end up with a ton of data 
php artisan db:seed
Seed Users 
app/database/seeds/UserTableSeeder.php 
<?php 
use CarbonCarbon; 
use FakerFactory as Faker; 
class UserTableSeeder extends Seeder 
{ 
public function run() 
{ 
$faker = Faker::create(); 
DB::table('users')->truncate(); 
for ($i = 0; $i < 50; $i++) { 
DB::table('users')->insert([ 
'email' => $faker->email, 
'name' => $faker->name, 
'password' => Hash::make($faker->word), 
'created_at' => Carbon::now(), 
'updated_at' => Carbon::now() 
]); 
} 
} 
}
Seed Books 
app/database/seeds/BookTableSeeder.php 
<?php 
use CarbonCarbon; 
use FakerFactory as Faker; 
class BookTableSeeder extends Seeder 
{ 
public function run() 
{ 
$faker = Faker::create(); 
DB::table('books')->truncate(); 
for ($i = 0; $i < 50; $i++) { 
DB::table('books')->insert([ 
'isbn13' => $faker->ean13(), 
'title' => $faker->sentence, 
'author' => $faker->name, 
'price' => $faker->randomNumber(2) . '.' . $faker->randomNumber(2), 
'created_at' => Carbon::now(), 
'updated_at' => Carbon::now(), 
]); 
} 
} 
}
Seed User Books 
app/database/seeds/UserBookTableSeeder.php 
<?php 
use CarbonCarbon; 
class UserBookTableSeeder extends Seeder 
{ 
public function run() 
{ 
DB::table('books_users')->truncate(); 
for ($i = 1; $i < 51; $i++) { 
DB::table('books_users')->insert([ 
[ 
'user_id' => $i, 
'book_id' => $i, 
'created_at' => Carbon::now(), 
'updated_at' => Carbon::now() 
], 
[ 
'user_id' => $i, 
'book_id' => 51 - $i, 
'created_at' => Carbon::now(), 
'updated_at' => Carbon::now() 
] 
]); 
} 
} 
}
Step 3: Models 
• Very little difference compared to a more traditional 
Laravel app 
• Define a ManyToMany relationship between users and 
books
app/models/User.php 
class User extends Eloquent implements UserInterface, RemindableInterface { 
use UserTrait, RemindableTrait; 
protected $table = 'users'; 
protected $fillable = ['email', 'name', 'password']; 
protected $hidden = array('password', 'remember_token'); 
public function books() 
{ 
return $this->belongsToMany('Book', 'books_users'); 
} 
public function setPasswordAttribute($password) 
{ 
$this->attributes['password'] = Hash::make($password); 
} 
}
app/models/Book.php 
class Book extends Eloquent { 
protected $table = 'books'; 
protected $fillable = ['isbn13', 'title', 'author', 'price']; 
public function users() 
{ 
return $this->belongsToMany('User', 'books_users'); 
} 
}
Step 4: Routes 
• Should you use Laravel magic? (Route::resource() or 
Route::controller()) 
• Pros: Less code 
• Cons: Less code 
• It is generally clearer (to me) to explicitly define your 
routes (so you have a blueprint) 
• However, some people would disagree, so we’ll look 
at both
RESTful routes 
Option 1 (Less code) 
Route::group(['prefix' => 'api'], function() { 
Route::resource('users', 'UserController'); 
Route::resource('books', 'BookController'); 
}); 
This will automatically look for create, edit, 
index, show, store, update, and destroy 
methods in your controller.
RESTful Routes 
Option 2 (Explicit code) 
Route::group(['prefix' => 'api'], function() { 
Route::group(['prefix' => 'books'], function(){ 
Route::get('', array('uses' => 'BookController@index')); 
Route::get('{book_id}', array('uses' => 'BookController@show')); 
Route::post('', array('uses' => 'BookController@store')); 
Route::patch('{book_id}', array('uses' => 'BookController@update')); 
Route::delete('{book_id}', array('uses' => 'BookController@destroy')); 
}); 
Route::group(['prefix' => 'users'], function(){ 
Route::get('', array('uses' => 'UserController@index')); 
Route::get('{user_id}', array('uses' => 'UserController@show')); 
Route::get('{user_id}/books', array('uses' => 'UserController@showBooks')); 
Route::post('', array('uses' => 'UserController@store')); 
Route::post('{user_id}/books/{book_id}', array('uses' => 'UserController@storeBooks')); 
Route::patch('{user_id}', array('uses' => 'UserController@update')); 
Route::delete('{user_id}', array('uses' => 'UserController@destroy')); 
Route::delete('{user_id}/books/{book_id}', array('uses' => 'UserController@destroyBooks')); 
}); 
});
Let’s talk about status codes 
• Your API needs to send back a HTTP status code 
so that the client knows if the succeeded or failed 
(and if it failed, why) 
• 2xx - GREAT SUCCESS 
• 3xx - Redirect somewhere else 
• 4xx - Client errors 
• 5xx - Service errors
Some common status codes 
• 200 - generic OK 
• 201 - Created OK 
• 301 - Moved permanently and redirect to new location 
• 400 - Generic bad request (often used for validation on models) 
• 401 - Unauthorized (please sign in) 
• 403 - Unauthorized (you are signed in but shouldn’t be accessing this) 
• 404 - Does not exist 
• 500 - API dun goofed 
• 503 - API is not available for some reason 
• Plus lots more!
Step 5: Controllers 
• You will need (at least) 5 methods: index (get all), show (get 
one), store, update, destroy 
• What about create() and edit() (if you use 
Route::resource())? 
• You don’t need them if you’re building a pure data-driven 
API! 
• Use Postman (http://www.getpostman.com/) to interact 
with your API instead of Blade templates
Controllers / Index 
/** 
* Get all books 
* 
* @return Response 
*/ 
public function index() 
{ 
$books = Book::all(); 
return Response::json([ 
'data' => $books 
]); 
} 
/** 
* Get all users 
* 
* @return Response 
*/ 
public function index() 
{ 
$users = User::all(); 
return Response::json([ 
'data' => $users 
]); 
}
Controllers / Show 
/** 
* Get a single user 
* 
* @param $user_id 
* @return Response 
*/ 
public function show($user_id) 
{ 
$user = User::findOrFail($user_id); 
return Response::json([ 
'data' => $user 
]); 
} 
/** 
* Get a single book 
* 
* @param $book_id 
* @return Response 
*/ 
public function show($book_id) 
{ 
$book = Book::findOrFail($book_id); 
return Response::json([ 
'data' => $book 
]); 
}
Controllers / Store 
/** 
* Store a book 
* 
* @return Response 
*/ 
public function store() 
{ 
$input = Input::only('isbn13', 'title', 'author', 
'price'); 
$book = Book::create($input); 
return Response::json([ 
'data' => $book 
]); 
} 
/** 
* Store a user 
* 
* @return Response 
*/ 
public function store() 
{ 
$input = Input::only('email', 'name', 
'password'); 
$user = User::create($input); 
return Response::json([ 
'data' => $user 
]); 
}
Controllers / Update 
/** 
* Update a book 
* 
* @param $book_id 
* @return Response 
*/ 
public function update($book_id) 
{ 
$input = Input::only('isbn13', 'title', 
'author', 'price'); 
$book = Book::find($book_id); 
$book->update($input); 
return Response::json([ 
'data' => $book 
]); 
} 
/** 
* Update a user 
* 
* @param $user_id 
* @return Response 
*/ 
public function update($user_id) 
{ 
$input = Input::only('email', 'name', 
'password'); 
$user = User::findOrFail($user_id); 
$user->update($input); 
return Response::json([ 
'data' => $user 
]); 
}
Controllers / Destroy 
/** 
* Delete a book 
* 
* @param $book_id 
* @return Response 
*/ 
public function destroy($book_id) 
{ 
$book = User::findOrFail($book_id); 
$book->users()->sync([]); 
$book->delete(); 
return Response::json([ 
'success' => true 
]); 
} 
/** 
* Delete a user 
* 
* @param $user_id 
* @return Response 
*/ 
public function destroy($user_id) 
{ 
$user = User::findOrFail($user_id); 
$user->books()->sync([]); 
$user->delete(); 
return Response::json([ 
'success' => true 
]); 
}
Postman 
Demonstration
Let’s Review! 
• Request is sent through client (we used Postman, but could 
be AngularJS app, iPhone app, etc.) 
• Route interprets where it needs to go, sends it to 
appropriate controller + method 
• Controller takes the input and figures out what to do with it 
• Model (Eloquent) interacts with the database 
• Controller returns the data as JSON 
• Look, ma, no views!
A few problems… 
• We’re relying on the Laravel “hidden” attribute to avoid 
showing sensitive information but otherwise have no 
control over what is actually output. This is dangerous. 
• What happens if our database schema changes? 
• For example, we need to add a daily vs semester 
rental price and rename the “price” database column 
• How can we easily show a user + associated books with 
one API call?
Use transformers!
Transformers 
(Not like the robots) 
• “Transform” data per resource so that you have a lot more 
control over what you’re returning and its data type 
• Easy to build your own, or you can use Fractal for more 
advanced features: http://fractal.thephpleague.com/ 
• Serialize, or structure, your transformed data in a more 
specific way 
• Uses items (one object) and collections (group of objects) 
• Easily embed related resources within each other
Book Transformer 
app/Packback/Transformers/BookTransformer.php 
/** 
* Turn book object into generic array 
* 
* @param Book $book 
* @return array 
*/ 
public function transform(Book $book) 
{ 
return [ 
'id' => (int) $book->id, 
'isbn13' => $book->isbn13, 
'title' => $book->title, 
'author' => $book->author, 
// If we needed to rename the 'price' field to 'msrp' 
'msrp' => '$' . money_format('%i', $book->price) 
]; 
}
User Transformer 
app/Packback/Transformers/UserTransformer.php 
/** 
* Turn user object into generic array 
* 
* @param User $user 
* @return array 
*/ 
public function transform(User $user) 
{ 
return [ 
'id' => (int) $user->id, 
'name' => $user->name, 
'email' => $user->email 
]; 
}
/** 
* List of resources possible to include 
* 
* @var array 
*/ 
protected $availableIncludes = [ 
'books' 
]; 
/** 
* Include books in user 
* 
* @param User $user 
* @return LeagueFractalItemResource 
*/ 
public function includeBooks(User $user) 
{ 
$books = $user->books; 
return $this->collection($books, new BookTransformer); 
}
API Controller 
Extend the ApiController in 
UserController and BookController 
/** 
* Wrapper for Laravel's Response::json() method 
* 
* @param array $array 
* @param array $headers 
* @return mixed 
*/ 
protected function respondWithArray(array $array, array $headers = []) 
{ 
return Response::json($array, $this->statusCode, $headers); 
} 
class UserController extends ApiController 
class BookController extends ApiController 
app/controllers/ApiController.php
/** 
* Respond with Fractal Item 
* 
* @param $item 
* @param $callback 
* @return mixed 
*/ 
protected function respondWithItem($item, $callback) 
{ 
$resource = new Item($item, $callback); 
$rootScope = $this->fractal->createData($resource); 
return $this->respondWithArray($rootScope->toArray()); 
} 
/** 
* Respond with Fractal Collection 
* 
* @param $collection 
* @param $callback 
* @return mixed 
*/ 
protected function respondWithCollection($collection, $callback) 
{ 
$resource = new Collection($collection, $callback); 
$rootScope = $this->fractal->createData($resource); 
return $this->respondWithArray($rootScope->toArray()); 
}
Controller with Fractal 
public function index() 
{ 
$books = Book::all(); 
return $this->respondWithCollection($books, new BookTransformer); 
} 
public function show($book_id) 
{ 
$book = Book::findOrFail($book_id); 
return $this->respondWithItem($book, new BookTransformer); 
}
Improved Postman API Calls 
with Fractal
A Disclaimer 
• This app is an over-simplified example 
• Feel free to ignore everything I’ve told you tonight 
• Different conventions/opinions 
• Strict REST doesn’t make sense for every scenario 
• BUT the more you scale, the harder it will be to keep 
your code organized
REST APIs with Laravel 102 
AKA 
Things we didn’t have time to cover tonight 
• Testing :( 
• Pagination - return lots of records, a little bit at a time 
• Validation 
• Better error handling 
• Authentication 
• OOP best practices + design patterns
Questions? 
Twitter: @samanthageitz 
Email: samanthamichele7@gmail.com

Contenu connexe

Tendances

Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!Jorge Vásquez
 
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...Edureka!
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation FrameworkCaserta
 
React Context API
React Context APIReact Context API
React Context APINodeXperts
 
Grails Simple Login
Grails Simple LoginGrails Simple Login
Grails Simple Loginmoniguna
 
REST API and CRUD
REST API and CRUDREST API and CRUD
REST API and CRUDPrem Sanil
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8RichardWarburton
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring DataArturs Drozdovs
 
Advanced Javascript
Advanced JavascriptAdvanced Javascript
Advanced JavascriptAdieu
 
Why TypeScript?
Why TypeScript?Why TypeScript?
Why TypeScript?FITC
 
Introduction à spring boot
Introduction à spring bootIntroduction à spring boot
Introduction à spring bootAntoine Rey
 
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Edureka!
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practicesfelixbillon
 

Tendances (20)

Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!
 
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...
 
Spring MVC
Spring MVCSpring MVC
Spring MVC
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation Framework
 
Complete Java Course
Complete Java CourseComplete Java Course
Complete Java Course
 
React Context API
React Context APIReact Context API
React Context API
 
Spring MVC 3.0 Framework
Spring MVC 3.0 FrameworkSpring MVC 3.0 Framework
Spring MVC 3.0 Framework
 
Grails Simple Login
Grails Simple LoginGrails Simple Login
Grails Simple Login
 
Javascript essentials
Javascript essentialsJavascript essentials
Javascript essentials
 
REST API and CRUD
REST API and CRUDREST API and CRUD
REST API and CRUD
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Advanced Javascript
Advanced JavascriptAdvanced Javascript
Advanced Javascript
 
Why TypeScript?
Why TypeScript?Why TypeScript?
Why TypeScript?
 
JPA and Hibernate
JPA and HibernateJPA and Hibernate
JPA and Hibernate
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 
Introduction à spring boot
Introduction à spring bootIntroduction à spring boot
Introduction à spring boot
 
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practices
 

En vedette

Laravel 5 Annotations: RESTful API routing
Laravel 5 Annotations: RESTful API routingLaravel 5 Annotations: RESTful API routing
Laravel 5 Annotations: RESTful API routingChristopher Pecoraro
 
Web services with laravel
Web services with laravelWeb services with laravel
Web services with laravelConfiz
 
RESTful API development in Laravel 4 - Christopher Pecoraro
RESTful API development in Laravel 4 - Christopher PecoraroRESTful API development in Laravel 4 - Christopher Pecoraro
RESTful API development in Laravel 4 - Christopher PecoraroChristopher Pecoraro
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Elena Kolevska
 
Your rest api using laravel
Your rest api using laravelYour rest api using laravel
Your rest api using laravelSulaeman .
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...GeeksLab Odessa
 
Laravel 5.2 Gates, AuthServiceProvider and Policies
Laravel 5.2 Gates, AuthServiceProvider and PoliciesLaravel 5.2 Gates, AuthServiceProvider and Policies
Laravel 5.2 Gates, AuthServiceProvider and PoliciesAlison Gianotto
 
Super powered API testing
Super powered API testing Super powered API testing
Super powered API testing postmanclient
 
jQuery Keynote - Fall 2010
jQuery Keynote - Fall 2010jQuery Keynote - Fall 2010
jQuery Keynote - Fall 2010jeresig
 
Service-Oriented Architecture
Service-Oriented ArchitectureService-Oriented Architecture
Service-Oriented ArchitectureSamantha Geitz
 
Developing and Testing a MongoDB and Node.js REST API
Developing and Testing a MongoDB and Node.js REST APIDeveloping and Testing a MongoDB and Node.js REST API
Developing and Testing a MongoDB and Node.js REST APIAll Things Open
 
Laravel Restful API and AngularJS
Laravel Restful API and AngularJSLaravel Restful API and AngularJS
Laravel Restful API and AngularJSBlake Newman
 
SOAP-UI The Web service Testing
SOAP-UI The Web service TestingSOAP-UI The Web service Testing
SOAP-UI The Web service TestingGanesh Mandala
 
4 Major Advantages of API Testing
4 Major Advantages of API Testing4 Major Advantages of API Testing
4 Major Advantages of API TestingQASource
 
OpenStack Tempest and REST API testing
OpenStack Tempest and REST API testingOpenStack Tempest and REST API testing
OpenStack Tempest and REST API testingopenstackindia
 
Auto encoding-variational-bayes
Auto encoding-variational-bayesAuto encoding-variational-bayes
Auto encoding-variational-bayesmehdi Cherti
 
software testing on whatsapp
software testing on whatsappsoftware testing on whatsapp
software testing on whatsappnil65
 

En vedette (20)

Laravel 5 Annotations: RESTful API routing
Laravel 5 Annotations: RESTful API routingLaravel 5 Annotations: RESTful API routing
Laravel 5 Annotations: RESTful API routing
 
Web services with laravel
Web services with laravelWeb services with laravel
Web services with laravel
 
RESTful API development in Laravel 4 - Christopher Pecoraro
RESTful API development in Laravel 4 - Christopher PecoraroRESTful API development in Laravel 4 - Christopher Pecoraro
RESTful API development in Laravel 4 - Christopher Pecoraro
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
REST API Laravel
REST API LaravelREST API Laravel
REST API Laravel
 
Your rest api using laravel
Your rest api using laravelYour rest api using laravel
Your rest api using laravel
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
Laravel 5.2 Gates, AuthServiceProvider and Policies
Laravel 5.2 Gates, AuthServiceProvider and PoliciesLaravel 5.2 Gates, AuthServiceProvider and Policies
Laravel 5.2 Gates, AuthServiceProvider and Policies
 
Javascript laravel's friend
Javascript laravel's friendJavascript laravel's friend
Javascript laravel's friend
 
Super powered API testing
Super powered API testing Super powered API testing
Super powered API testing
 
jQuery Keynote - Fall 2010
jQuery Keynote - Fall 2010jQuery Keynote - Fall 2010
jQuery Keynote - Fall 2010
 
Service-Oriented Architecture
Service-Oriented ArchitectureService-Oriented Architecture
Service-Oriented Architecture
 
Developing and Testing a MongoDB and Node.js REST API
Developing and Testing a MongoDB and Node.js REST APIDeveloping and Testing a MongoDB and Node.js REST API
Developing and Testing a MongoDB and Node.js REST API
 
Laravel Restful API and AngularJS
Laravel Restful API and AngularJSLaravel Restful API and AngularJS
Laravel Restful API and AngularJS
 
SOAP-UI The Web service Testing
SOAP-UI The Web service TestingSOAP-UI The Web service Testing
SOAP-UI The Web service Testing
 
Api testing
Api testingApi testing
Api testing
 
4 Major Advantages of API Testing
4 Major Advantages of API Testing4 Major Advantages of API Testing
4 Major Advantages of API Testing
 
OpenStack Tempest and REST API testing
OpenStack Tempest and REST API testingOpenStack Tempest and REST API testing
OpenStack Tempest and REST API testing
 
Auto encoding-variational-bayes
Auto encoding-variational-bayesAuto encoding-variational-bayes
Auto encoding-variational-bayes
 
software testing on whatsapp
software testing on whatsappsoftware testing on whatsapp
software testing on whatsapp
 

Similaire à REST APIs in Laravel 101

Getting to know Laravel 5
Getting to know Laravel 5Getting to know Laravel 5
Getting to know Laravel 5Bukhori Aqid
 
Laravel for Web Artisans
Laravel for Web ArtisansLaravel for Web Artisans
Laravel for Web ArtisansRaf Kewl
 
Getting Started with Rails
Getting Started with RailsGetting Started with Rails
Getting Started with RailsBasayel Said
 
Riding the Edge with Ember.js
Riding the Edge with Ember.jsRiding the Edge with Ember.js
Riding the Edge with Ember.jsaortbals
 
wwc start-launched
wwc start-launchedwwc start-launched
wwc start-launchedMat Schaffer
 
Learning to code for startup mvp session 3
Learning to code for startup mvp session 3Learning to code for startup mvp session 3
Learning to code for startup mvp session 3Henry S
 
Staying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHPStaying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHPOscar Merida
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsMike Subelsky
 
cake phptutorial
cake phptutorialcake phptutorial
cake phptutorialice27
 
Rails and the Apache SOLR Search Engine
Rails and the Apache SOLR Search EngineRails and the Apache SOLR Search Engine
Rails and the Apache SOLR Search EngineDavid Keener
 
PTW Rails Bootcamp
PTW Rails BootcampPTW Rails Bootcamp
PTW Rails BootcampMat Schaffer
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Rapid API Development ArangoDB Foxx
Rapid API Development ArangoDB FoxxRapid API Development ArangoDB Foxx
Rapid API Development ArangoDB FoxxMichael Hackstein
 
Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Herman Peeren
 
Introduction to Laravel Framework (5.2)
Introduction to Laravel Framework (5.2)Introduction to Laravel Framework (5.2)
Introduction to Laravel Framework (5.2)Viral Solani
 
Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyNick Sieger
 

Similaire à REST APIs in Laravel 101 (20)

Supa fast Ruby + Rails
Supa fast Ruby + RailsSupa fast Ruby + Rails
Supa fast Ruby + Rails
 
Getting to know Laravel 5
Getting to know Laravel 5Getting to know Laravel 5
Getting to know Laravel 5
 
MVS: An angular MVC
MVS: An angular MVCMVS: An angular MVC
MVS: An angular MVC
 
Laravel for Web Artisans
Laravel for Web ArtisansLaravel for Web Artisans
Laravel for Web Artisans
 
Getting Started with Rails
Getting Started with RailsGetting Started with Rails
Getting Started with Rails
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Riding the Edge with Ember.js
Riding the Edge with Ember.jsRiding the Edge with Ember.js
Riding the Edge with Ember.js
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
wwc start-launched
wwc start-launchedwwc start-launched
wwc start-launched
 
Learning to code for startup mvp session 3
Learning to code for startup mvp session 3Learning to code for startup mvp session 3
Learning to code for startup mvp session 3
 
Staying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHPStaying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHP
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
cake phptutorial
cake phptutorialcake phptutorial
cake phptutorial
 
Rails and the Apache SOLR Search Engine
Rails and the Apache SOLR Search EngineRails and the Apache SOLR Search Engine
Rails and the Apache SOLR Search Engine
 
PTW Rails Bootcamp
PTW Rails BootcampPTW Rails Bootcamp
PTW Rails Bootcamp
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Rapid API Development ArangoDB Foxx
Rapid API Development ArangoDB FoxxRapid API Development ArangoDB Foxx
Rapid API Development ArangoDB Foxx
 
Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!
 
Introduction to Laravel Framework (5.2)
Introduction to Laravel Framework (5.2)Introduction to Laravel Framework (5.2)
Introduction to Laravel Framework (5.2)
 
Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRuby
 

Dernier

How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?IES VE
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Will Schroeder
 
VoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBXVoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBXTarek Kalaji
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-pyJamie (Taka) Wang
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPathCommunity
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationIES VE
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding TeamAdam Moalla
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfDaniel Santiago Silva Capera
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxGDSC PJATK
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesMd Hossain Ali
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemAsko Soukka
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Brian Pichman
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024SkyPlanner
 

Dernier (20)

How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
 
VoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBXVoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBX
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-py
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
 
20150722 - AGV
20150722 - AGV20150722 - AGV
20150722 - AGV
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
 
201610817 - edge part1
201610817 - edge part1201610817 - edge part1
201610817 - edge part1
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024
 

REST APIs in Laravel 101

  • 1. REST API Development and Testing 101 By Samantha Geitz
  • 2. A bit about me • 3 years of experience in web development • Now work for Packback • Background mostly in WordPress, a little bit of Rails, now use Laravel full-time • About 1 year experience building APIs
  • 3. What we’re going to talk about tonight • “Typical” Laravel application / MVC • What is an API, and why should you care? • Shitty way to structure an API • Better way to structure an API • Demonstration of interacting with API
  • 4. Our Application • Packback • Digital textbook rentals for college students • Resources: Users, Books • Users need to be able to “rent” books • https://github.com/samanthamic hele7/packback-rest-api-101 • Two branches: master and api_with_fractal
  • 5. Anatomy of the“Typical” Laravel Application • Model (Eloquent) + database • Controller + routes • View (Blade)
  • 6. Problems! • What happens if we want to build an iOS/Android application with our data? • What happens if we want to use AngularJS or EmberJS? • What happens when we want to rebuild the front-end in a few years? • What happens if we want to let other companies work with our data? (Twitter API, Facebook API, etc.)
  • 7. Solution: Let’s build an API! (Application Programming Interface)
  • 8. What the hell does that even mean? • APIs only care about data - not what things look like • Data in, data out • JSON is what most of the cool kids are using • Keeps data types intact • You can also use XML if you like typing a lot • Turns everything into a string
  • 9. <book> <id>1</id> <title>The Lord of the Rings</title> <author>J. R. R. Tolkien</author> </book> XML Example { "book": { "id" : 1, "title": "The Lord of the Rings", "author": "J. R. R. Tolkien" } } JSON Example
  • 10. Laravel makes it really easy • The client can access routes (which are basically just URLs) • Controllers handle logic (or call other classes to handle it for them) • Get data from or store data in database (via models) • ????? • PROFIT!!! • Return data as JSON
  • 11. Stuff that we need to do • /createUser • /fetchUser • /setUserPassword • /updatePaymentInfo • /addBook • /getBook • /deleteBook • /addBooktoUser • /removeBook
  • 12. Okay, this is getting kind of confusing
  • 13. REST to the Rescue! • Representational State Transfer • Hopefully not what you’re doing if I’m boring you
  • 14. It does CRUD • C - Create (POST) • R - Read (GET) • U - Update (PATCH/PUT) • D - Destroy (DELETE)
  • 15. Stuff that we need to do (the RESTful way) • POST /users - Create a new user • GET /users - Get all users • GET /users/{id} - Get one user by ID • PATCH /users/{id} - Update a user by ID • DELETE /users/{id} - Delete a user by ID • POST /users/{id}/books/{id} - Add a book (or books) to a user • GET /users/{id}/books/ - Get a list of books for a specific user • etc.
  • 16. Cool story, bro, but how do I actually build an API?
  • 17. Step 1: Create Databases • Run database migrations (the same way as in a regular Laravel application) • Books, users, pivot php artisan migrate
  • 18. app/database/migrations/2014_11_18_024437_create_users_table.<?php use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function(Blueprint $table) { $table->increments('id'); $table->string('email'); $table->string('name'); $table->string('password'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users'); } }
  • 19. app/database/migrations/2014_11_18_024939_create_books_table.<?php use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateBooksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('books', function(Blueprint $table) { $table->increments('id'); $table->string('isbn13'); $table->string('title'); $table->string('author'); $table->float('price'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('books'); } }
  • 20. database/migrations/2014_11_18_025038_create_books_users_<?php use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateBooksUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('books_users', function(Blueprint $table) { $table->increments('id'); $table->integer('user_id')->unsigned(); $table->foreign('user_id')->references('id')->on('users'); $table->integer('book_id')->unsigned(); $table->foreign('book_id')->references('id')->on('books'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('books_users', function(Blueprint $table) { $table->dropForeign('books_users_user_id_foreign'); $table->dropForeign('books_users_book_id_foreign'); }); Schema::drop('books_users'); }
  • 21. Step 2: Seed data • Your life will be much easier if you fill your database with fake data • Faker is easy to use and has realistic fake data: https://github.com/fzaninotto/Faker • I generally do one seed file per table • Hook in database/seeds/DatabaseSeeder.php • Make sure you truncate every time the seeder is run or you will end up with a ton of data php artisan db:seed
  • 22. Seed Users app/database/seeds/UserTableSeeder.php <?php use CarbonCarbon; use FakerFactory as Faker; class UserTableSeeder extends Seeder { public function run() { $faker = Faker::create(); DB::table('users')->truncate(); for ($i = 0; $i < 50; $i++) { DB::table('users')->insert([ 'email' => $faker->email, 'name' => $faker->name, 'password' => Hash::make($faker->word), 'created_at' => Carbon::now(), 'updated_at' => Carbon::now() ]); } } }
  • 23. Seed Books app/database/seeds/BookTableSeeder.php <?php use CarbonCarbon; use FakerFactory as Faker; class BookTableSeeder extends Seeder { public function run() { $faker = Faker::create(); DB::table('books')->truncate(); for ($i = 0; $i < 50; $i++) { DB::table('books')->insert([ 'isbn13' => $faker->ean13(), 'title' => $faker->sentence, 'author' => $faker->name, 'price' => $faker->randomNumber(2) . '.' . $faker->randomNumber(2), 'created_at' => Carbon::now(), 'updated_at' => Carbon::now(), ]); } } }
  • 24. Seed User Books app/database/seeds/UserBookTableSeeder.php <?php use CarbonCarbon; class UserBookTableSeeder extends Seeder { public function run() { DB::table('books_users')->truncate(); for ($i = 1; $i < 51; $i++) { DB::table('books_users')->insert([ [ 'user_id' => $i, 'book_id' => $i, 'created_at' => Carbon::now(), 'updated_at' => Carbon::now() ], [ 'user_id' => $i, 'book_id' => 51 - $i, 'created_at' => Carbon::now(), 'updated_at' => Carbon::now() ] ]); } } }
  • 25. Step 3: Models • Very little difference compared to a more traditional Laravel app • Define a ManyToMany relationship between users and books
  • 26. app/models/User.php class User extends Eloquent implements UserInterface, RemindableInterface { use UserTrait, RemindableTrait; protected $table = 'users'; protected $fillable = ['email', 'name', 'password']; protected $hidden = array('password', 'remember_token'); public function books() { return $this->belongsToMany('Book', 'books_users'); } public function setPasswordAttribute($password) { $this->attributes['password'] = Hash::make($password); } }
  • 27. app/models/Book.php class Book extends Eloquent { protected $table = 'books'; protected $fillable = ['isbn13', 'title', 'author', 'price']; public function users() { return $this->belongsToMany('User', 'books_users'); } }
  • 28. Step 4: Routes • Should you use Laravel magic? (Route::resource() or Route::controller()) • Pros: Less code • Cons: Less code • It is generally clearer (to me) to explicitly define your routes (so you have a blueprint) • However, some people would disagree, so we’ll look at both
  • 29. RESTful routes Option 1 (Less code) Route::group(['prefix' => 'api'], function() { Route::resource('users', 'UserController'); Route::resource('books', 'BookController'); }); This will automatically look for create, edit, index, show, store, update, and destroy methods in your controller.
  • 30. RESTful Routes Option 2 (Explicit code) Route::group(['prefix' => 'api'], function() { Route::group(['prefix' => 'books'], function(){ Route::get('', array('uses' => 'BookController@index')); Route::get('{book_id}', array('uses' => 'BookController@show')); Route::post('', array('uses' => 'BookController@store')); Route::patch('{book_id}', array('uses' => 'BookController@update')); Route::delete('{book_id}', array('uses' => 'BookController@destroy')); }); Route::group(['prefix' => 'users'], function(){ Route::get('', array('uses' => 'UserController@index')); Route::get('{user_id}', array('uses' => 'UserController@show')); Route::get('{user_id}/books', array('uses' => 'UserController@showBooks')); Route::post('', array('uses' => 'UserController@store')); Route::post('{user_id}/books/{book_id}', array('uses' => 'UserController@storeBooks')); Route::patch('{user_id}', array('uses' => 'UserController@update')); Route::delete('{user_id}', array('uses' => 'UserController@destroy')); Route::delete('{user_id}/books/{book_id}', array('uses' => 'UserController@destroyBooks')); }); });
  • 31. Let’s talk about status codes • Your API needs to send back a HTTP status code so that the client knows if the succeeded or failed (and if it failed, why) • 2xx - GREAT SUCCESS • 3xx - Redirect somewhere else • 4xx - Client errors • 5xx - Service errors
  • 32. Some common status codes • 200 - generic OK • 201 - Created OK • 301 - Moved permanently and redirect to new location • 400 - Generic bad request (often used for validation on models) • 401 - Unauthorized (please sign in) • 403 - Unauthorized (you are signed in but shouldn’t be accessing this) • 404 - Does not exist • 500 - API dun goofed • 503 - API is not available for some reason • Plus lots more!
  • 33. Step 5: Controllers • You will need (at least) 5 methods: index (get all), show (get one), store, update, destroy • What about create() and edit() (if you use Route::resource())? • You don’t need them if you’re building a pure data-driven API! • Use Postman (http://www.getpostman.com/) to interact with your API instead of Blade templates
  • 34. Controllers / Index /** * Get all books * * @return Response */ public function index() { $books = Book::all(); return Response::json([ 'data' => $books ]); } /** * Get all users * * @return Response */ public function index() { $users = User::all(); return Response::json([ 'data' => $users ]); }
  • 35. Controllers / Show /** * Get a single user * * @param $user_id * @return Response */ public function show($user_id) { $user = User::findOrFail($user_id); return Response::json([ 'data' => $user ]); } /** * Get a single book * * @param $book_id * @return Response */ public function show($book_id) { $book = Book::findOrFail($book_id); return Response::json([ 'data' => $book ]); }
  • 36. Controllers / Store /** * Store a book * * @return Response */ public function store() { $input = Input::only('isbn13', 'title', 'author', 'price'); $book = Book::create($input); return Response::json([ 'data' => $book ]); } /** * Store a user * * @return Response */ public function store() { $input = Input::only('email', 'name', 'password'); $user = User::create($input); return Response::json([ 'data' => $user ]); }
  • 37. Controllers / Update /** * Update a book * * @param $book_id * @return Response */ public function update($book_id) { $input = Input::only('isbn13', 'title', 'author', 'price'); $book = Book::find($book_id); $book->update($input); return Response::json([ 'data' => $book ]); } /** * Update a user * * @param $user_id * @return Response */ public function update($user_id) { $input = Input::only('email', 'name', 'password'); $user = User::findOrFail($user_id); $user->update($input); return Response::json([ 'data' => $user ]); }
  • 38. Controllers / Destroy /** * Delete a book * * @param $book_id * @return Response */ public function destroy($book_id) { $book = User::findOrFail($book_id); $book->users()->sync([]); $book->delete(); return Response::json([ 'success' => true ]); } /** * Delete a user * * @param $user_id * @return Response */ public function destroy($user_id) { $user = User::findOrFail($user_id); $user->books()->sync([]); $user->delete(); return Response::json([ 'success' => true ]); }
  • 40. Let’s Review! • Request is sent through client (we used Postman, but could be AngularJS app, iPhone app, etc.) • Route interprets where it needs to go, sends it to appropriate controller + method • Controller takes the input and figures out what to do with it • Model (Eloquent) interacts with the database • Controller returns the data as JSON • Look, ma, no views!
  • 41. A few problems… • We’re relying on the Laravel “hidden” attribute to avoid showing sensitive information but otherwise have no control over what is actually output. This is dangerous. • What happens if our database schema changes? • For example, we need to add a daily vs semester rental price and rename the “price” database column • How can we easily show a user + associated books with one API call?
  • 43. Transformers (Not like the robots) • “Transform” data per resource so that you have a lot more control over what you’re returning and its data type • Easy to build your own, or you can use Fractal for more advanced features: http://fractal.thephpleague.com/ • Serialize, or structure, your transformed data in a more specific way • Uses items (one object) and collections (group of objects) • Easily embed related resources within each other
  • 44. Book Transformer app/Packback/Transformers/BookTransformer.php /** * Turn book object into generic array * * @param Book $book * @return array */ public function transform(Book $book) { return [ 'id' => (int) $book->id, 'isbn13' => $book->isbn13, 'title' => $book->title, 'author' => $book->author, // If we needed to rename the 'price' field to 'msrp' 'msrp' => '$' . money_format('%i', $book->price) ]; }
  • 45. User Transformer app/Packback/Transformers/UserTransformer.php /** * Turn user object into generic array * * @param User $user * @return array */ public function transform(User $user) { return [ 'id' => (int) $user->id, 'name' => $user->name, 'email' => $user->email ]; }
  • 46. /** * List of resources possible to include * * @var array */ protected $availableIncludes = [ 'books' ]; /** * Include books in user * * @param User $user * @return LeagueFractalItemResource */ public function includeBooks(User $user) { $books = $user->books; return $this->collection($books, new BookTransformer); }
  • 47. API Controller Extend the ApiController in UserController and BookController /** * Wrapper for Laravel's Response::json() method * * @param array $array * @param array $headers * @return mixed */ protected function respondWithArray(array $array, array $headers = []) { return Response::json($array, $this->statusCode, $headers); } class UserController extends ApiController class BookController extends ApiController app/controllers/ApiController.php
  • 48. /** * Respond with Fractal Item * * @param $item * @param $callback * @return mixed */ protected function respondWithItem($item, $callback) { $resource = new Item($item, $callback); $rootScope = $this->fractal->createData($resource); return $this->respondWithArray($rootScope->toArray()); } /** * Respond with Fractal Collection * * @param $collection * @param $callback * @return mixed */ protected function respondWithCollection($collection, $callback) { $resource = new Collection($collection, $callback); $rootScope = $this->fractal->createData($resource); return $this->respondWithArray($rootScope->toArray()); }
  • 49. Controller with Fractal public function index() { $books = Book::all(); return $this->respondWithCollection($books, new BookTransformer); } public function show($book_id) { $book = Book::findOrFail($book_id); return $this->respondWithItem($book, new BookTransformer); }
  • 50. Improved Postman API Calls with Fractal
  • 51. A Disclaimer • This app is an over-simplified example • Feel free to ignore everything I’ve told you tonight • Different conventions/opinions • Strict REST doesn’t make sense for every scenario • BUT the more you scale, the harder it will be to keep your code organized
  • 52. REST APIs with Laravel 102 AKA Things we didn’t have time to cover tonight • Testing :( • Pagination - return lots of records, a little bit at a time • Validation • Better error handling • Authentication • OOP best practices + design patterns
  • 53. Questions? Twitter: @samanthageitz Email: samanthamichele7@gmail.com