현재 개인 휴식 API를 개발 중입니다. 상위 레벨 리소스를 작성하기 위해 게시 할 때 하위 리소스의 코드 종속성 문제가 발생합니다. 이 나머지 API를 REST API - 공동 종속 엔드 포인트 드라이 런 흐름?
/products/[PRODUCT_ID]/categories
/products/[PRODUCT_ID]/media
/products/[PRODUCT_ID]/shippingZones
/products/[PRODUCT_ID]/variants
예를 들어
..I 다음 상위 엔드 포인트가 ..
/products
그리고/제품에 대한 다음과 같은 자식 엔드 포인트의 상대 ..
,/제품에는 'categories', 'media', 'shippingZones', 'variant'와 같은 키에 대해 게시 된 페이로드를 수락 할 수도 있습니다.이러한 키가 설정되면/products 끝 점이 드릴 다운되고/products의 현재 게시 요청에 대한 페이로드 키를 기반으로 하위 리소스가 만들어지고 연결됩니다.
다음은/products에 대한 POST 요청에서 실행되는 코드로, 현재 처리되는 방식을 보여줍니다. 아래에서 한눈에 살펴본 후 문제를 직접 살펴 보겠습니다. 설명하기 전에 문제를보실 수 있을까요?
protected function post()
{
if (!$this->validatePermissions()) {
return;
}
$productsM = new productsModel();
$filesM = new filesModel();
$userId = $this->controller->user['id'];
$productId = $this->getResourceIdByName('products');
$productCategories = $this->controller->payload['productCategories'];
$productMedia = $this->controller->payload['productMedia'];
$productShippingZones = $this->controller->payload['productShippingZones'];
$productVariants = $this->controller->payload['productVariants'];
$existingProduct = ($productId) ? $productsM->getSingle(array('id' => $productId, 'userId' => $userId)) : array();
$product = array_merge($existingProduct, $this->controller->getFilteredPayload(array(
'title',
'description',
'shippingType',
'fileId',
'hasVariants',
'isHidden'
)));
$this->validateParameters(array('title' => $product['title']));
if ($productId && !$existingProduct) {
$this->addResponseError('productId');
}
if ($product['shippingType'] && !in_array($product['shippingType'], array('free', 'flat', 'calculated'))) {
$this->addResponseError('shippingType');
}
if ($product['fileId'] && !$filesM->getNumRows(array('id' => $product['fileId'], 'userId' => $userId))) {
$this->addResponseError('fileId');
}
if ($this->hasResponseErrors()) {
return;
}
$lastCreatedProduct = (!$existingProduct) ? $productsM->getSingle(array('userId' => $userId), array('publicId' => 'DESC')) : array();
$product = $productsM->upsert(array('id' => $productId, 'userId' => $userId), array_merge($product, array(
'publicId' => $lastCreatedProduct['publicId'] + 1,
'userId' => $userId,
'isActive' => 1,
'modified' => time(),
'created' => time()
)), array('publicId'));
// product categories subresource
if (is_array($productCategories)) {
foreach ($productCategories as $index => $productCategory) {
$endpoint = "/products/{$product['id']}/categories/{$productCategory['id']}";
$requestMethod = ($productCategory['isActive'] !== '0') ? endpoint::REQUEST_METHOD_POST : endpoint::REQUEST_METHOD_DELETE;
$productCategory = $this->executeEndpointByPath($endpoint, $requestMethod, $productCategory);
foreach ($productCategory['errors'] as $error) {
$this->addResponseError($error['parameter'], $error['message'], array('productCategories', $index, $error['parameter']));
}
$product['productCategories'][$index] = $productCategory['data'];
}
}
// product media subresource
if (is_array($productMedia)) {
foreach ($productMedia as $index => $media) {
$endpoint = "/products/{$product['id']}/media/{$media['id']}";
$requestMethod = ($media['isActive'] !== '0') ? endpoint::REQUEST_METHOD_POST : endpoint::REQUEST_METHOD_DELETE;
$media = $this->executeEndpointByPath($endpoint, $requestMethod, $media);
foreach ($media['errors'] as $error) {
$this->addResponseError($error['parameter'], $error['message'], array('productMedia', $index, $error['parameter']));
}
$product['productMedia'][$index] = $media['data'];
}
}
// product shipping zones subresource
if (is_array($productShippingZones)) {
foreach ($productShippingZones as $index => $productShippingZone) {
$endpoint = "/products/{$product['id']}/shippingZones/{$productShippingZone['id']}";
$requestMethod = ($productShippingZone['isActive'] !== '0') ? endpoint::REQUEST_METHOD_POST : endpoint::REQUEST_METHOD_DELETE;
$productShippingZone = $this->executeEndpointByPath($endpoint, $requestMethod, $productShippingZone);
foreach ($productShippingZone['errors'] as $error) {
$this->addResponseError($error['parameter'], $error['message'], array('productShippingZones', $index, $error['parameter']));
}
$product['productShippingZones'][$index] = $productShippingZone['data'];
}
}
// product variants subresource
if (is_array($productVariants)) {
foreach ($productVariants as $index => $productVariant) {
$endpoint = "/products/{$product['id']}/variants/{$productVariant['id']}";
$requestMethod = ($productVariant['isActive'] !== '0') ? endpoint::REQUEST_METHOD_POST : endpoint::REQUEST_METHOD_DELETE;
$productVariant = $this->executeEndpointByPath($endpoint, $requestMethod, $productVariant);
foreach ($productVariant['errors'] as $error) {
$this->addResponseError($error['parameter'], $error['message'], array('productVariants', $index, $error['parameter']));
}
$product['productVariants'][$index] = $productVariant['data'];
}
}
return $product;
}
좋아! 이제 문제. 이 흐름을 사용하면 새로 생성 된 제품의/products에 대한 하위 리소스 생성은 제품 데이터베이스 테이블에 삽입 된 새 행에 종속되어 반복 실행 및 하위 리소스 생성에 앞서 제품 ID를 반환합니다. 하위 리소스는 엔드 포인트 uri에 productId를 전달하지 않았습니다.
이것은 코드 종속성의 문제를 야기하고 모든 또는 다른 원칙을 유지합니다.
새 제품이 생성되고 초기/제품 오류 검사가 완료되면 제품은 제품 데이터베이스 테이블에서 새 행을 가져옵니다. 그러나이 작업이 완료된 후 하위 리소스 생성 초기 요청에서 전달 된 데이터로 인해 모든 하위 리소스 생성이 실패하면 초기 요청은 부분적으로 만 성공합니다. 하위 리소스의 오류로 인해 특별히 오류가있는 하위 리소스가 만들어져 처음 생성 된 제품과 연결되는 것을 방지 할 수 있습니다.
그래서 여기에 .. 내 아이디어 몇 가지의
나는 잠재적으로 완전히 삽입/업데이트를 무시하고 있는지 확인하기 위해 처리하는 모든 부모/자식 엔드 포인트 오류를 통해 데이터를 실행하는 드라이 런 방식을 구현하고 싶습니다데이터가 깨끗합니다. 코드 플로우의 가독성을 과도하게 복잡하게하거나 깨뜨리지 않고 엔드 포인트의 플로우에이를 병합하는 방법을 확신 할 수 없습니다.
다른 방법으로 생각해 보거나 실행 흐름을 변경하면 이것이 최선의 접근 방식의 올바른 방향을 지적하게 될 것입니다.
감사합니다.
필자는 PHP MySQLi 클래스 트랜잭션 메소드를 사용하고 스크립트 실행시 ID 종속성을 지원하면서 실행 중 임의의 단계에서 트랜잭션 중에 오류가 발생하면 롤백 지원을 구축했습니다. 한 돌로 2 마리의 새를 풀 었다고 나는 믿는다. –
소프트웨어의 궁극적 인 테스트는 "효과가 있습니까?"입니다. 네가 작동하는 시나리오를 찾은 것처럼 들린다. –