Repositories can manipulate and "transform" data?

Asked

Viewed 94 times

4

I’m implementing two video service Apis (Youtube and Vimeo), and because it’s a layer of data, I thought it was ideal to create repositories for each one, with the API being the "source" of the data.

something like:

class YoutubeApiRepository implements VideoRepositoryContract
{
    public function search(string $term): ?array
    {
        $YoutubeApi = new YoutubeApi;
        return $YoutubeApi->findVideos('baby shark');
        // return Google_Service_YouTube_SearchResult
    }
}

class VimeoApiRepository implements VideoRepositoryContract
{
    public function search(string $term): ?array
    {
        $VideoApi = new VimeoApiClient;
        return $VideoApi->findAllByTerm('baby shark')
        // return []
    }
}

The "problem" is that each API has a return in a different format...

1 - Would it be wrong for a Repository to iterate and manipulate the results of these Apis to standardize them? or it would be better if attached to another class "transformative"?

2 - In the case of a transformative class, an interface and a concrete implementation are created for each repository, such as would it be possible to standardize the past parameters? for example, Youtube returns an instance of the Object Google_Service_YouTube_SearchResult, already the Vimeo returns a Array ""and any data could be passed to the transformer...

Example of the class "transformer":

Interface VideoResponseTransformer
{
    public function transform($rawData): array
}

class YoutubeResponseTransformer implements VideoResponseTransformer
{
    public function transform($rawData) //Google_Service_YouTube_SearchResult
    {
        foreach ($rawData as $video) {
            ....
        }
   }
}

class VimeoResponseTransformer implements VideoResponseTransformer
{
    public function transform($rawData) //Array
    {
        foreach ($rawData as $video) {
            ....
        }
    }
}
  • Curiosity you are using in a framework?

  • Yes, I’m wearing Laravel

  • 1

    Not only that: https://laravel.com/docs/8.x/eloquent-resources#generating-Resources you need?

  • Thanks for the suggestion, I know there are Resources, but I wanted to know how to implement this independent framework solution

  • 1

    look at this is problematic: YoutubeApiRepository implements VideoRepositoryContract and class VimeoApiRepository implements VideoRepositoryContract the correct is that each repository implements exclusively its Interface, until it can extend of this one but, each one has its mainly to work with injection of dependency. The other part of formatting the data follows the example I quoted and if you can read this data you can format your way you are on the path but, some changes are missing in your code.

  • 1

    I understood, only that this way, with different interfaces, these two classes would not be easily replaceable, right?

  • What do you mean? I don’t understand!

  • @Virgilionovic I wish these implementations could be replaced in a simple way, and being of the same type (same interface), I get it

  • Thiago does not !!! you ai are breaking the sole responsibility, in POO is said that each code solves a problem, and you are condensing everything into one, is what I said each concrete Class has its interface and this interface can extend from another standard type interface, because at the time of the injection you will specify the class that implements the concrete. Well that’s how I ride and what I see do, including the Laravel Framework itself is like this.

  • basically: interface VideoRepositoryContract extends RepositoryContract and class YoutubeApiRepository implements VideoRepositoryContract and so on, being that RepositoryContract is your main base.

  • Ah one thing I saw these days in your code: $YoutubeApi = new YoutubeApi; and $VideoApi = new VimeoApiClient; could be injected also and these two classes be designed in the same way. Good is an idea of how to use.

  • 1

    @Virgilionovic but how is this instilling sole responsibility? Repository only returns the data, and the doubt is whether they can also manipulate them, and in Laravel I do not use the concrete class, the parameter passed is the Interface, and the Laravel service container can assemble a concrete class later

  • So I don’t think it makes much sense to have a generic repository interface, because each type has its characteristics (different interfaces), what do you think?

Show 8 more comments

1 answer

3

1 - It would be wrong to iterate and manipulate the results of these API to standardize them? or would it be better if attached to another class "transformer"?

Why would that be wrong? Your initial thinking is correct, you have created an interface that abstracts communication with the various video services you will consume. You treated these services as repositories, and there’s no problem with that, but your primary goal in this approach is abstract access to the various video services that exist around.

From there you can create a Factory to achieve the correct implementation according to the type of service you will consume. You can also add support to other services at any time without the need to change something in existing services.

2 - In the case of a transformer class, an interface is created and a concrete implementation for each repository, as would be possible standardize past parameters? for example, Youtube returns a instance of the Google_service_youtube_searchresult Object, already the Vimeo returns a "raw" array, and any data could be passed to the transformer...

I think you’ve given the answer on that point. Each platform will treat the data differently, this is an implementation detail and not a usage detail, and for this reason you do not need to create an interface to try to unify this. Unless you can find a pattern to build your interface, and if this isn’t too costly for you, I suggest you treat the data transformation as a responsibility for implementing each repository.

About the @Virgilio comment, if you want to perform a dependency injection per constructor it will be necessary for your classes to implement a specific interface for each one. You would have a IYoutubeRepository and a IVimeoRepository for example, but from what I understood of your question, your idea is really to be able to replace and decouple the implementations of different platforms.

If this is the case, you can use a Factory interface like IVideoRepositoryFactory which can receive the platform (viemo, youtube, etc.) as a parameter and return a correct instance of IVideoRepositoryContract. If you decide to go this way, the dependency injection would no longer be specifically from the platform, and you would start injecting Factory itself. Will depend on your implementation and need.

I was just wondering what the real advantage of Factory would be, since she would have to return a Repository too, can create an example?

Factory is a standard that solves problems to create objects. It does not conflict with the Dependency Inversion standard, whose main objective is to decrease the coupling between the components of your system. They solve different problems and can be used together, and your case is a good example of this. You have a service that searches for videos, which can have several implementations according to each platform. Who will consume this service need not worry about finding which is the correct implementation for the platform he is looking for, and to solve this problem you can utilize a factory. Below is a pseudo-code about this and a Stack exchange software Engineering link with a similar discussion.

class Video { }

interface IVideoFinder{
    Video search(string url);
}

// várias implementações YoutubeFinder, VimeoFinder, DailyMotionFinder...

interface IVideoFactory {
    VideoFinder create(string url);
}

class VideoFactory : IVideoFactory {
    VideoFinder create(string url) {
    // Retorna o VideoFinder correto de acordo com a URL da plataforma
    }
}

class Consumer{
    Consumer(IVideoFactory videoFactory) { }
    DoSomething(string url) {
        var video = videoFactory.create(url).search(url)
        // Fazer algo com as informações de video, independente da plataforma...
    }
}
  • 1

    Thanks for the answer, I was only in doubt what would be the real advantage of Factory, since it would have to return a Repository too, can you create an example? thank you!

  • 1

    With Fabrica (or Factory) which is the functionality is instance creation, would break DI and IOC from it, but, you could exemplify in code without implementing your answer, I was curious, even not answered because lately I take negative votes without deserving mainly by questions like this. I liked your answer I just did not understand if this is his case because of the Framework that he himself is using.

  • 1

    @Virgilionovic using a Factory is one of the ways to get an instance of a structure at runtime, and does not break the DI. It would also be possible to use the dependency container itself, depending on the framework they offer a Service Locator, but it is much harder to understand the code since the Service Locator is not contextualized. I believe that this is a subject for another question, this is already very big.

  • 1

    @Vinicius in Laravel that is framework in question the Factory would not be ideal. but then everyone thinks about their development strategy, and from what he posted there is no way to say anything.

  • 1

    @Virgilionovic why wouldn’t Factory be ideal? I think this is independent of framework, even why I left without the Laravel tag, but someone added

  • @If Thiagodias did not put important data to answer your question, omitted the fact of the framework and what is in the question is not ideal, I would not use a class only to create instance because it is legal has to have a clear goal that denotes using code like this, Why not make it simple? Why complicate? You’re using interface and this denotes implementation of it, I don’t need then a Fabric now it all depends on what and when to use such a pattern. Finally the answer of the friend is right, but, because he himself reported lack more context, so I did not even respond.

  • 1

    @Virgilionovic Because the framework is not important in this case, this code snippet could easily be from Symfony, which also has Service Container. I’m sorry, but I didn’t understand what you meant by not using an interface, just look at her signature

  • @Thiagodias I didn’t say not to use interface I said use each other, I know the code of the Laravel Framework your base is Symfony I come from the roots of that Framework when it was all Facade, so I’m saying you can use interface and implementing classes (concrete), but, that this is implemented with sole responsibility, but, it needs to write an example code for you to understand the whole process and in your question does not have the return model of Apis. Note that this here on the site is a do for me and we only take negative vote doing this.

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.