Skip to main content

Build an Event-Driven Social Media Backend

Overview​

In this tutorial you build a complete, Twitter-style social media backend with WSO2 Integrator, the low-code integration platform built on Ballerina. You design everything visually, and WSO2 Integrator generates clean Ballerina underneath. Most parts show both: the visual steps on one tab, and the exact code the platform produced on the other.

By the end, a single POST will flow from the API through a user check and sentiment screening into MySQL, and out to a Slack channel.

What you will build

A backend for a small social network where people register, publish short posts, and follow each other. Every new post is first screened by a sentiment-analysis service; anything negative is rejected before it is stored. An accepted post is saved to MySQL and, without making the author wait, announced to a team Slack channel through a RabbitMQ event pipeline. You build it as three small integrations, and every part is something you design on the canvas.

Architecture​

You build three focused integrations inside one project rather than a single monolith, the way you would in production.

IntegrationTypeResponsibility
Social Media APIHTTP serviceUsers and posts REST API. Checks the user, screens posts for sentiment, persists to MySQL, and publishes a new-post event to RabbitMQ.
Sentiment APIHTTP serviceA small service that scores post text as positive, negative, or neutral.
Post NotifierRabbitMQ event integrationConsumes new-post messages and posts to Slack.

Architecture diagram: a POST request hits the Social Media API, which synchronously screens the text with the Sentiment API and persists to MySQL, then asynchronously publishes a new-post event to RabbitMQ, which the Post Notifier consumes to post a message to Slack

The integrations collaborate through a deliberate choice of contract. The Social Media API calls the Sentiment API over HTTP because it needs the verdict synchronously to decide whether to store the post. It hands the notification off to RabbitMQ because the author should not wait on Slack, and because you can add more consumers later (email, analytics) without touching the API.

The Social Media API is the orchestrator: it depends on the sentiment service, a database, and the message pipeline. So you build the two standalone integrations it leans on first (Steps 2 and 3), then assemble the API itself (Step 4) and run the whole thing (Step 5).

Event-driven backbone

RabbitMQ is a first-class event integration trigger: you build the consumer entirely in the Visual Designer. The pattern is broker-agnostic; the platform also ships triggers for Kafka, MQTT, Solace, and Azure Service Bus.

Prerequisites

Before you start, make sure you have:

Set up the MySQL database

Run this script against your MySQL instance. It creates the database, an application user, the three tables, and a couple of seed users:

CREATE DATABASE IF NOT EXISTS social_media;

-- Application user the integration connects as
CREATE USER IF NOT EXISTS 'social_media_user'@'localhost' IDENTIFIED BY 'social_media_pass';
GRANT ALL PRIVILEGES ON social_media.* TO 'social_media_user'@'localhost';
FLUSH PRIVILEGES;

USE social_media;

CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
mobile_number VARCHAR(15) NOT NULL,
birth_date DATE
);

CREATE TABLE posts (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
description VARCHAR(255) NOT NULL,
category VARCHAR(255),
tags VARCHAR(255),
created_date DATE,
user_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

CREATE TABLE followers (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
leader_id INT NOT NULL,
follower_id INT NOT NULL,
created_date DATE,
UNIQUE (leader_id, follower_id),
FOREIGN KEY (leader_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (follower_id) REFERENCES users(id) ON DELETE CASCADE
);

INSERT INTO users (name, mobile_number, birth_date) VALUES
('Alice', '+94771234001', '1995-03-12'),
('Bob', '+94771234002', '1998-07-25');

You now have a social_media database reachable with these credentials, which you give to the dbClient connection in Step 4:

SettingValue
Hostlocalhost
Port3306
Databasesocial_media
Usersocial_media_user
Passwordsocial_media_pass

Step 1: Set up the project​

Everything you build sits inside one project, so you set that up first. WSO2 Integrator creates the project and your first integration together, in a single form.

Create the project and open the Design view
  1. Launch WSO2 Integrator and, on the Create a Project card, click Create to create a project.
  2. Name the project social-media and choose where it lives on disk. This is the one project that will hold all three integrations from the architecture.
  3. Under What do you want to build?, select Integration, name it social-media, and click Create.

The Create a Project form, with the project and integration both named social-media

The project opens to its landing view. The artifacts panel on the left is where your integration takes shape: Entry Points, Connections, Types, Functions, Data Mappers, and Configurations are all empty for now, and you fill the ones you need as the tutorial goes. The center pane lists the social-media integration you just created.

The social-media project landing view, showing the artifacts panel on the left and the Integrations and Libraries pane in the center

Open the integration and you land in the Design view, where the canvas shows the flow of whichever artifact you select. The integration is empty, so the Design view invites you to add your first artifact. Every part that follows starts here, with + Add Artifact. Use the Show Source toggle whenever you want to see the generated code; you never have to edit it.

The empty social-media integration in the Design view, showing the "Your integration is empty" message and the Add Artifact button


The Social Media API ties three pieces together: a service to screen posts, a pipeline to announce them, and a store to keep them. Build the two standalone integrations first, the Sentiment API and the Post Notifier.

Step 2: Build the Sentiment API​

The first standalone integration is the screening service. Build a small Sentiment API that takes post text and returns a sentiment label with probabilities. For the tutorial it returns hardcoded values, so you can focus on the integration rather than a real model.

Create the service, types, and the response flow
  1. From the project view, click + Add to add another integration to the same social-media project.

    The social-media project view with the Add button highlighted

    Select Integration, name the new integration sentiment-api; the package name defaults from the name and the organization is inherited from the project. Click Add.

    The Add New Integration form with the integration named sentiment-api

  2. In the new integration, click + Add Artifact, then HTTP Service. Set the Service Base Path to /text-processing, choose a Custom Listener on Port 9000 named httpListener, and click Create.

    Creating the HTTP service with base path /text-processing on a custom listener at port 9000

  3. Add three types: a Post with a text field, a Probability with neg, neutral, and pos decimals, and a Sentiment holding a Probability and a label. When adding each type, expand Advanced configs and tick Accessible by other integrations: the Social Media API in Step 4 imports Post and Sentiment directly from this module.

    The Type Diagram showing the Post, Probability, and Sentiment records

  4. Click + Add Resource. Set the method to POST and the path to api/sentiment, bind the Payload to Post, and define responses 201 returning Sentiment and 500 returning error. Click Save.

    Adding the POST api/sentiment resource with a Post payload and Sentiment response

  5. Open the resource flow and build the response with Declare Variable nodes: one for the probability, one for the sentiment, then a Return. The values are hardcoded for the tutorial.

    Building the Sentiment record in the Record Configuration panel

    The completed POST api/sentiment flow: Start, two Declare Variable nodes, Return, and an Error Handler

Capability: Low-code HTTP service design. You define the types, the resource, and its response flow visually, and the platform writes the service for you.


Step 3: Build the Post Notifier: RabbitMQ to Slack​

The other standalone integration is the announcement pipeline. Build the Post Notifier, a RabbitMQ-triggered event integration that consumes new-post messages and posts to Slack. Declare the configurations it needs first, the broker details and the Slack token, then build the connector and the event integration on top of them. This is where RabbitMQ's first-class trigger support shines: you build the consumer entirely in the designer.

Add configurations, the Slack connection, and the RabbitMQ handler
  1. From the project view, click + Add to add a third integration to the same project. Select Integration, name it post-notifier, and click Add.

    The Add New Integration form with the integration named post-notifier

  2. Add the configurations the integration needs: rabbitmqHost (string) and rabbitmqPort (int) for the broker, and slackAuthToken (string) for the Slack app.

    The three configurables: rabbitmqHost, rabbitmqPort, and slackAuthToken

  3. Add the Slack connector. Set its Config to bind the token to slackAuthToken, and name the connection slackClient. Follow the Slack setup guide to create an app and copy a bot token, then add scopes.

    Configuring the Slack connection with auth token bound to slackAuthToken and named slackClient

  4. Click + Add Artifact, choose Event Integration, then RabbitMQ.

    The artifact palette with RabbitMQ selected under Event Integration

    Name the listener rabbitmqListener, point its Host and Port at rabbitmqHost and rabbitmqPort, and set the Queue Name to ballerina.social.media. Click Create.

    Configuring the RabbitMQ listener host, port, and the ballerina.social.media queue

  5. Add an event handler and choose onMessage. Define the message content as a NotificationEvent type with a leaderId field.

    Defining the NotificationEvent content type with a leaderId field

  6. In the onMessage flow, add the slackClient connection's Send a message to a channel operation. Set the channel and a text built from the event's leaderId.

    Configuring the Slack message with a channel and a text built from the leaderId

    The completed handler posts to Slack whenever a message lands on the queue.

    The onMessage flow: Start, the slack post node, and an Error Handler

Capability: RabbitMQ trigger and connectors. A broker message drives an integration that calls a SaaS connector, the core of event-driven, connector-rich integration.


With the Sentiment API and the Post Notifier built, assemble the Social Media API that uses them.

Step 4: Build the Social Media API​

This is the heart of the backend. The Social Media API is the orchestrator: it exposes the users-and-posts REST API, stores everything in MySQL, screens each post with the Sentiment API from Step 2, and announces accepted posts through the Post Notifier from Step 3. You build all of it here, in the social-media integration: add the connections it needs, then design the resources and the post-creation flow on the canvas. The social_media database and its tables were created in the Prerequisites.

Add the connections​

The API talks to three things, so add a connection for each before you build the flow: the MySQL database (through the persist feature), the RabbitMQ broker, and the Sentiment API.

Add the database, RabbitMQ, and Sentiment connections
  1. Database. In the artifacts panel, open Connections and click +, then choose Connect to a Database. Select MySQL and enter the social_media credentials from the Prerequisites.

    Entering the MySQL credentials in the Connect to a Database wizard

    Select all three tables, then name the connection dbClient. The persist feature generates a type-safe client with CRUD functions and the matching User, Post, and Follower entities.

    Naming the database connection dbClient with its generated configurables

  2. RabbitMQ. Add a RabbitMQ connection, bind its Host and Port to rabbitmqHost and rabbitmqPort configurables, and name it rabbitmqClient.

    Configuring the RabbitMQ client connection with host and port configurables

  3. Sentiment API. Add an HTTP connection with the Url of the Sentiment API, http://localhost:9000/text-processing, and name it sentimentClient.

    Configuring the sentiment HTTP client connection pointing at the Sentiment API URL

Create the service and list users​

With the connections in place, add the HTTP service and build your first resource: list all users straight from the database.

Create the service and the get-users resource
  1. Click + Add Artifact, then HTTP Service under Integration as API. Keep Design From Scratch, set the Service Base Path to /social-media, and accept the Shared Listener (Port 9090). Click Create.

    Creating the HTTP service with base path /social-media on the shared listener

  2. Add the resources your API exposes. This walkthrough builds two of them in full; the rest follow the same pattern:

    MethodPathReturns
    GET/usersall users
    POST/users/{id}/poststhe created post
  3. Open the get users resource. Click +, expand dbClient, and add Get rows from users. Name the result users and select the fields to return.

    Adding a Get rows node on dbClient and selecting the user fields

  4. Add a Return node that returns users.toJson().

    Returning the users list as JSON

Handle a new post​

This is the resource that ties everything together. When someone posts, you confirm the user exists (a 404 if not), screen the text with the Sentiment API (a 406 if it comes back negative), store the post, announce it through RabbitMQ, and return 201.

Build the post-creation flow
  1. Add the POST /users/{id}/posts resource with a NewPost payload (description, tags, category), and define its typed responses: 201 http:Created, 404 http:NotFound, 406 http:NotAcceptable, and 500 error.

    Defining the post resource with a NewPost payload and 201, 404, 406, and 500 responses

  2. Confirm the user exists. In the flow, add a Get rows from users node filtered by id (result user), then an If node with the condition user.length() == 0.

    An If node checking user.length() equals 0

    In its branch, declare an http:NotFound response with body { msg: "User not found" } and Return it.

    Declaring an http response and returning it

  3. Screen the text. Declare a variable postMessage holding { text: newPost.description }.

    Preparing the request payload for the Sentiment API

    Then call sentimentClient with an http post to /api/sentiment, storing the result in sentiment.

    Calling the Sentiment API through the sentimentClient connection

  4. Reject negatives. Add an If node with the condition sentiment.label == "neg".

    An If node checking the sentiment label

    In its branch, declare an http:NotAcceptable response with body { msg: "Post not acceptable" } and Return it.

    Declaring an http response and returning it

  5. Store the post. Add an Insert rows into posts node on dbClient, using the record helper to build the post from newPost and the path parameter id.

    Building the post record and inserting it with the record helper

  6. Announce it. Add a rabbitmqClient publishMessage node with content { leaderId: id.toString() } and routing key ballerina.social.media, the queue the Post Notifier listens on.

    Publishing the new-post message to RabbitMQ

  7. Return success. Declare an http:Created response with body { msg: "Post successfully created" } and Return it.

    Declaring the http response and returning it

Capability: Orchestration on one canvas. A single visual flow loads data with the persist client, calls another service over HTTP, branches on the result, stores a record, publishes an event, and returns the right HTTP status, all without writing code.


Step 5: Run and test​

Everything is built. Make sure your MySQL and RabbitMQ instances are running and the social_media database exists (from the Prerequisites), and fill in each integration's Config.toml (the database password, the RabbitMQ host and port, and the Slack token). Then Run the three integrations.

Open the Social Media service, click Try It, and invoke a resource in place.

Calling get users, for example, returns 200 OK with the seed users:

Testing the get users resource with the Try It tool, returning 200 OK and the seed users

Then exercise post users/[id]/posts: a normal post returns 201 Created and posts to Slack, a post the Sentiment API scores negative returns 406 Not Acceptable, and an unknown user returns 404 Not Found.

Testing the post users resource with the Try It tool: a request body returns 201 Created with a success message


What's next​

You have built a complete, event-driven backend as three integrations, designed entirely in the Visual Designer: a REST API that screens posts with a sentiment service, stores them in MySQL through the persist feature, and announces them to Slack over a RabbitMQ pipeline.

Explore more of what you can build with WSO2 Integrator: