iChaib
iChaib

Reputation: 479

What's the best design to follow for this API in this case?

I'm building an API that post a given message to different platforms (Twitter, FaceBook...).

The problem is that for each platform I may change the wrapper that allow me to post the message. For example, in C# I can post a message on twitter using the yedda API or the CsharpTwitt API, for FaceBook I'll use others APIs...

Hence, I have to be able to use different wrappers to post a message for each platform. alt text

For now, this is the design I use, but it's clear that it will be too complicated if I add more APIs with more wrappers.

I think it's a common design issue and I'm wondering

  1. Am I using the best approach to have a well designed API?
  2. Otherwise, what is the best design for such a situation?
  3. What design pattern is applicable here?

Upvotes: 4

Views: 189

Answers (3)

ychaouche
ychaouche

Reputation: 5092

I'm not familiar with C#, but I can offer you some python code in the hope that the ideas inside may be useful.

I'll start with the client code, to show how the API is used :

# Client code
myapi = MyAPI()
# then call different methods :
message = "Some status"
# send to all platforms
myapi.broadcast(message)
# or
myapi.send_facebook(message) # send to fb only
myapi.send_twitter(message) # send to twitter only
# or
myapi.send("facebook",message) # another way of doing the same thing

Now the implementation :

# actual APIs
import FacebookAPI1 
import FacebookAPI2
...
import TwitterAPI1
import TwitterAPI2
...
# your individual wrappers, one for each API you want to use
# they all expose a send method
class FacebookAPI1Wrapper:
    def send(self,message):
        #use FacebookAPI1 functions

class FacebookAPI2Wrapper:
    def send(self,message):
        #use FacebookAPI2 functions

class TwitterAPI1Wrapper:
    def send(self,message):
        #use TwitterAPI1 functions

class TwitterAPI2Wrapper:
    def send(self,message):
        #use TwitterAPI2 functions

# Your API, this is the only class the client code needs.
class MyAPI:
      def __init__(self):
            # you decide internally what wrappers to use
            self.fb_api = FacebookAPI1Wrapper()                
            self.twitter_api = TwitterAPI2Wrapper()
            # No need for an intermediate level here I guess (Twitter and Platform_1 in your examples)
            # like : self.fb_api = Facebook() where Facebook chooses what wrapper to use internally (FacebookAPIWrapper)
            # it would just add unnecessary level of inderection.
            ... # other plateforms
            # hash-table-like structure, keys are plateform names, values are objects
            # this attribute is useful for the exposed send method where the first argument is a string
            # representing the name of the plateform the client wants to send a message to 
            self.plateforms = {"facebook" : self.fb_api,
                               "twitter"  : self.twitter_api
                               ...        : ...
                               }

      def broadcast(self,message):
            for plateform in self.plateforms.values() : #.values() will return the objects stored in the hash-table
                  plateform.send_message(message)

      def send_facebook(self,message):
            self.fb_api.send(message)

      def send_twitter(self,message):
            self.twitter_api.send(message)

      #...

      def send(self,plateform_name,message):
            # a simple hash table lookup
            platform = self.platforms.get(plateform_name)
            plateform.send(message)

Changing your code internally (implementation code) won't break client code as long as you keep the same interface.

Upvotes: 0

Arseny
Arseny

Reputation: 7361

you may use abstract factory if your create different message wrappers.

abstrcat class Abstractfactory{
       IBridge Create(int type);
}
class Platrofrm1facroty:Abstractfactory
{  
  //type m.b. for Wrapper1 to wrapperN 
  IBridge Create(int type);
}
class Twitterfacroty:Abstractfactory
{  
  //type m.b. for Yedda or CshartTwitt
  IBridge Create(int type);
}

Upvotes: 1

randomguy
randomguy

Reputation: 12252

I like this approach because this way you can dependency inject whatever wrapper you wish and change it with a single line of code.

For example

Bind<Yedda>().To<ITwitter>();
Bind<FBWrapper>().To<IFacebook>();

And now throughout the code ITwitter actually maps to the Yedda wrapper.

Dependency injection could be something worthwhile to look at.

Upvotes: 3

Related Questions