How I Built a Social Media Publisher on AWS for Free

As a writer, I am interested on sharing my knowledge with the community, and social media platforms (Twitter, LinkedIn, Facebook and so on) are a great way to start with.

Sharing on social media platforms has a cost, on time and on money, so, I decided to not pay that cost, building an application that does that for me.

In this open source project, you will see how I applied some of the concepts of previous posts, like the Main and Abstractions, Plugins, Inversion of Control, Dependency Injection, Open Closed Principle, and others.

In this post, you will see why and how I built a social media publisher that doesn’t cost me money and does the use cases I need.

NOTE: This application is not plug and play. It requires knowledge on Software Engineering.

TRY IT YOURSELF: This is an opensource project. You can find the source code here.

Why I Built it from Scratch?

The Cost Of Social Media

The easy way to share on social media is using their applications and post directly there, and that’s okay if you want to share a thought once a week, however, when you have not only one social media account, but multiple, and you want to publish your thoughts frequently, said, 3 times at day, you will have troubles if you care about your time, it is simple math:

time = (3 social media accounts) *
       (3 times at day) * 
       (5 minutes by publication)

time = 45 minutes at day

Do you want to spend 45 minutes at day sharing on social media? I do not.

Now, let’s say you are willing to spend that time. There are some content you want to publish frequently, like old posts on your blog, a book you want to get noted, or thoughts you think are still relevant. That means, you need to structure the idea again, check the writing, choose the social media platforms and publish it. You did this before, and you need to do it again, and if you want to publish them frequently, you will do the same process again and again.

So, those 45 minutes a day are not just for new content, but for old content also. You can keep the content somewhere and just copy and paste before publishing. That will save you some time.

Why Build This From Scratch?

Of course, this problem is not new, so, you can find a lot of applications that offer you similar features, for instance, I use Crowdfire.

Crowdfire allows me to publish on several social media platforms, schedules posts, and gives me some analytics over the behavior of those posts. I use the free version, offer me 10 scheduled posts, with limited media content, only 3 social media platforms connected, and other things.

If I want more, I need to pay, and they don’t handle some features I am interested in, like publishing old posts/thoughts frequently.

So, I built this from scratch, with the following goals:

  • Be open source: If anyone is interested, can contribute.
  • Not cost money: This application is deployed over the always free layer in AWS.
  • Allow to keep your thoughts: You can save my posts and thoughts
  • Allow to publish your thoughts: Your posts are published from the oldest one to the newest one, in a never-ending loop

In the following sections, you will see how I approach those uses cases using AWS and Java.

How I Built It?

In this section, I will share how I built Social Media Publisher. I will use the C4 model to express architecture.

Context View

Let’s start with the following context diagram:

Context diagram

There, we see how a Writer interacts with Social Media Publisher. Also, the Writer must have social media accounts active, in this case, we only support LinkedIn and Twitter.

The Writer can save thoughts/posts in the Social Media Publisher and schedule them to be published in the future. The schedule is not done by post, instead, it is a recurrent operation. The following are the common interactions a Writer and the System do:

  1. The Writer saves posts in the system. A post has a name, description, published date, tags, and an URL. The following is an example of a post:
{  
  "description": "Do you really understand....",  
  "id": "1",  
  "name": "Dependency Inversion: why...",  
  "publishedDate": "2020-01-18T00:00:00",  
  "tags": [  
       "coderstower", 
       "java", 
       "solid" 
   ],  
  "url": "https://coderstower.com/2019...."  
}  

The published date represents the last time the post was published.

2. After, the Writer defines how frequently he wants to publish the posts. For instance, I want to publish a post each 2 days at 2 pm. This rule is defined in the system.

3. Now, the system will be executed at the scheduled time, searching for the oldest post in the posts set, and publishes it on the registered social media accounts.

4. An email is sent to the Writer showing the result of the publication.

With this context, let’s go deep and see the container view of the Social Media Publisher application.

Container View

Now, let’s see the containers of the system:

Container view

There, we can see the infrastructure and technologies we use in Social Media Publisher. The following is the steps perform to publish a post:

  1. The Writer defines a CloudWatch rule. This rule says how frequently the oldest post is going to be published.
  2. When the CloudWatch rule is executed, a AWS Lambda is called. That lambda is a Spring Boot application.
  3. The Spring Boot application searches the oldest post in AWS DynamoDB, the right authentication credentials for social media accounts, and publishes it on the registered social media accounts. If the publication succeed, the application updated the last published date of the post to the current date.
  4. Finally, the application sends an email with the information regarding the publication, could be a failure or not.

Now, we understand the infrastructure we use. Let’s move to how the Spring Boot application is built.

Component View

The component diagram shows us how the Spring Boot application is composed:

Component diagram

The Spring Boot application has two flows: Publishing posts and updating OAuth2 credentials.

The first flow, publishing posts, has the following:

  1. One controller, /posts/next. This receives the call from Cloud Watch.
  2. A Posts Publisher, this class handles which is the next post to publish and to which social media accounts.
  3. And a Posts Repository, who connects to AWS DynamoDB, querying and updating the posts.

The second flow is for updating OAuth2 credentials:

  1. One controller, /oauth2/{social-media}/credentials. When this endpoint is accessed, Spring Security will redirect to the right social-media account to request a OAuth2 code flow. This flow will redirect the Writer to his social media account, to log in, and the social media redirects back to the initial endpoint, with valid OAuth2 credentials.
  2. An OAuth2 Credential Manager, who grabs the OAuth2 credentials and update the keys with the new values.
  3. And finally, an OAuth2 Credentials Repository, to access AWS DynamoDB.

NOTE: OAuth1 credentials (Twitter) generate access keys that don’t expire, however, OAuth2 credentials (LinkedIn) need to be refreshed frequently, as they expire.

Right now, the second flow only works locally, not in AWS. This is because AWS Lambda doesn’t support a Security Session, which is required to use Spring Security OAuth.

NOTE: I tried to avoid the use of a Session, and being able to deploy these features on AWS Lambda, but, the amount of customization involved is huge. If you are curious about how to do it, check this branch. You can deploy the application on an AWS EC2, to be able to use a Spring Session, but, AWS will charge you, which is not part of the use cases.

Finally, let’s go deep and see the implementation view.

Implementation View

Let’s start with the project structure:

Project structure

There, we see two main projects, aws-publisher and spring-publisher:

  • spring-publisher: It is responsible for all the business logic, choosing the right social accounts, handling the security logic, and having the way of publishing in social accounts.
  • aws-publisher: It is responsible for anything AWS related: accessing DynamoDB and the Lambda Spring boot proxy.

As we see, we split the application between the main and abstraction, where the abstraction is spring-publisher and the main is the aws-publisher. This allows us to change the cloud provider if we want, handling them as a set of plugins.

Now, regarding the publication of posts, this is the general structure:

General structure of publishing

There, we have a SocialMediaPublisher interface, which defines the behaviors of social media accounts. We have two implementations, LinkedIn and Twitter.

The PostsPublisher has a reference to multiple SocialMediaPublisher, and when it needs to publish a post, it iterates over the social media registered publishers and requests them to publish.

This structure applies the Strategy Pattern and the Open Close Principle.

The implementation view has much more to talk about, but, I think that is not necessary, you always can check the source code if you are curious.

Final Though

Building things is fun for us, as Software Engineers, but sometimes we waste a lot of time and effort building things that doesn’t return the investment, so, think twice before building something, moreover, if there are applications on the market that already solve the problem you have.

Design patterns and OOP concepts are always useful, they are not just theory, you can apply them in real life problems, but, don’t exaggerate, sometimes, applying a pattern is a waste of time and effort.

If you are interested in seeing the implementation and how to install the application, you can go to the Github project.

If you liked this post and are interested in hearing more about my journey as a Software Engineer, you can follow me on Twitter and travel together.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s