Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offer #33

Open
Azimjonm2333 opened this issue Jul 7, 2024 · 1 comment
Open

Offer #33

Azimjonm2333 opened this issue Jul 7, 2024 · 1 comment
Assignees
Labels
good first issue Good for newcomers

Comments

@Azimjonm2333
Copy link

I would like to suggest making one BaseAPIView at least for CRUD models
For example you can see it in CurrencyAPIView
If there are many models, there will be a lot of code duplication
Why not do it like this

class CurrencyAPIView(BaseAPIView, CurrencyViewInterface):
    list_serializer = ListCurrencyResponseSerializer
    detail_serializer = DetailCurrencyResponseSerializer
    create_serializer = CreateCurrencyRequestSerializer
    create_response_serializer = CreateCurrencyResponseSerializer
    update_serializer = UpdateCurrencyRequestSerializer
    update_response_serializer = UpdateCurrencyResponseSerializer

    list_use_case = ListCurrencyUseCase
    detail_use_case = DetailCurrencyUseCase
    create_use_case = CreateCurrencyUseCase
    update_use_case = UpdateCurrencyUseCase

    list_input_dto = ListCurrencyInputDto
    detail_input_dto = DetailCurrencyInputDto
    create_input_dto = CreateCurrencyInputDto
    update_input_dto = UpdateCurrencyInputDto

After that, we don't have to write a CRUD for the models every time like this:

# src/presentation/rest_api/apps/currency/views.py
class CurrencyAPIView(ViewSet, CurrencyViewInterface):
    authentication_classes = ()

    @extend_schema(
        responses={HTTPStatus.OK: ListCurrencyResponseSerializer},
        methods=[HTTPMethod.POST],
        parameters=[
            OpenApiParameter(
                "skip",
                int,
                OpenApiParameter.QUERY,
                description="Number of items to skip.",
            ),
            OpenApiParameter(
                "limit",
                int,
                OpenApiParameter.QUERY,
                description="Maximum number of items to retrieve.",
            ),
        ],
    )
    def list(self, request: Request) -> Response:
        # request
        parameters = {
            "skip": int(request.query_params.get("skip", 0)),
            "limit": int(request.query_params.get("limit", 100)),
        }

        # logic
        use_case = container.resolve(ListCurrencyUseCase)
        input_dto = mapper.to(ListCurrencyInputDto).map(parameters)
        result = use_case.execute(input_dto)

        # response
        return Response(
            data=ListCurrencyResponseSerializer(result).data, status=status.HTTP_200_OK
        )

    @extend_schema(
        responses={
            HTTPStatus.OK: DetailCurrencyResponseSerializer,
            HTTPStatus.NOT_FOUND: NotFoundResponseSerializer,
        },
        methods=[HTTPMethod.GET],
        parameters=[OpenApiParameter("id", CurrencyId, OpenApiParameter.PATH)],
    )
    def retrieve(self, request: Request, pk: Optional[CurrencyId]) -> Response:
        # logic
        try:
            use_case = container.resolve(DetailCurrencyUseCase)
            result = use_case.execute(pk)
        except EntityDoesNotExist as e:
            raise Http404() from e

        # response
        return Response(
            data=DetailCurrencyResponseSerializer(result).data,
            status=status.HTTP_200_OK,
        )

    @extend_schema(
        request=CreateCurrencyRequestSerializer,
        responses={HTTPStatus.CREATED: CreateCurrencyResponseSerializer},
        methods=[HTTPMethod.POST],
    )
    def create(self, request: Request) -> Response:
        # request
        serializer = CreateCurrencyRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # logic
        use_case = container.resolve(CreateCurrencyUseCase)
        input_dto = CreateCurrencyInputDto(**serializer.data)
        result = use_case.execute(input_dto)

        # response
        return Response(
            data=CreateCurrencyResponseSerializer(result).data,
            status=status.HTTP_201_CREATED,
        )

    @extend_schema(
        request=UpdateCurrencyRequestSerializer,
        responses={
            HTTPStatus.OK: UpdateCurrencyResponseSerializer,
            HTTPStatus.NOT_FOUND: NotFoundResponseSerializer,
        },
        methods=[HTTPMethod.PATCH],
        parameters=[OpenApiParameter("id", CurrencyId, OpenApiParameter.PATH)],
    )
    def partial_update(self, request: Request, pk: Optional[CurrencyId]) -> Response:
        # request
        serializer = UpdateCurrencyRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # logic
        try:
            use_case = container.resolve(UpdateCurrencyUseCase)
            input_dto = UpdateCurrencyInputDto(**serializer.data)
            result = use_case.execute(pk, input_dto)
        except EntityDoesNotExist as e:
            raise Http404() from e

        # response
        return Response(
            data=UpdateCurrencyResponseSerializer(result).data,
            status=status.HTTP_200_OK,
        )

    @extend_schema(
        responses={
            HTTPStatus.NO_CONTENT: None,
            HTTPStatus.NOT_FOUND: NotFoundResponseSerializer,
        },
        methods=[HTTPMethod.DELETE],
        parameters=[OpenApiParameter("id", CurrencyId, OpenApiParameter.PATH)],
    )
    def destroy(self, request: Request, pk: Optional[CurrencyId]) -> Response:
        # logic
        try:
            use_case = container.resolve(DeleteCurrencyUseCase)
            use_case.execute(pk)
        except EntityDoesNotExist as e:
            raise Http404() from e

        return Response(data=None, status=status.HTTP_204_NO_CONTENT)
@azizjon-aliev
Copy link
Owner

Hi @Azimjonm2333,

Thank you for your suggestion! Your idea of creating a BaseAPIView to reduce code duplication for CRUD operations is excellent. This approach would indeed simplify the code and make it more maintainable.

  1. Implementation Plan

  • This class will handle the common CRUD logic for all models.

  • It will use generics and dynamic attributes to allow customization for each specific model.

  1. Update the CurrencyAPIView to use BaseAPIView:
  • This class will inherit from BaseAPIView and set the required serializers and use cases.

With these changes, any new API view for CRUD operations can inherit from BaseAPIView and define its own serializers, use cases, and input DTOs, significantly reducing code duplication.

Please let me know if you have any questions or further suggestions!

Best regards,
@azizjon-aliev

@azizjon-aliev azizjon-aliev added help wanted Extra attention is needed good first issue Good for newcomers and removed help wanted Extra attention is needed labels Jul 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants