[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"academy-blogs-en-1-1-all-push-notifications-websocket-chat-all--*":3,"academy-blog-translations-c4q538jp0bh7b49":99},{"data":4,"page":87,"perPage":87,"totalItems":87,"totalPages":87},[5],{"alt":6,"collectionId":7,"collectionName":8,"content":9,"cover_image":10,"cover_image_path":11,"created":12,"created_by":13,"expand":14,"id":93,"keywords":94,"locale":69,"published_at":95,"scheduled_at":13,"school_blog":91,"short_description":96,"slug":97,"status":89,"title":6,"updated":98,"updated_by":13,"views":92},"EP. 38 Adding Push Notification Support to WebSocket Chat","sclblg987654321","school_blog_translations","\u003Ch3>Why Use Push Notifications with WebSocket Chat?\u003C\u002Fh3>\u003Cp>While WebSocket enables real-time data transmission, users may miss new messages if the application is closed or if there is a connection issue. Push Notifications ensure that users continue to receive alerts even when they are not actively using the app.\u003C\u002Fp>\u003Ch3>Technologies Used in the Notification System\u003C\u002Fh3>\u003Col>\u003Cli>\u003Cstrong>WebSocket Server:\u003C\u002Fstrong> Used for sending messages between users.\u003C\u002Fli>\u003Cli>\u003Cstrong>Web Push API:\u003C\u002Fstrong> Utilized for sending notifications to the user's browser.\u003C\u002Fli>\u003Cli>\u003Cstrong>Firebase Cloud Messaging (FCM):\u003C\u002Fstrong> Serves as the notification service for sending messages to mobile devices.\u003C\u002Fli>\u003Cli>\u003Cstrong>Database (PostgreSQL \u002F MongoDB):\u003C\u002Fstrong> Stores user subscription data for notifications.\u003C\u002Fli>\u003C\u002Fol>\u003Ch3>Install Necessary Libraries\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext\">go get github.com\u002Fappleboy\u002Fgo-fcm\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Database Setup to Store User Tokens\u003C\u002Fh3>\u003Cp>File: \u003Ccode>\u003Cspan>schema.sql\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext\">CREATE TABLE notification_tokens (\n    id SERIAL PRIMARY KEY,\n    user_id INTEGER NOT NULL,\n    token TEXT NOT NULL UNIQUE\n);\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Creating GraphQL Schema for Notifications Subscription\u003C\u002Fh3>\u003Cp>File: \u003Ccode>\u003Cspan>schema.graphql\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext\">type Mutation {\n  registerNotificationToken(userID: ID!, token: String!): String!\n  sendPushNotification(userID: ID!, message: String!): String!\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Creating Resolvers for Push Notifications\u003C\u002Fh3>\u003Cp>File: \u003Ccode>\u003Cspan>resolver.go\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext\">package main\n\nimport (\n    \"context\"\n    \"database\u002Fsql\"\n    \"fmt\"\n    \"github.com\u002Fappleboy\u002Fgo-fcm\"\n    _ \"github.com\u002Flib\u002Fpq\"\n)\n\ntype Resolver struct {\n    db *sql.DB\n}\n\nfunc (r *Resolver) Mutation_registerNotificationToken(ctx context.Context, userID int, token string) (string, error) {\n    _, err := r.db.Exec(\"INSERT INTO notification_tokens (user_id, token) VALUES ($1, $2) ON CONFLICT (token) DO NOTHING\", userID, token)\n    if err != nil {\n        return \"Failed to register token\", err\n    }\n    return \"Token registered successfully\", nil\n}\n\nfunc (r *Resolver) Mutation_sendPushNotification(ctx context.Context, userID int, message string) (string, error) {\n    var token string\n    err := r.db.QueryRow(\"SELECT token FROM notification_tokens WHERE user_id = $1\", userID).Scan(&amp;token)\n    if err != nil {\n        return \"User token not found\", err\n    }\n\n    data := &amp;fcm.Message{\n        To: token,\n        Notification: &amp;fcm.Notification{\n            Title: \"New Message\",\n            Body:  message,\n        },\n    }\n\n    client, err := fcm.NewClient(\"YOUR_FIREBASE_SERVER_KEY\")\n    if err != nil {\n        return \"Failed to initialize FCM client\", err\n    }\n    \n    _, err = client.Send(data)\n    if err != nil {\n        return \"Failed to send notification\", err\n    }\n    return \"Notification sent successfully\", nil\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Connecting WebSocket and Push Notification\u003C\u002Fh3>\u003Cp>File: \u003Ccode>\u003Cspan>websocket_server.go\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext\">package main\n\nimport (\n    \"fmt\"\n    \"net\u002Fhttp\"\n    \"github.com\u002Fgorilla\u002Fwebsocket\"\n)\n\nvar upgrader = websocket.Upgrader{\n    CheckOrigin: func(r *http.Request) bool { return true },\n}\n\nfunc handleWebSocket(w http.ResponseWriter, r *http.Request) {\n    conn, _ := upgrader.Upgrade(w, r, nil)\n    defer conn.Close()\n    fmt.Println(\"Client connected\")\n    \n    for {\n        _, msg, err := conn.ReadMessage()\n        if err != nil {\n            break\n        }\n        fmt.Println(\"Received message:\", string(msg))\n    }\n}\n\nfunc main() {\n    http.HandleFunc(\"\u002Fws\", handleWebSocket)\n    fmt.Println(\"WebSocket Server Running on Port 8080\")\n    http.ListenAndServe(\":8080\", nil)\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Client-Side Notification Subscription\u003C\u002Fh3>\u003Cp>File: \u003Ccode>\u003Cspan>client.js\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext\">async function registerNotification() {\n    const registration = await navigator.serviceWorker.register(\"\u002Fservice-worker.js\");\n    const subscription = await registration.pushManager.subscribe({\n        userVisibleOnly: true,\n        applicationServerKey: \"YOUR_PUBLIC_VAPID_KEY\"\n    });\n    \n    fetch(\"\u002Fgraphql\", {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application\u002Fjson\" },\n        body: JSON.stringify({\n            query: `mutation { registerNotificationToken(userID: 1, token: \"${subscription.endpoint}\") }`\n        })\n    });\n}\n\nregisterNotification();\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Challenge!\u003C\u002Fh3>\u003Cp>Try adding Group Notifications to ensure that everyone in the chat room receives alerts for new messages, even when the app is not open.\u003C\u002Fp>\u003Chr>\u003Ch3>Next EP\u003C\u002Fh3>\u003Cp>In EP.39, we will introduce a file upload feature in the WebSocket Chat, allowing users to share images and documents! 🚀\u003C\u002Fp>","48_11zon_urz9upo25y.webp","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Frirt3q4ggacbr0q\u002F48_11zon_urz9upo25y.webp","2026-03-04 08:51:13.961Z","",{"keywords":15,"locale":63,"school_blog":73},[16,23,28,33,38,43,48,53,58],{"collectionId":17,"collectionName":18,"created":19,"created_by":13,"id":20,"name":21,"updated":22,"updated_by":13},"sclkey987654321","school_keywords","2026-03-04 08:51:12.024Z","mfphds63msma911","Chat Alerts","2026-04-10 16:14:33.622Z",{"collectionId":17,"collectionName":18,"created":24,"created_by":13,"id":25,"name":26,"updated":27,"updated_by":13},"2026-03-04 08:48:07.088Z","brfbypclggbbkcx","WebSocket API","2026-04-10 16:13:40.594Z",{"collectionId":17,"collectionName":18,"created":29,"created_by":13,"id":30,"name":31,"updated":32,"updated_by":13},"2026-03-04 08:51:12.327Z","oe33epaljgufqzf","Web Push API","2026-04-10 16:14:33.793Z",{"collectionId":17,"collectionName":18,"created":34,"created_by":13,"id":35,"name":36,"updated":37,"updated_by":13},"2026-03-04 08:47:05.949Z","caufix9o52uw4bh","Real-Time Chat","2026-04-10 16:13:23.517Z",{"collectionId":17,"collectionName":18,"created":39,"created_by":13,"id":40,"name":41,"updated":42,"updated_by":13},"2026-03-04 08:20:14.253Z","ah6lvy4x8qe08l5","Golang","2026-04-10 16:07:26.172Z",{"collectionId":17,"collectionName":18,"created":44,"created_by":13,"id":45,"name":46,"updated":47,"updated_by":13},"2026-03-04 08:20:11.547Z","ey3puyme01a9bsw","Go","2026-04-10 16:07:25.893Z",{"collectionId":17,"collectionName":18,"created":49,"created_by":13,"id":50,"name":51,"updated":52,"updated_by":13},"2026-03-04 08:51:12.685Z","v6aqa9mkbj1i0fg","Firebase Cloud Messaging","2026-04-10 16:14:33.924Z",{"collectionId":17,"collectionName":18,"created":54,"created_by":13,"id":55,"name":56,"updated":57,"updated_by":13},"2026-03-04 08:34:00.920Z","ecac9y661or1xka","WebSocket","2026-04-10 16:08:05.227Z",{"collectionId":17,"collectionName":18,"created":59,"created_by":13,"id":60,"name":61,"updated":62,"updated_by":13},"2026-03-04 08:46:14.110Z","itovzjisctbn2ej","Push Notification","2026-04-10 16:13:10.376Z",{"code":64,"collectionId":65,"collectionName":66,"created":67,"flag":68,"id":69,"is_default":70,"label":71,"updated":72},"en","pbc_1989393366","locales","2026-01-22 11:00:02.726Z","twemoji:flag-united-states","qv9c1llfov2d88z",false,"English","2026-04-10 15:42:46.825Z",{"category":74,"collectionId":75,"collectionName":76,"expand":77,"id":91,"views":92},"wqxt7ag2gn7xcmk","pbc_2105096300","school_blogs",{"category":78},{"blogIds":79,"collectionId":80,"collectionName":81,"created":82,"created_by":13,"id":74,"image":83,"image_alt":13,"image_path":84,"label":85,"name":86,"priority":87,"publish_at":88,"scheduled_at":13,"status":89,"updated":90,"updated_by":13},[],"sclcatblg987654321","school_category_blogs","2026-03-04 08:33:53.210Z","59ty92ns80w_15oc1implw.png","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002F59ty92ns80w_15oc1implw.png",{"en":86,"th":86},"Golang The Series",1,"2026-03-16 04:39:38.440Z","published","2026-04-25 02:32:15.470Z","c4q538jp0bh7b49",223,"rirt3q4ggacbr0q",[20,25,30,35,40,45,50,55,60],"2025-03-17 02:09:14.580Z","Learn how to integrate Push Notifications into your WebSocket Chat using the Web Push API and Firebase Cloud Messaging (FCM) to alert users of new messages even when the application is not open.","push-notifications-websocket-chat","2026-04-22 07:11:45.014Z",{"en":97}]