Laravel Ecommerce Api yazımı
Bu serimizde laravel api kullarak back-end yazalım.
https://github.com/abdullahsuhaisk/BasicEcommerceApiWithLaravel
Setting Up Enviroment
Eğer php server bilgisayarınızda yok ise xamp benzeri bir server kurulumu yapınız.
Composer kurulumunu yapınız.
Ardından composer ile global laravel kurulumunu yapınız.
Proje dizinine gelip
laravel new Eapi komutu ile laravel projemizi oluşturalım
https://github.com/abdullahsuhaisk/BasicEcommerceApiWithLaravel
Projenin git Linki
CREATE API RESOURCE CONTROLLER
php artisan help make:model
Komutu ile yardım alabiliriz.
php artisan make:model Model/Product -a
Komutu ile Model klasörüme Product model dosyamı oluşturacağım. Aynı zamanda migrations ve resource controllerimi oluşturacak. Yani bana ne lazımsa tek bir komut ile oluşturuyorum.
Projemde product, reviews modelleri olacak geniş ölçekliden ziyade best practise leri uyguylayacağımız mini bir proje olacak.
php artisan make:model Model/Review-a
Komutu ile reviews lerimi oluşturuyorum.
Komutu ile route lerimi listeliyorum. Bir api için gerekli olan bütün methodlar tanımlandı(post,get vs)
Eğer create ve editmethodlarını iptal etmek istersem. Kodum şu şekilde olmalıydı;
Kodumu bu şekilde değiştiriyorum. Değiştirdiğim için controller deki create ve edit methodlarını kaldırmam gerekiyor. Kaldırmasamda sorun olmaz.
| | GET|HEAD | api/products | products.index Bütün productlarımı görmem için
| | POST | api/products | products.store Yeni bir product ekleyebilmem için
| | GET|HEAD | api/products/{product} | products.show Yalnızca bir product ı görebilmem için
| | PUT|PATCH | api/products/{product} | products.update |
| | DELETE | api/products/{product} | products.destroy |
Reviews için route oluşturmam gerekiyor. Ama burada route parametremin şu şekilde olmasını istiyorum /products/11/reviews
MİGRATİON
Migration php kodları vasıtası ile database de tablo oluşturmaya yarar.
Şimdi products migrations dosyamızı oluşturalım. Burada tablolarda tutmak için bize neler lazım diye düşünüyoruz.
Bu kod satırları ile şunları demek istiyorum.
review tablomda product id yi tutyorum. Çünkü her bir product ın reviewları olur ve bir productın birden fazla review ı olabilir.
İkinci satırda ise eğer bir product silinir ise ona ait olan bütün review ları sil demek istiyorum.
Şimdi sırada veritabanı bağlantıları yapmam var.
Xamp yada başka php server ımı açıyorum.
Yeni bir veritabanı oluşturuyorum.
.env
Ayarlarımıda yaptıktan sonra migrate komutu ile migrations larımı app ime entegre edeceğim.
php artisan migrate
Hata ile karşılaşırsanız çözüm
Tablolarımız oluştu.
DATABASE SEEDİNG WİTH FAKER LİBRARY
Bu bölümde faktory kullanarak fake datalar ile db mizi dolduracağız.
Buradaki PRODUCT->İD İLE product modelin içinden bir tane seçme işlemi yapıyoruz.
Sırada database/seeds klasörüne gelip run methodunda çalışacak methodları belirlemede.
php artisan db:seed
Komutu ile seeding işleminin başlaması gerekiyor
Verilerim eklenmiş.
CREATİNG RELATİONSHİP
Bir product ın birden fazla reviews ı olur.
Bu ilişkinin anahtar kelimesi hasMany() dir.
Tam tersi bir tane review ın bir tane Product ı olabilir. Yani bir review bir ürün için yazılmıştır.
Bu ilişkinin anahtar kelimeside belongsTo() dur.
php artisan tinker
Komutu ile kontrol işlemi yapacağız.
Gördüğünüz gibi komutlarım yardımıyla modelimde instance alabiliyorum. Ve model kodlarım sorunsuz çalışıyor.
CREATE APİ RESOURCE \ TRANSFORMER
php artisan make : resource Product/ProductCollection
Transformer' ın ne işe yaradığına değinmeden önce,
ProductControllerimize geri dönelim. index methodumun bütün productları dönecek şekilde düzenleyelim.
php artisan serve
Komutları ile app derleyelim. Önceki başlıklarda route oluşturmuştyk.
http://127.0.0.1:8000/api/products
giriş yaptığımızda karşımıza çıkan ekran ;
Sonuç olarak bütün productlarımın bütün bilgileri dönüyor. İşte transformers burada devreye girecek. Mesela ben api da id ve time bilgilerini vermek istemiyorum.
php artisan make : resource Product/ProductResource
Komutu ile bir tane daha resource oluşturacağım.
Artık db den gelen bilgiler yazılanlar şeklinde çıkacak. Şimdi ProductController ' e gidiyorum.
show methodunda productresource yi çağıracağım.
Transformer kullanarak çağırdım.
TRANSFORMİNG PRODUCTS
Artık product işlemi yaparken direk product modelimizi dönmüyoruz. Transformer olarak yazdığımız productResource yi kullanıyoruz. Burada review leri koymadık. Şimdi review ları koyalım. Ama link şeklinde yapalım. Projemizdeki route leri göreceğiz kod
php artisan route:list
Kullanacağım route buldum şimdi. ProductResource ma yazıyorum.
rating mantığını çözelim.
Peki product ımızın hiç review ı yok ise ?
Stok için ise
Şimdi total price yapalım.
ProductCollection nun son hali.
PRODUCTCOLLECTİON TRANSFORMİNG
Api products a istek yaptığımızda yine bütün productların bütün bilgileri geliyordu. Bu seferde bütün productların gelmesini fakat bazı bilgilerin gelmesini istiyorum.
CONFİGURE PASSPORT PACKPAGE
Apı mıza bağlanırken kullanıcıların Authentice olup olmadıklarını kontorol etmek için kullanıyoruz.
composer require laravel/passport
komutu ile appi 'a passport kütüphanesini yüklüyoruz. Ardından
php artisan migrate
komutu ile passport ile gelen tabloları entegre migrate ediyoruz.
php artisan passport
komutu ile initilize işlemlerini gerçekleştiriyoruz. oauth_clients tablosuna iki yeni kayıt geldi. Client_ıd ve client_secret lerimiz burda.
Ardında user.php dosyamıza
Son olarak config/Api da
Şimdi postMan 'e geçiş yapacağız. Ama öncesinde yeni kullanıcı oluşturmamız gerekiyor.
Daha önce hiç kullanıcı oluşturmamıştık.
php artisan make:auth
Postman ile istek atacağız;
CPost isreği attığımızda cevap olarak;
access_token geliyor bu bizim giriş yaptığımızı haber veriyor.
Şimdi route 'ye tekrar bakalım :
Tekrar istek yaptığımızda üye bilgilerimizi veriyor.
CREATE NEW PRODUCT
Yeni bir ürün ekleneceği zaman ürün eklemek isteyen consumer 'in giriş olmasını istiyoruz.
php artisan route:list
Komutu ile route lerimi listeliyorum. Altını çizmiş olduğum işlerde autharization yani kullanıcının giriş yapmış olmasını beklemekteyim.
ProductController ıma gidiyorum ve contructor() yani kurucu methodumu oluşturuyorum. ProductControllerım ilk çalıştığında bütün methodlarımdan önce bu method çalışacak.
ProductControllerımın store methodunu şu şekilde güncelledim.
Şimdi postman aracılığı ile Auth olmadan post isteği atacağız ve authentica olarak post işlemi yapıp farkını göreceğiz.
Yeni bir request sınıfı oluşturalım
php artisan make:request ProductRequest
komutu ile yeni bir request sınıfı oluşturuyorum.
app/http/request dizininin altında bulabileceğim bu oluşturduğum classın authorize() methodunu true yapacağım.Public function rules methodunada validate işlemlerini yapacağüım.
ProductRequest methodu:
PostMan ile post işlemi yaptığımda tekrardan
The name field is required hatası alacam
Peki yeni product kaydetme işlemini nasıl yapacağız ?
store methodumda Yeni bir product nesnesi oluşturacağız ve requestimden gelen attiributes leri oluşturduğum prodoct nesnesinin özelliklerine atayacaz.
Ekleme işlemi başarılı oldu.
PRODUCT GÜNCELLEME VE DETAY
Güncelleme işlemi yapabilmem için öncelikle route nu bulmam gerekiyor.
php artisan route : list
komutu ile productlarıma bakabiliyorum.
api/products/{product}route adresinden güncelleme işlemlerimi yapacağım.
| | PUT|PATCH | api/products/{product} | products.update | App\Http\Controllers\ProductController@update | api,auth:api |
153 ıd ye sahip productımı güncelleyeceğim.
ProductControllere gidiyorum.
Doludracağım değişkenler : name,details,stock,price,discount
İşlemlerimi gerçekleştirdiğimde decription alanı güncellenmiyor.
Dikkat ederseniz fillable olarak description almadık. Onun yerine detail aldık. Yani yapmamız gerek işlemler var. Request den gelen dizinin içinde ki description yerine detail atayacağız. Ardından descriptionu sileceğiz.
Şimdi başarılı oldu ve gücellenmiş productımızı döndü.
PRODUCT SİLME
Destroy methodum şu şekilde. Reviews migrate dosyamdaki şu kod sayesinde product silindiğinde o producta ait reviewslerde siliniyor.
Post man ile delete request gönderdiğimde silinme işlemi başarılı olur.
https://github.com/abdullahsuhaisk/BasicEcommerceApiWithLaravel
Setting Up Enviroment
Eğer php server bilgisayarınızda yok ise xamp benzeri bir server kurulumu yapınız.
Composer kurulumunu yapınız.
Ardından composer ile global laravel kurulumunu yapınız.
Proje dizinine gelip
laravel new Eapi komutu ile laravel projemizi oluşturalım
https://github.com/abdullahsuhaisk/BasicEcommerceApiWithLaravel
Projenin git Linki
CREATE API RESOURCE CONTROLLER
php artisan help make:model
Komutu ile yardım alabiliriz.
php artisan make:model Model/Product -a
Komutu ile Model klasörüme Product model dosyamı oluşturacağım. Aynı zamanda migrations ve resource controllerimi oluşturacak. Yani bana ne lazımsa tek bir komut ile oluşturuyorum.
Projemde product, reviews modelleri olacak geniş ölçekliden ziyade best practise leri uyguylayacağımız mini bir proje olacak.
php artisan make:model Model/Review-a
Komutu ile reviews lerimi oluşturuyorum.
Komutlarımı yazdıktan sonra Modellerim,Controllerim vs oluştu. Şimdi route oluşturuyoruz
Link alanına products girildiğinde productContoller imi gidecek.
php artisan route:list
Eğer create ve editmethodlarını iptal etmek istersem. Kodum şu şekilde olmalıydı;
Route::apiResource('/products','ProductController');
Kodumu bu şekilde değiştiriyorum. Değiştirdiğim için controller deki create ve edit methodlarını kaldırmam gerekiyor. Kaldırmasamda sorun olmaz.
| | GET|HEAD | api/products | products.index Bütün productlarımı görmem için
| | POST | api/products | products.store Yeni bir product ekleyebilmem için
| | GET|HEAD | api/products/{product} | products.show Yalnızca bir product ı görebilmem için
| | PUT|PATCH | api/products/{product} | products.update |
| | DELETE | api/products/{product} | products.destroy |
Reviews için route oluşturmam gerekiyor. Ama burada route parametremin şu şekilde olmasını istiyorum /products/11/reviews
MİGRATİON
Migration php kodları vasıtası ile database de tablo oluşturmaya yarar.
Şimdi products migrations dosyamızı oluşturalım. Burada tablolarda tutmak için bize neler lazım diye düşünüyoruz.
$table->integer('product_id')->unsigned()->index();
$table->foreign('product_id')->references(id)->on('products')->onDelete('cascade');
Bu kod satırları ile şunları demek istiyorum.
review tablomda product id yi tutyorum. Çünkü her bir product ın reviewları olur ve bir productın birden fazla review ı olabilir.
İkinci satırda ise eğer bir product silinir ise ona ait olan bütün review ları sil demek istiyorum.
Şimdi sırada veritabanı bağlantıları yapmam var.
Xamp yada başka php server ımı açıyorum.
Yeni bir veritabanı oluşturuyorum.
.env
Ayarlarımıda yaptıktan sonra migrate komutu ile migrations larımı app ime entegre edeceğim.
php artisan migrate
Hata ile karşılaşırsanız çözüm
Tablolarımız oluştu.
DATABASE SEEDİNG WİTH FAKER LİBRARY
Bu bölümde faktory kullanarak fake datalar ile db mizi dolduracağız.
Buradaki PRODUCT->İD İLE product modelin içinden bir tane seçme işlemi yapıyoruz.
Sırada database/seeds klasörüne gelip run methodunda çalışacak methodları belirlemede.
review seed de hata yapmışız hataların düzeltilmiş hali
php artisan db:seed
Komutu ile seeding işleminin başlaması gerekiyor
Verilerim eklenmiş.
CREATİNG RELATİONSHİP
Bir product ın birden fazla reviews ı olur.
Bu ilişkinin anahtar kelimesi hasMany() dir.
Tam tersi bir tane review ın bir tane Product ı olabilir. Yani bir review bir ürün için yazılmıştır.
Bu ilişkinin anahtar kelimeside belongsTo() dur.
php artisan tinker
Komutu ile kontrol işlemi yapacağız.
CREATE APİ RESOURCE \ TRANSFORMER
php artisan make : resource Product/ProductCollection
Transformer' ın ne işe yaradığına değinmeden önce,
ProductControllerimize geri dönelim. index methodumun bütün productları dönecek şekilde düzenleyelim.
public function index()
{
return Product::all();
}
Komutları ile app derleyelim. Önceki başlıklarda route oluşturmuştyk.
http://127.0.0.1:8000/api/products
giriş yaptığımızda karşımıza çıkan ekran ;
Sonuç olarak bütün productlarımın bütün bilgileri dönüyor. İşte transformers burada devreye girecek. Mesela ben api da id ve time bilgilerini vermek istemiyorum.
php artisan make : resource Product/ProductResource
Komutu ile bir tane daha resource oluşturacağım.
Artık db den gelen bilgiler yazılanlar şeklinde çıkacak. Şimdi ProductController ' e gidiyorum.
show methodunda productresource yi çağıracağım.
Transformer kullanarak çağırdım.
TRANSFORMİNG PRODUCTS
Artık product işlemi yaparken direk product modelimizi dönmüyoruz. Transformer olarak yazdığımız productResource yi kullanıyoruz. Burada review leri koymadık. Şimdi review ları koyalım. Ama link şeklinde yapalım. Projemizdeki route leri göreceğiz kod
php artisan route:list
Kullanacağım route buldum şimdi. ProductResource ma yazıyorum.
rating mantığını çözelim.
'raiting'=>$this->reviews()->sum('star'),tüm starların toplamını gösteriyor.
'raiting'=>$this->reviews->sum('star')/$this->reviews->count(),ortalamasını aldım.
Peki product ımızın hiç review ı yok ise ?
'raiting'=>$this->reviews->count() > 0 ? round($this->reviews->sum('star')/$this->reviews->count(),2): 'no raiting yet',Çözümünü uyguladım.
Stok için ise
'stock'=>$this->stock == 0 ? 'Out of stock' : $this->stock,benzer mantık uygulanır.
Şimdi total price yapalım.
ProductCollection nun son hali.
PRODUCTCOLLECTİON TRANSFORMİNG
Api products a istek yaptığımızda yine bütün productların bütün bilgileri geliyordu. Bu seferde bütün productların gelmesini fakat bazı bilgilerin gelmesini istiyorum.
ProductConroller de de index methodumu
public function index(){ //return Product::all(); return ProductCollection::collection(Product::all());}
Yeni oluşturduğum resource sınıfından türetilmiş ProducCollection dönmesini sağlıyorum.
CONFİGURE PASSPORT PACKPAGE
Apı mıza bağlanırken kullanıcıların Authentice olup olmadıklarını kontorol etmek için kullanıyoruz.
composer require laravel/passport
komutu ile appi 'a passport kütüphanesini yüklüyoruz. Ardından
php artisan migrate
komutu ile passport ile gelen tabloları entegre migrate ediyoruz.
php artisan passport
komutu ile initilize işlemlerini gerçekleştiriyoruz. oauth_clients tablosuna iki yeni kayıt geldi. Client_ıd ve client_secret lerimiz burda.
Ardında user.php dosyamıza
class User extends Authenticatable{ use HasApiTokens,Notifiable; protected $fillable = [ 'name', 'email', 'password', ]; protected $hidden = [ 'password', 'remember_token', ];}
use HasApiTokensSatırını ekliyoruz. yani tokens kullanacağını user e belirttik.
<?php namespace App\Providers; use Illuminate\Support\Facades\Gate;use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;use Laravel\Passport\Passport; class AuthServiceProvider extends ServiceProvider{ protected $policies = [ 'App\Model' => 'App\Policies\ModelPolicy', ]; public function boot() { $this->registerPolicies(); Passport::routes(); }}authService providers a eklemelerini yapalım.
Son olarak config/Api da
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', ],],değişiklikleri yaptığımızda tamamlanmış olur.
Şimdi postMan 'e geçiş yapacağız. Ama öncesinde yeni kullanıcı oluşturmamız gerekiyor.
Daha önce hiç kullanıcı oluşturmamıştık.
php artisan make:auth
Komutu ile laravel in kendinden gelen Kullanıcı işlemlerini aktif edelim. ardından sitemizi local de çalıştırıp üye olalım.
Buradan kayıt oluyoruz.Postman ile istek atacağız;
Şimdi route 'ye tekrar bakalım :
Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user();});api/user e get isteği yapalım. api routede kendiliğinden tanımlanmış bir routeydi bu. Üyenin giriş yapıp yapmadığını kullanan middleware kullanıyor.
Tekrar istek yaptığımızda üye bilgilerimizi veriyor.
CREATE NEW PRODUCT
Yeni bir ürün ekleneceği zaman ürün eklemek isteyen consumer 'in giriş olmasını istiyoruz.
php artisan route:list
Komutu ile route lerimi listeliyorum. Altını çizmiş olduğum işlerde autharization yani kullanıcının giriş yapmış olmasını beklemekteyim.
ProductController ıma gidiyorum ve contructor() yani kurucu methodumu oluşturuyorum. ProductControllerım ilk çalıştığında bütün methodlarımdan önce bu method çalışacak.
class ProductController extends Controller{ public function __construct() { $this->middleware('auth:api')->except('index','show'); // ->except We don't need to index and show method with authenticate }except ile index ve show methodlarımda middleware kullanmayacağımı belirtiyorum.
ProductControllerımın store methodunu şu şekilde güncelledim.
public function store(Request $request){ return 'Product ekleme işlemi';}
Şimdi postman aracılığı ile Auth olmadan post isteği atacağız ve authentica olarak post işlemi yapıp farkını göreceğiz.
Yeni bir request sınıfı oluşturalım
php artisan make:request ProductRequest
komutu ile yeni bir request sınıfı oluşturuyorum.
app/http/request dizininin altında bulabileceğim bu oluşturduğum classın authorize() methodunu true yapacağım.Public function rules methodunada validate işlemlerini yapacağüım.
ProductRequest methodu:
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class ProductRequest extends FormRequest{ public function authorize() { return true; } public function rules() { return [ 'name' => 'required|max:255|unique:products', 'description' => 'required', 'price' => 'required|max:10', 'stock' => 'required|max:6', 'discount' => 'required|max:2', ]; }}Şimdi controllere tekrar dönüş yapıp
public function store(ProductRequest $request){ }Store methoduma parametre olarak request yerine ProductRequest gelmesini sağladım.
PostMan ile post işlemi yaptığımda tekrardan
The name field is required hatası alacam
Request yani gelen istekte aşağıdaki gibi alanlar dolu olmalıdır.
Peki yeni product kaydetme işlemini nasıl yapacağız ?
store methodumda Yeni bir product nesnesi oluşturacağız ve requestimden gelen attiributes leri oluşturduğum prodoct nesnesinin özelliklerine atayacaz.
Ekleme işlemi başarılı oldu.
PRODUCT GÜNCELLEME VE DETAY
Güncelleme işlemi yapabilmem için öncelikle route nu bulmam gerekiyor.
php artisan route : list
komutu ile productlarıma bakabiliyorum.
api/products/{product}route adresinden güncelleme işlemlerimi yapacağım.
| | PUT|PATCH | api/products/{product} | products.update | App\Http\Controllers\ProductController@update | api,auth:api |
153 ıd ye sahip productımı güncelleyeceğim.
ProductControllere gidiyorum.
public function update(Request $request, Product $product){ return $request->all();}update methodumu güncelledim.
public function update(Request $request, Product $product){ return $product;}Bu sefer gelen productımı döndürdüm sonuç product döndü. Şimdi controller methodumda parametre olarak gelen product ı işleyip update yapacağım.
Bunları yapmak için öncelikle product model ime gidip fillable dizisini doldurmam gerek.public function update(Request $request, Product $product){ $product->update($request->all()); return $product;}
Doludracağım değişkenler : name,details,stock,price,discount
protected $fillable = ['name','detail','stock','price','discount'];
İşlemlerimi gerçekleştirdiğimde decription alanı güncellenmiyor.
Dikkat ederseniz fillable olarak description almadık. Onun yerine detail aldık. Yani yapmamız gerek işlemler var. Request den gelen dizinin içinde ki description yerine detail atayacağız. Ardından descriptionu sileceğiz.
public function update(Request $request, Product $product){ $request['detail'] = $request->description; unset($request['description']); $product->update($request->all()); return $product;}
Şimdi başarılı oldu ve gücellenmiş productımızı döndü.
PRODUCT SİLME
public function destroy(Product $product){ $product->delete(); return response(null,Response::HTTP_NO_CONTENT);}
Destroy methodum şu şekilde. Reviews migrate dosyamdaki şu kod sayesinde product silindiğinde o producta ait reviewslerde siliniyor.
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');Bu kod sayesinde.
Post man ile delete request gönderdiğimde silinme işlemi başarılı olur.
Yorumlar
Yorum Gönder