DDD: Laravel API’nizi Veritabanınızdan Ayırmak
Ayırma
Java frameworklerinde, veritabanınızdan yönlendirmelerinizi(routes) ve istek(request) nesnelerini ayırmak için uzun bir yöntem vardır.
Decoupling terimini anlamak için ilk etapta kuplajın ne anlama geldiğini bilmeniz gerekir .
Genel olarak birleştirme: diyelim ki farklı işlevlere sahip iki hizmetin çalışması için birbirine ihtiyaç duyduğunda, bu iki hizmetin birbirine (“coupled”)“birleştirilmiş” olmasıdır. Elbette bunlar projeden projeye değişir, burada örnek olarak verdiğim şey “typcial” bir bağlantı türüydü.
Decoupling ile diyelim ki API ve yönlendirmeleri(routes) aynı tutarken veritabanı yapınızı bu şekilde değiştirebilirsiniz.
Bunun artılarına ve eksilerine girmeyeceğiz, ancak sadece Etki Alanına Dayalı bir yaklaşıma yardımcı olduğunu belirtiyoruz.
OpenAPI ile Nesneleri Tanımlamak
property/value çiftleri topluluğu, bir nesnedir. Bir özellik nesnesi tanımlamak için properties
anahtar kelimesi kullanılır.
OpenAPI’de nesneler genellikle genel components/schemas
bölümde tanımlanır.
Burada OpenAPI nesnelerinin PHP nesneleri ile mantıksal olarak nasıl gruplanacağını göstereceğiz. Bu işlem kodlarımızı anlaşılır ve kolayca düzeltilebilir hale getirir.
<?phpnamespace App\Forms;use OpenApi\Generator;/**
* @OA\Schema(
* schema="User",
* required={
* "name",
* "email"
* }
* )
*/
class UserForm { /** @OA\Property() */
public string $name; /** @OA\Property() */
public string $email;
}
Bu kısımda iki (UserForm
)yol altında bir sınıf oluşturduk (app/Forms
).
Sınıfımız içinde type (UserForm
)tanımladık ve alanların ve gerekli olduğunu belirttik.(schema User name email
)
OpenAPI nesnesinin PHP nesnesi ile aynı şekilde çağrılmasına bile gerek olmadığına dikkat edin.
Sınıfımız içinde tanımladığımız özelliklerimiz için hem string hem de string tipinde olmasını ( UserForm
) belirtmiş bulunmaktayız. ($name$email
)
Bir yönlendirme(route) Json olarak tek bir nesne döndürürse, @OA\JsonContent(ref="#/components/schemas/User")
. ref
, @OA\Items
, @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/User"))
.
<?php
/**
* @OA\Swagger(
* schemes={"https"},
* host="mywebsite.com",
* basePath="",
* @OA\Info(
* version="1.0.0",
* title="My Website",
* description="Put Markdown Here [a Link](https://www.google.com)",
* @OA\Contact(
* email="my@email"
* ),
* ),
* )
*/
class UserController extends Controller
{
/**
* @OA\Get(path="/api/users", description="Get all users", operationId="",
* @OA\Response(response=200, description="OK",
* @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/User"))
* ),
* @OA\Response(response=401, description="Unauthorized"),
* @OA\Response(response=404, description="Not found")
* )
*/
public function index(Request $request)
{
return User::all();
}
}
Şu an itibariyle, bir önceki makaleye kıyasla, tür JsonContent
ve işlevdeki return
ifadedeki uyumsuzluk index
giderildi. JsonContent(type="string")
Doğru dönüş türüne dönüştürüldü , JsonContent(type="array")
.
Bu notu nereye koyuyorsun?
Laravel topluluğu genellikle OpenAPI açıklamalarını modellere koyar. Genellikle DTO’lara OpenAPI ek açıklamaları koyan Java topluluğunun ve onu başka bir yere koyan Symfony topluluğunun aksine.
FormRequest
Tüm uygulama esnekliğini korumak için onu yerleştirmeyi tercih ediyoruz . Örneğin, yalnızca özelliği olan bir modeliniz olduğunu söyleyin . Her farklı izin türü için, yani ve , bu farklı izinleri ve rolleri sürdürebilmek ve işleyebilmek için her seferinde tablonuzda daha fazla genişlemeniz gerekir. Onları içeri alarak, karşılaşabileceğimiz her farklı senaryo için tabloyu genişletmeye devam etmemize gerek yok , bunun yerine izinleri ayrı bir tabloyla atamak gibi daha karmaşık mantıkla uğraşıyoruz. Bu şekilde API'niz, her bir tablo için bir rotaya kıyasla daha zengin içerik ve ilişkiler ortaya çıkarabilir.Useris_adminis_adminis_super_adminis_team_adminUsersFormRequestUsersFormRequest
Yeni oluşturulan UserForm
sınıfımızı daha da genişletmek için yerleşik Laravels ile genişletiyoruz FormRequest
.
...
Illuminate\Foundation\Http\FormRequest'i kullanın;/**
* @OA \Schema(
* schema="Kullanıcı",
* gerekli={
* "ad",
* "e-posta"
* }
* )
*/
class UserForm FormRequest'i genişletir { /** @OA \Property() */
public string $name; /** @OA \Property() */
genel dize $email;
}
Form istekleri, esasen kendi doğrulama ve yetkilendirme mantığını kapsayan özel istek sınıflarıdır. Uç noktamıza gelen isteği doğrulamak için Laravels’i kullanarak FormRequest
, onu denetleyiciden soyutlarız, bu da isteği denetleyicinin yönteminde doğrulamamız gerekmeyecek şekilde yapar. Bu, daha sonra, soyutlandıkları için doğrulama kurallarını yeniden kullanma yeteneğini açar.
Laravels’i genişleten her sınıfın FormRequest
iki metoda erişimi vardır.
authorize()
rules()
Yöntem authorize
, şu anda kimliği doğrulanmış kullanıcının istek tarafından temsil edilen eylemleri gerçekleştirmesine izin verilip verilmediğini veya yetkilendirildiğini belirlemekten sorumlu olandır ve bu, bir boolean
değer döndürür. Yöntem rules
, isteğin verilerine uygulanması gereken doğrulama kurallarını döndürür.
...
Illuminate\Foundation\Http\FormRequest'i kullanın;/**
* @OA \Schema(
* schema="Kullanıcı",
* gerekli={
* "ad",
* "e-posta"
* }
* )
*/
class UserForm FormRequest'i genişletir { /** @OA \Property() */
public string $name; /** @OA \Property() */
genel dize $email; public function Authorize()
{
return true;
} public function Rules()
{
return [
'ad' => 'gerekli|dize',
'eposta' => 'gerekli|dize',
];
}
}
En önemli şey, rules()
OA ek açıklamalarınızla eşleşmesidir, çünkü bu, örneğin bir parametrenin bir tür olarak belirtildiği ancak aslında başka bir tür olduğu kararsız ve tehlikeli belgelerden kaçınmaya yardımcı olur. Kısacası, beklediğimiz verilerin aslında rules
.
Daha sonraki aşamalarda bu iki fonksiyon hakkında potansiyel olarak daha fazla bilgi olacaktır FormRequest
, ancak şimdilik bilmeniz gereken tek şey bu iki fonksiyonun Laravels'in bir parçası olduğudur FormRequest
.
Şimdi bu çözüme kavuştuktan sonra , artık Laravels’i genişleten sınıfımızı UserController
kullanmak istediğimiz için , kendimize geçiyoruz .UserFormFormRequest
UserController
Sınıfta şimdi aşağıdaki işlevi ekledik :
...
Form olarak App\Forms\UserForm'u kullanın;class UserController, Controller'ı genişletir
{
... /**
* @OA \Post(path="/api/create", description="Kullanıcı oluştur", operasyonId="",
* @OA \RequestBody( @OA \JsonContent(ref="#/components/schemas/ Kullanıcı"), gerekli=true,description="Bir kullanıcının oluşturulması"),
* @OA \Response(response=201, description="Oluşturuldu",
* @OA \JsonContent(ref="#/components/schemas/) User")
* ),
* @OA \Response(response=401, description="Yetkisiz"),
* @OA \Response(response=422, description="İşlenemeyen Varlık / Doğrulama Başarısız")
* )
*/
public function store(Form $request)
{
return $request->save();
}
}
Bu store
işlevde daha çok iki "yeni" OpenAPI ek açıklamasını tanıttık ve diğerlerinden bazılarını değiştirdik, biri @OA\Post
bu işlemin türünde olduğunu belirten post
ve diğeri @OA\RequestBody
tipik olarak create
ve işlemlerle birlikte kullanılan , bunlar şunlar update
olabilir : veya . Genellikle oluşturulacak kaynağın temsilini içerir.postputpatchRequestBody
Ve içindeki save()
işlev UserForm
aşağıdaki gibi görünür:
...
Uygulama\Modeller\Kullanıcı'yı kullanın;class UserForm, FormRequest'i genişletir { ... public function save()
{
$user = new User();
$kullanıcı->ad = $bu->ad;
$kullanıcı->e-posta = $bu->e-posta;
$user->save();
return [
'ad' => $kullanıcı->adı,
'e-posta' => $kullanıcı->e-posta
];
}
}
Fonksiyonumuzda save
yeni bir User
örnek oluşturuyoruz ve değerlerimizi bunlara karşılık gelen User
model değerlerine atadık. Ve döndürdüğümüz değerler ek açıklamaya karşılık gelmelidir Swagger
.