Ya hemos visto como consumir una API con Vue.js anteriormente, en esta miniserie de entradas (no sé cuántas tendrá), veremos como crear una API con Lumen (micro-framework de los creadores de Laravel) y consumirla con Vue.js 2, es decir, Lumen será el backend y Vue.js 2 será el frontend de la app. La aplicación de ejemplo que crearemos será una web muy simple para compartir enlaces (un link sharing). Digo que la app que crearemos será muy simple porque no tendrá sistema de usuarios (ya veremos en otro momento como hacerlo), ni sistema de votos, ni nada complejo, simplemente se podrán ver, crear y eliminar los enlaces.
En esta primera entrada, veremos como crear la API para esta app. Esta API será súper simple, con ella simplemente podremos obtener todos los enlaces y crear y eliminar un enlace.
Primero de todo, tenemos que instalar Lumen:
1 |
composer create-project --prefer-dist laravel/lumen <nombre> |
Donde pone <nombre> ponemos el nombre que queramos darle, yo por ejemplo he puesto backend, ya que voy a separar el backend (Lumen) y el frontend (Vue.js) en carpetas diferentes.
Cuando finalice entramos a la carpeta creada y ejecutamos:
1 |
php -S localhost:8000 -t public |
Con este comando, ejecutaremos el servidor y si entramos a http://localhost:8000/ veremos que nos saldrá la versión que hayamos instalado de Lumen.
Vamos a empezar a crear la API. Primero configuramos la conexión a la base de datos, abrimos el archivo .env y añadimos el nombre, el usuario y la contraseña para poder acceder a la base de datos:
1 2 3 4 5 6 |
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=<nombre base de datos> DB_USERNAME=<usuario base de datos> DB_PASSWORD=<contraseña base de datos> |
Como queremos poder utilizar Eloquent ORM tendremos que descomentar estas dos líneas del archivo bootstrap/app.php :
1 2 3 |
$app->withFacades(); $app->withEloquent(); |
Con esto ya podremos utilizar Eloquent ORM en nuestro proyecto.
Ahora vamos a crear una migración para crear la tabla donde se guardarán los links en la base de datos:
1 |
php artisan make:migration CreateLinksTable |
Se creará un archivo en database/migrations , lo abrimos y le ponemos este código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateLinksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('links', function (Blueprint $table) { $table->increments('id'); $table->string('url'); $table->text('description'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('links'); } } |
Si quieres más información sobre las migraciones entra en este enlace.
Ejecutamos la migración:
1 |
php artisan migrate |
Una vez finalice este comando, ya tendremos la tabla en nuestra base de datos. Ahora vamos a crear el modelo asociado a la tabla, tienes que ir a la carpeta app y crear un archivo llamado Link.php y añadirle este código:
1 2 3 4 5 6 7 8 9 10 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Link extends Model { protected $fillable = ['url', 'description']; } |
Ahora vamos a crear el controlador, vamos a app/Http/Controllers y creamos un archivo llamado LinksController.php :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<?php namespace App\Http\Controllers; use App\Link; use Illuminate\Http\Request; class LinksController extends Controller { public function __construct() { } public function index() { return response()->json(Link::all()); } public function store(Request $request) { $this->validate($request, [ 'url' => 'required|url|active_url|unique:links', 'description' => 'max:500' ]); $link = Link::create([ 'url' => $request->input('url'), 'description' => $request->input('description') ]); return response()->json(['msg' => 'Link created!', 'newLink' => $link]); } public function destroy($id, Request $request) { $link = Link::findOrFail($id); $link->delete(); return response()->json(['msg' => 'Link deleted!']); } } |
Hay tres métodos: uno para listar (index), otro para crear (store) y el último para eliminar (destroy). Los tres hacen su función y al final retornan un JSON, para después, cuando se haga la petición desde el frontend poder tratar los datos.
Ahora vamos a crear las rutas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
... $app->group(['prefix' => 'api'], function() use ($app) { $app->get('links', [ 'as' => 'links.index', 'uses' => 'LinksController@index' ]); $app->post('links', [ 'as' => 'links.store', 'uses' => 'LinksController@store' ]); $app->delete('links/{id}', [ 'as' => 'links.destroy', 'uses' => 'LinksController@destroy' ]); }); |
Para poder acceder a la API fácilmente y ver si funciona correctamente, yo utilizo una aplicación de Chrome llamada Advanced REST client. Con esta aplicación puedes hacer diferentes tipos de peticiones (GET, POST, DELETE, etc.) a cualquier API y obtener los resultados de la petición.
En el controlador, si te fijas estamos utilizando una función de Eloquent ORM llamada <Modelo>::findOrFail($id); , que lo que hace es ver si existe el registro con ese id en la base de datos, si existe lo retorna y si no existe nos muestra un template con un error ModelNotFoundException. Pero como nosotros estamos haciendo peticiones desde el frontend, lo que queremos es un objeto JSON para poder obtener y mostrar el error desde ahí. Por eso vamos a modificar la función render del archivo app/Exceptions/Handler.php :
1 2 3 4 5 6 7 8 9 10 11 12 |
... public function render($request, Exception $e) { if ($e instanceof ModelNotFoundException) { return response()->json([ 'error' => 'No records found!', ], 404); } ... } } |
Lo que se hace aquí, es capturar el error ModelNotFoundException y en vez de renderizar el template, se retorna que ha habido un error 404 con un JSON y un mensaje para poder tratarlo desde el frontend.
Y hasta aquí la creación de la API, en la siguiente entrada veremos como consumirla y utilizarla con Vue.js 2.