
Laravel REST API Part 2: Create Migrations, Models, and Factories
Published on Nov 19, 2024
In this tutorial, we’ll walk through creating models, migrations, for our Laravel API. and we will populate some data as well with factories and seeders to be able to test our api's.
Setting Up Models and Migrations
Database Design Overview
- users: We have already predefined migration file with users table, so we will not worry about it.
- categories: We could have the following columns [id, name].
- products: We might have [id, name, price, stock, category_id]
- orders: With the following columns [id, user_id, total_price, status]
- order_product: A pivot table for the many-to-many relationship between orders and products, with fields [id, order_id, product_id, quantity]
Creating Models and Migrations
Run the following commands to create the models and migrations:
php artisan make:model Category -m php artisan make:model Product -m php artisan make:model Order -m
The -m flag generates migration files automatically.
Category Migration
In the create_categories_table.php migration file:
Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); });
Product Migration
In the create_products_table.php migration file:
Schema::create('products', function (Blueprint $table) { $table->id(); $table->string('name'); $table->decimal('price', 10, 2); $table->integer('stock')->default(0); $table->foreignId('category_id')->constrained()->cascadeOnDelete(); $table->timestamps(); });
Order Migration
In the create_orders_table.php migration file:
Schema::create('orders', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constraned()->cascadeOnDelete(); $table->decimal('total_price', 10, 2)->default(0); $table->tinyInteger('status')->default(0); $table->timestamps(); }); Schema::create('order_product', function (Blueprint $table) { $table->id(); $table->foreignId('product_id')->constraned()->cascadeOnDelete(); $table->foreignId('order_id')->constraned()->cascadeOnDelete(); $table->integer('quantity')->default(1); $table->timestamps(); });
Alongside with the orders migration we added order_product in same file because they are related and we will not have a model for it. So no need to create a separate file for it
And don't forget to add this line in down function:
Schema::dropIfExists('order_product');
Defining Model Relationships
Category Model
In Category.php:
use Illuminate\Database\Eloquent\Relations\HasMany; protected $fillable = ["name"]; public function products(): HasMany { return $this->hasMany(Product::class); }
Product Model
In Product.php
use Illuminate\Database\Eloquent\Relations\BelongsTo; protected $fillable = [ 'name', 'price', 'stock', 'category_id', ]; public function category(): BelongsTo { return $this->belongsTo(Category::class); }
Order Model
in Order.php
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; protected $fillable = [ 'user_id', 'total_price', 'status', ]; public function user(): BelongsTo { return $this->belongsTo(User::class); } public function products(): BelongsToMany { return $this->belongsToMany(Product::class); }
Creating Factories
Category Factory
Generate the factory:
php artisan make:factory CategoryFactory
In CategoryFactory.php in definition function:
return [ 'name' => fake()->word(), ];
Product Factory
Generate the factory:
php artisan make:factory ProductFactory
In ProductFactory.php
return [ 'name' => fake()->words(4, true), 'price' => fake()->numberBetween(10, 500), 'stock' => fake()->numberBetween(0, 50) ];
Update Models
We need also to update our models to be able to use those factories:
In Category.php model we need to add HasFactory trait
use Illuminate\Database\Eloquent\Factories\HasFactory; /** @use HasFactory<\Database\Factories\CategoryFactory> */ use HasFactory;
You need to do the same with Product model as well
DatabaseSeeder
In the DatabaseSeeder.php we need to seed our data using factories we just added, you might create a separate seeder file for each model, but our setup is very basic, so no need for separate files.
Category::factory()->count(5)->hasProducts(50)->create();
With this simple line we will be able to create 5 categories each category should have 50 product, which will be good enough to be able to test our api's.
Run Migrations and Seeder
We will use the following command to add migrations table and seeder data to our database
php artisan migrate --seed
We should be done, you can verify by checking the data via SQLite viewer extension if you installed it.
Conclusion
We are done with our basic setup in the previous article and in this article we added our tables and data we are going to need.
In the next article we will begin to add our api's and we will start with authentication.