DEV Community

loading...
Cover image for Facebook post preview with ReactJS and AWS Lambda

Facebook post preview with ReactJS and AWS Lambda

Hugo Dias
Software Engineer
・2 min read

I'm currently focused on learning more about React. For me, the best way to learn something is to build a small project that's not a todo list (lol).

That being said, I've decided to build a small app that receives an URL, fetch the meta tags (especially the open graph tags) and build a preview based on facebook.

To accomplish this task I've chosen ReactJS and AWS Lambda (hosted on Netlify).

The Lambda function

The lambdas task is pretty simple. Receive an URL, parse and fetch the meta tags, looking for the Open Graph tags.

The open-graph-scraper npm package almost got the entire job done, so here is the final code of the lambda:

import ogs from "open-graph-scraper";
import getUrl from "get-urls";
import urlParser from "url";

export function handler(event, context, callback) {
  const text = event.queryStringParameters.q;
  const urls = getUrl(text);

  // Return if there is no urls in text
  if (!urls.size) {
    return callback(null, {
      statusCode: 200,
      body: JSON.stringify({
        text: text,
        meta: null,
        error: ["Empty url in text"]
      })
    });
  }

  // Retrieve first URL in text - urls are already normalized
  const url = [...urls][0];
  const options = { url };

  ogs(options, (error, results) => {
    const statusCode = results.success ? 200 : 500;
    callback(null, buildResponseObject(statusCode, results, text));
  });
}

function getUrlDomain(url) {
  const urlObj = urlParser.parse(url);
  return urlObj.host;
}

function cleanText(text) {
  return text.replace(/(?:https?|ftp):\/\/[\n\S]+/g, "");
}

function buildResponseObject(statusCode, result, text) {
  let meta = statusCode === 200 ? result.data : null;

  if (meta) {
    let images = meta.ogImage;

    if (images instanceof Array) {
      meta.ogImage = images[0];
    }

    let domain = meta.ogUrl;

    if (domain) {
      meta.ogUrl = getUrlDomain(meta.ogUrl);
    }
  }

  const body = {
    meta: meta,
    text: cleanText(text),
    error: statusCode !== 200 ? result.error : null
  };

  return {
    statusCode,
    body: JSON.stringify(body)
  };
}
Enter fullscreen mode Exit fullscreen mode

The Frontend

As I mentioned at the beginning of the post, react was chosen to build the client interface.

The packages used are:

  "dependencies": {
    "get-urls": "^7.2.0",
    "netlify-lambda": "^0.4.0",
    "open-graph-scraper": "^3.3.0",
    "react": "^16.4.1",
    "react-content-loader": "^3.1.2",
    "react-dom": "^16.4.1",
    "react-scripts": "1.1.4",
    "styled-components": "^3.3.2"
  },
Enter fullscreen mode Exit fullscreen mode

And here is the result:

screenshot

Contributing

It's free and open source!

The code is hosted on Github and you can see it in action here.

I'm looking forward to your feedback, folks.

Thanks

Discussion (9)

Collapse
shtefcs profile image
Stefan Smiljkovic

Nice work, we could use this for moon.ly our open source project, since current data grabber is failing on some sites. I just compared with your tool:

Moonly: i.imgur.com/fdrmfaw.png
OG grabber: i.imgur.com/WuuC0mo.png

In case you want to contribute, check this github.com/Moonly-App/moonly-exten...

Also, this is how your website looks in mirror i.imgur.com/LkBDhXd.png :D.

Collapse
dance2die profile image
Sung M. Kim • Edited

Ah, this is a nice site.

Using your site, I found out my home page looks boring without an image.

preview

Collapse
hugodias profile image
Hugo Dias Author

Hahahah it’s time to fix it! :)

Collapse
dance2die profile image
Sung M. Kim

Definitely.

And also, may I request for more meaningful sub-domain?
(So others can find & memorize easily?)

Netlify lets you set it like below.

edit site name

Thread Thread
hugodias profile image
Hugo Dias Author

Oh yes! Thanks for the tip. Just changed it to facebook-preview.netlify.com/

:)

Thread Thread
dance2die profile image
Sung M. Kim

🎉 Yay!
You're welcome
& and much appreciate the name change ✌️

Collapse
guidovizoso profile image
Guido Vizoso

That's a really good project to learn React and the final result is awesome. Keep the good work!

Collapse
andy profile image
Andy Zhao (he/him)

Awesome! This is like Twitter's card validator:
cards-dev.twitter.com/validator

Except much more up-to-date :)

Collapse
pavanbelagatti profile image
Pavan Belagatti

This is going to help most of the marketing folks out there to see how their article is going to look. Good job there