Search code examples
javaapioopdesign-patternsoembed

Which design pattern would be appropriate for the following api implementation?


I would like to add oEmbed tags to my site (I'm the oEmbed api provider). My api should respond the results based on the file type.

oEmbed Types has

  • Photo
  • Video
  • Link
  • Rich

My response to photo contains the following field

{
    "author_name": "rajasuba.s",
    "author_url": <author_image_url>,
    "thumbnail_width": 130,
    "provider_url": <provider_url>,
    "thumbnail_url": "<thumbnail_image_url>",
    "title": "Picture.png",
    "provider_name": "XYZ",
    "type": "photo",
    "version": "1.0",
    "url": "<given_url>",
    "thumbnail_height": 120
}

My response to video contains the following field

{
    "author_name": "rajasuba.s ",
    "author_url": "<image_url_of_author>",
    "thumbnail_width": 130,
    "html": "<iframe src="<source_url>" width=\"480\" height=\"270\" frameborder=\"0\">",
    "provider_url": "<service_url>",
    "thumbnail_url": "<thumbnail_image_url>",
    "title": "video_small_resource.mp4",
    "provider_name": "XYZ",
    "type": "video",
    "version": "1.0",
    "thumbnail_height": 120
}

And similarly for link and rich types.

I’m implementing this api in the following way. All I have is a servlet (where the api request lands). Here I have the following

public class OEmbedServlet extends HttpServlet {
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException
    {
    //Parse request uri

      String format = request.getParameter(“format”);
      String url = request.getParameter(“url”);
      String file_id = request.getParameter(“file_id”);

      String max_width = request.getParameter(“max_height”);
      String max_height = request.getParameter(“max_width”);

          if(authorised_user) {
            oembed.setFileInfo(file_id);
            oembed.setProviderInfo();
            oembed.setURL(url);
            oembed.setThumbnailInfo();
            oembed.setOEmbedType();
          }

     writeResponse(response, oembed.getJSONObject(), format);
   }
}

And another class which does all utility job for this servlet

public class OEmbed {
private HttpServletRequest request;

public OEmbed(HttpServletRequest request) {
this.request = request;
this.oembedType = OEmbedType.LINK;
this.width = 0;
this.height = 0;
this.thumbnailWidth = 0;
this.thumbnailHeight = 0;
}

public enum OEmbedType {
RICH/*0*/,
LINK/*1*/,
PHOTO/*2*/,
VIDEO/*3*/
}

public void String author;
public void String file_id;
public void String extension;
public void String fileType;

//Getter and setter methods for all required info to be passed in the response like 

public String getAuthorName() {
return this.author;
}

public String setAuthorName(String name) {
this.author = name;
}

public void setURL(String url) {
this.url = url;
}

public String getURL(String url) {
return this.url;
}

//…. and other getter and setter methods
/*
- Few setter methods are invoked from the servlet
- Few setter methods are clubbed together and invoked from util classes
- The setter methods in util does some computation to assign value - or they are assigned based on inputted params
- All required getter methods are obtained while writing response json
*/

public JSONObject getJSONObject(boolean isAuthorised) throws Exception
{
JSONObject oembedObj = new JSONObject();
if(this.url != null && !this.url.isEmpty()) {
switch(this.oembedType) {
case PHOTO:
oembedObj.put("url", this.thumbnailUrl);
break;
case LINK:
oembedObj.put("url", this.url);
default:
oembedObj.put("url", this.url);
oembedObj.put("html", htmlContent);
break;
}

if(this.thumbnailUrl != null && !this.thumbnailUrl.isEmpty()) {
oembedObj.put(“thumbnail_url”, this.thumbnailUrl);
oembedObj.put(“thumbnail_width”, this.thumbnailWidth);
oembedObj.put(“thumbnail_height”, this.thumbnailHeight);
}

}
}

I still feel this design very cumbersome. I feel inconvenient in the following things,

  • few setter methods were invoked from servlet and few were invoked from util class
  • also while making use of class variables in util class - i have to be careful whether those attribute values were already initialised

say for an example

public void setThubnailUrl(String url) {
this.thumbnail_url = url;
}
public void setThubnailUrl() {
setThumbnailInfo();
getThumbnailStatus();
setThumbnailUrl(url);    //So before initialising this url - i have to make sure manually - whether the required params for thumbnail url is initialised already (I'm not sure weather it is a best practice to do like this)
}

How can I organise it in a much better way? Which design pattern would be appropriate for the following case? Any suggestions are welcome :-)


Solution

  • First of all, you have a header and a content baked into a single message now which makes it harder to deal with both at the client and the server.

    Divide the message into two parts.

    The header describes general metadata such as author, generator service and the content type. The content is different for every contentType.

    By doing that small separation you are free to create different content builders without affecting the general handler.

    Thus you can introduce the factory pattern for that part and let different classes generate different content.

    As I'm a .NET coder I can't give you code. But typically you have a hashmap where the key is the contentType and the value is a factor method for the class that creates the content.

    pseudocode:

    var classInstance = _factoryMap[requestedContentType].CreateInstance();
    var content = classInstance.CreateContent(someResourceId);
    
    //create response here.