Set-up anonymous messages for your hashnode blog
Create a new messages widget, code the server, setup telegram bot, and deploy the app to vercel
Let's see how to create a messaging widget for your hashnode blog. We will set-up the widget to send the message to a server, which sends the message to the user via telegram.
Final Product
This is our final result. A messaging widget that sends messages straight to the authors via telegram. Please feel free to send feedback.
Creating a new Hashnode widget
A hashnode widget is a small HTML application(HTML + CSS + JS), that can be embedded into any hashnode blog using a shortcut like %%[widget-name]
.
Hashnode dashboard -> Widgets -> Add a new Widget
We can skip about the UI as you can design better than mine. The important thing here is the endpoint.
anonymoose.vercel.app/api/message?chat_id={chat_id_here}
Send a POST request to the endpoint with payload,
{
"message": "<your-message-here>"
}
In a later section, we'll see how to deploy your own instance of the app to vercel.
Setting up the server
We will build our application using FastAPI.
Create a new virtualenv and install fastapi.
virtualenv .venv
.venv/Scripts/activate
pip install fastapi==0.63.0 uvicorn==0.13.3
We will use uvicorn
for the development purpose. The deployment doesn't require uvicorn as vercel
runs serverless python.
The API will have just one endpoint to receive a POST request from our widget.
# app/api.py
from fastapi import APIRouter, Query
from fastapi.background import BackgroundTasks
from app.telegram import send_message
from app.schemas import Payload
api = APIRouter(prefix="/api")
@api.post("/message")
async def post_anonymous_message(
data: Payload, background: BackgroundTasks, chat_id: str = Query(...)
):
background.add_task(send_message, data.message, chat_id)
return {"message": "success"}
Let's see what we did here. We imported all the required stuff on top. The send_message
and Payload
imports will be explained below. The router(/api
) will have a single POST endpoint at /message
. It takes in the payload
, chat_id
, and an instance of FastAPI's BackgroundTasks
.
BackgroundTasks let you run tasks in the background. This comes in very handy when you want to instantly return the response instead of making the user wait for a long-running job. In our case, we don't know the network delay in sending a telegram message.
For example, let's consider an application that allows people to upload and share images(like Instagram). Once an image is uploaded, you want to resize the image to 5 different sizes(for thumbnails and other purposes). We can use background tasks to resize the images and send the response as soon as the upload is complete.
Here's how it works,
- User uploads image
- Send response as soon as the upload is finished
- Resize the image in the background
What's in the Payload
?
Payload
is a pydantic model for validating the JSON input.
# app/schemas.py
from pydantic import BaseModel, Field
class Payload(BaseModel):
message: str = Field(..., max_length=100)
Here the json data contains a single field, message
, with a max length of 100.
Define the send_message
function
To define the send_message
function, we need to set up a new telegram bot.
Go to your telegram app and search for @BotFather
Now type /newbot
in the chatbox to start creating the app. Follow all the instructions, and finally, you'll get the bot token
. Save the bot token to a .env
file.
# .env
TOKEN=12345678910:ABCDEFGHIJKLMNOQRSTUVWXYZ
# dummy token for illustration purposes
Install python-dotenv to load the env variables.
pip install python-dotenv==0.15.0
And we'll use pydantic to load the environment variables.
# app/config.py
from pydantic import BaseSettings
class Config(BaseSettings):
token: str
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
Before defining our send_message
function, we need to install one more requirement. We'll use aiohttp to make requests to telegram API
pip install aiohttp==3.7.3
Once everything is set-up, we define the send_message function.
import aiohttp
from app.config import Config
settings = Config()
async def send_message(message: str, chat_id: str):
url = f"https://api.telegram.org/bot{settings.token}/sendMessage?chat_id={chat_id}&text={message}"
async with aiohttp.ClientSession() as session:
await session.get(url)
A GET
request to the telegram API endpoint sends our message to the provided chat_id
. In case you don't know your chat_id, send /start
to the bot @getmyid_bot
. It'll return your chat_id.
Finally, we create a FastAPI app.
# main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api import api
app = FastAPI(include_in_schema=False)
origins = [
"https://embeds.hashnode.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(api)
Since the widget is served from embeds.hashnode.com
, we add it to CORS.
How to deploy one for yourself?
Create a new telegram bot
- Add the token to env variables while deploying
- Change the API endpoint at your widget to the newly deployed one.
If you want to use the feature without deploying one, add a new widget with the endpoint as anonymoose.vercel.app/api/message?chat_id={chat_id_here}. You can use the widget here or create one for your own.
If you liked this, please give your feedback. In case you didn't like what I created and want to write something that goes against the hashnode policies, please feel free to write an anonymous message
Demo
Source
Avid learner | Frontend Developer , open source enthusiast
This is really cool! I remember hashnode had a DM feature earlier. It's not just limited to hashnode right? Can we use it elsewhere like on a portfolio site or something?
Yeah, it can be deployed on any website. Just change the CORS
in your deployment to your website.
Comments (2)