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

[QUESTION] How to use serializers from other domains for nested relationships #12

Open
juanxo opened this issue Aug 17, 2019 · 5 comments

Comments

@juanxo
Copy link

juanxo commented Aug 17, 2019

While trying to implement the structure that you have posed, I have reached a point where I wonder what would be the best course of action:

In my use case, I have two domains, one that includes a User model, and another one that includes an Outfit model. I'm also using django serializers atm as they provide some helpers to ease development.

For my use case, I want to return the User model nested inside the Outfit model, but that would cross models between domains. What would be the best approach here?

from django.contrib.auth.models import User
from .models.look import Outfit

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email', 'url']

class OutfitSerializer(serializers.HyperlinkedModelSerializer):
    user = UserSerializer()

    class Meta:
        model = Look
        fields = ['shortcode', 'user', 'url']
@phalt
Copy link
Owner

phalt commented Aug 20, 2019

This is a good question, and one my team has struggled with solving too. I briefly looked at some solutions around the internet. Things like protocol buffers try and solve this by setting up a shared resource of schemas for data. My only concern with that is: you then have the problem of controlling the distribution of that protocol buffer.

We solved this (we === the team at my current employment) by having our own UserSerializer in our domain. Because it was "our" version of the User, even though the User came from a different domain.

@pedrogimenez
Copy link

We finally solved it using a RelatedField that interacts with the UserInterface in the Outfits domain. This way we don't cross boundaries.

@phalt
Copy link
Owner

phalt commented Aug 20, 2019

@pedrogimenez very good idea. I like it! Can you share any code examples? I can promote this issue into a question for prosperity.

@pedrogimenez
Copy link

pedrogimenez commented Aug 22, 2019

I'm still not sure if this is the best approach but here's our implementation:

# com.outfits.serializers

from com.outfits.interfaces import UserInterface

class UserField(serializers.RelatedField):
    def to_representation(self, value):
        return UserInterface.get_user(id=value)

class OutfitSerializer(serializers.HyperlinkedModelSerializer):
    user = UserField(read_only=True)

    class Meta:
        model = Outfit
        fields = ['shortcode', 'user', 'url']
# com.outfits.interfaces

from com.users.apis import UserAPI

class UserInterface:

    @staticmethod
    def get_user(*, id: int) -> Dict:
        return UserAPI.get(id=id)

As I said above, the OutfitSerializer sends the get_user message to the UserInterface. This way, when you need to retrieve the user serialization, you do it through the ACL.

@phalt
Copy link
Owner

phalt commented Aug 22, 2019

I actually really like this pattern. I can foresee some performance issues if those interfaces are joining over network calls, but that would be a good opportunity to start keeping a shadow copy of the User in the Outfit serializer. But that only makes sense if you need a few attributes off of User. If you need the whole thing, it's a hard coupling to avoid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants