包含对象的对象的 Swagger 注释问题
Swagger annotation problems with objects containing objects
我正在 Symfony 4 项目中休息 api 编写端到端测试。
我用的是php7.4,Swagger注解,nelmio/api-doc-bundle3.6.1,nelmio/cors-bundle1.5.6
这是我的方法控制器代码。
/**
* @Route(path="", name="create", methods={"POST"})
* @ValidationGroups({"create"})
*
* @SWG\Post(
* path="/api/professions",
* tags={"Endpoint: Professions"},
* summary="save a profession",
* @SWG\Parameter(
* name="ProfessionDto",
* required=true,
* in="body",
* @Model(type=ProfessionDto::class)
* ),
* @SWG\Response(
* response=201,
* description="created",
* )
* )
*/
public function add(ProfessionDto $professionDto): CreatedView
{
$professionDto = $this->professionService->insert($professionDto);
return $this->created(['profession' => $professionDto]);
}
ProfessionDto 是定义交换数据的对象。它包含 属性 一些更多的对象,因为我想在返回的数据中有一些结构,而不仅仅是一堆键值对。
在 class ProfessionDto 中,我定义了与其他对象相关的属性,例如:
namespace App\Api\Dto;
use Nelmio\ApiDocBundle\Annotation\Model;
use Swagger\Annotations as SWG;
use Symfony\Component\Serializer\Annotation\Groups as SerializerGroups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @SWG\Definition()
*/
class ProfessionDto
{
use HistoryDto;
/**
* @SWG\Property(description="Id", type="integer")
*
* @SerializerGroups({"view", "update", "collection"})
*/
public ?int $id = null;
/**
* @Assert\NotBlank(groups={"create"})
* @Assert\Type("string")
* @SWG\Property(description="...", type="string")
*/
public string $name;
/**
* @Assert\Type("boolean")
* @SWG\Property(description="ist aktiviert/deaktiviert", type="boolean")
*/
public bool $active;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=ProfessionAreaDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?ProfessionAreaDto $professionArea = null;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=ProfessionalActivityDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?ProfessionalActivityDto $professionalActivity = null;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=IntroductionDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?IntroductionDto $introduction = null;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=PerformanceBehaviourDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?PerformanceBehaviourDto $performanceBehaviour = null;
}
如果我用邮递员或通过我的测试调用 api 并将我的数据作为 json 传递,例如
{
"id":null,
"name":"fancy new data",
"active":true,
"professionArea":{
"id":48,
"name":"Vitae nulla aperiam aut enim.",
"active":true,
"signature":null,
"signatureTypeId":null,
"transition":null,
"infotextCheck":null
},
"professionalActivity":{
"id":null,
"textMResignationTestimonial":null,
...
"changedBy":null
},
"introduction":{
"id":null,
"textMResignationTestimonial":null,
"textMInterimTestimonial":null,
...
"changedOn":null,
"changedBy":null
},
"performanceBehaviour":{
"id":null,
"textMResignationGrade1":null,
"textMInterimGrade1":null,
...
"changedOn":null,
"changedBy":null
},
"createdOn":null,
"createdBy":null,
"changedOn":null,
"changedBy":null
}
我收到错误消息:
TypeError: Typed 属性 App\Api\Dto\ProfessionDto::$professionArea 必须是 App\Api\Dto\ProfessionAreaDto 的实例或 null,使用数组
我做错了什么?我期望太多了吗?对象中的对象不可能吗?
因为这个项目没有使用 friendsofsymfony/rest-bundle 并且 Controller 没有扩展 AbstractFOSRestController。
所以我的问题的解决方案是手动编写一个 Denormalizer class,它将我的数组映射回正确的对象。
我是这样做的:
namespace App\Serializer;
use App\Api\Dto\IntroductionDto;
use App\Api\Dto\PerformanceBehaviourDto;
use App\Api\Dto\ProfessionalActivityDto;
use App\Api\Dto\ProfessionAreaDto;
use App\Api\Dto\ProfessionDto;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
class ProfessionDeNormalizer implements DenormalizerInterface
{
public function denormalize($data, $type, $format = null, array $context = [])
{
$dto = new ProfessionDto();
$areaDto = new ProfessionAreaDto();
$introDto = new IntroductionDto();
$activityDto = new ProfessionalActivityDto();
$performanceDto = new PerformanceBehaviourDto();
foreach($data['professionArea'] as $key => $value) {
$areaDto->$key = $value;
}
unset($data['professionArea']);
foreach($data['introduction'] as $key => $value) {
$introDto->$key = $value;
}
unset($data['introduction']);
foreach($data['professionalActivity'] as $key => $value) {
$areaDto->$key = $value;
}
unset($data['professionalActivity']);
foreach($data['performanceBehaviour'] as $key => $value) {
$areaDto->$key = $value;
}
unset($data['performanceBehaviour']);
foreach($data as $key => $value) {
$dto->$key = $value;
}
$dto->professionArea = $areaDto;
$dto->professionalActivity = $activityDto;
$dto->performanceBehaviour = $performanceDto;
$dto->introduction = $introDto;
return $dto;
}
public function supportsDenormalization($data, $type, $format = null)
{
return ProfessionDto::class === $type;
}
}
我正在 Symfony 4 项目中休息 api 编写端到端测试。
我用的是php7.4,Swagger注解,nelmio/api-doc-bundle3.6.1,nelmio/cors-bundle1.5.6
这是我的方法控制器代码。
/**
* @Route(path="", name="create", methods={"POST"})
* @ValidationGroups({"create"})
*
* @SWG\Post(
* path="/api/professions",
* tags={"Endpoint: Professions"},
* summary="save a profession",
* @SWG\Parameter(
* name="ProfessionDto",
* required=true,
* in="body",
* @Model(type=ProfessionDto::class)
* ),
* @SWG\Response(
* response=201,
* description="created",
* )
* )
*/
public function add(ProfessionDto $professionDto): CreatedView
{
$professionDto = $this->professionService->insert($professionDto);
return $this->created(['profession' => $professionDto]);
}
ProfessionDto 是定义交换数据的对象。它包含 属性 一些更多的对象,因为我想在返回的数据中有一些结构,而不仅仅是一堆键值对。
在 class ProfessionDto 中,我定义了与其他对象相关的属性,例如:
namespace App\Api\Dto;
use Nelmio\ApiDocBundle\Annotation\Model;
use Swagger\Annotations as SWG;
use Symfony\Component\Serializer\Annotation\Groups as SerializerGroups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @SWG\Definition()
*/
class ProfessionDto
{
use HistoryDto;
/**
* @SWG\Property(description="Id", type="integer")
*
* @SerializerGroups({"view", "update", "collection"})
*/
public ?int $id = null;
/**
* @Assert\NotBlank(groups={"create"})
* @Assert\Type("string")
* @SWG\Property(description="...", type="string")
*/
public string $name;
/**
* @Assert\Type("boolean")
* @SWG\Property(description="ist aktiviert/deaktiviert", type="boolean")
*/
public bool $active;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=ProfessionAreaDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?ProfessionAreaDto $professionArea = null;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=ProfessionalActivityDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?ProfessionalActivityDto $professionalActivity = null;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=IntroductionDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?IntroductionDto $introduction = null;
/**
* @SWG\Property(
* description="...",
* type="object",
* ref=@Model(type=PerformanceBehaviourDto::class)
* )
*
* @SerializerGroups({"view", "create", "update"})
*/
public ?PerformanceBehaviourDto $performanceBehaviour = null;
}
如果我用邮递员或通过我的测试调用 api 并将我的数据作为 json 传递,例如
{
"id":null,
"name":"fancy new data",
"active":true,
"professionArea":{
"id":48,
"name":"Vitae nulla aperiam aut enim.",
"active":true,
"signature":null,
"signatureTypeId":null,
"transition":null,
"infotextCheck":null
},
"professionalActivity":{
"id":null,
"textMResignationTestimonial":null,
...
"changedBy":null
},
"introduction":{
"id":null,
"textMResignationTestimonial":null,
"textMInterimTestimonial":null,
...
"changedOn":null,
"changedBy":null
},
"performanceBehaviour":{
"id":null,
"textMResignationGrade1":null,
"textMInterimGrade1":null,
...
"changedOn":null,
"changedBy":null
},
"createdOn":null,
"createdBy":null,
"changedOn":null,
"changedBy":null
}
我收到错误消息: TypeError: Typed 属性 App\Api\Dto\ProfessionDto::$professionArea 必须是 App\Api\Dto\ProfessionAreaDto 的实例或 null,使用数组
我做错了什么?我期望太多了吗?对象中的对象不可能吗?
因为这个项目没有使用 friendsofsymfony/rest-bundle 并且 Controller 没有扩展 AbstractFOSRestController。
所以我的问题的解决方案是手动编写一个 Denormalizer class,它将我的数组映射回正确的对象。
我是这样做的:
namespace App\Serializer;
use App\Api\Dto\IntroductionDto;
use App\Api\Dto\PerformanceBehaviourDto;
use App\Api\Dto\ProfessionalActivityDto;
use App\Api\Dto\ProfessionAreaDto;
use App\Api\Dto\ProfessionDto;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
class ProfessionDeNormalizer implements DenormalizerInterface
{
public function denormalize($data, $type, $format = null, array $context = [])
{
$dto = new ProfessionDto();
$areaDto = new ProfessionAreaDto();
$introDto = new IntroductionDto();
$activityDto = new ProfessionalActivityDto();
$performanceDto = new PerformanceBehaviourDto();
foreach($data['professionArea'] as $key => $value) {
$areaDto->$key = $value;
}
unset($data['professionArea']);
foreach($data['introduction'] as $key => $value) {
$introDto->$key = $value;
}
unset($data['introduction']);
foreach($data['professionalActivity'] as $key => $value) {
$areaDto->$key = $value;
}
unset($data['professionalActivity']);
foreach($data['performanceBehaviour'] as $key => $value) {
$areaDto->$key = $value;
}
unset($data['performanceBehaviour']);
foreach($data as $key => $value) {
$dto->$key = $value;
}
$dto->professionArea = $areaDto;
$dto->professionalActivity = $activityDto;
$dto->performanceBehaviour = $performanceDto;
$dto->introduction = $introDto;
return $dto;
}
public function supportsDenormalization($data, $type, $format = null)
{
return ProfessionDto::class === $type;
}
}