June 02, 2019

Grey's Anatomy Lorem Ipsum Generator Tutorial

screenshot of grey's anatomy lorem ipsum generator

This tutorial is going to walk through how to create a Grey’s Anatomy or other-themed Lorem Ipsum generator. I’m a huge fan of the show, Grey’s Anatomy (and Shonda Rhimes in general) for a while so I was overdue for creating a Grey’s Anatomy-themed Lorem Ipsum generator. Lorem Ipsum is generated, nonsense text that is used in design and publishing as placeholder text. Traditionally, Lorem Ipsum is written with Latin words but there are variations that involve non-Latin words as well.

This tweet thread about being a Shonda Rhimes enthusiast https://twitter.com/waterproofheart/status/408430997517393920

The live version of the Grey's Anatomy Lorem Ipsum Generator website can be viewed here and the code for this tutorial can be viewed on Github.

Here’s an example of the type of text that is generated by the Grey's Anatomy Lorem Ipsum generator:

“real hospital Dr. Cristina Yang well a trauma surgical fellow badly chief of pediatric surgery George Ellis orthopedic surgeon Dr. Shane Ross approximately Dr. Callie Torres exactly Dr. Izzie Stevens Izzie chief of plastic surgery an anesthesiologist Meredith’s father Zola Seattle Erica certainly Meredith Dr. Shane Ross basically basically Tucker maybe Dr. Virginia Dixon whoever Chief Richard Sadie significantly nicely Arizona real very Dr. Colin Marlowe Zola mostly things Dr. Teddy Altman rather Arizona Dr. Teddy Altman Seattle Dr. Izzie Stevens my person”

The above paragraph makes absolutely no sense but if you’re familiar with Grey’s Anatomy there are some familiar terms baked in there.

Requirements

To get the most out of this tutorial you should:

  • Have familiarity with git and JavaScript
  • Have a GitHub or GitLab account (in order to use Netlify functions).

Table of Contents

Set Up

In order to jump-start this project, I used Netlify’s GitHub - netlify/create-react-app-lambda starter. Netlify is a hosting service that specializes in hosting JAMstack websites, as of writing this tutorial, has a pretty comprehensive free tier(Plans and Pricing | Netlify) that integrates well with deploying GitHub projects to the world wide web. JAMstack is used to describe static websites that are compromised of JavaScript, APIs, and Markup. You can learn more about what is or isn’t considered JAMstack here JAMstack | JavaScript, APIs, and Markup ,

The create-react-app-lambda repository integrates Netlify’s functions with create-react-app which means out of the box you can deploy a React application that calls, Serverless functions, which you may know as Amazon Web Services (AWS) Lambdas. These functions can make asynchronous calls and process data but they must be stateless, meaning that given the same inputs the output will be the same. With Netlify you can deploy and manage AWS Lambda’s technology without an AWS account. You can read more about Serverless Lambda Functions on Netlify here: Functions | Netlify.

Let’s get started by copying over create-react-app-lambda . Click on the “Deploy to Netlify” button in the README.

This one-click button allows us to set up React + Netlify Functions without having to do heavy lifting. Essentially when you click the button you are creating a new site in Netlify and a connected GitHub repository. It takes a few minutes for the GitHub repository to populate with the files but once it is done populating you should be able to visit Netlify and view your site. If you’d like a better understanding of why things were set up the way they were in the create-react-lambda-app then check out this video by Shawn Wang (swyx) for more context.

After clicking the "Deploy to Netlify" button you should see something like this:

Note: Comprehensive instructions for interacting with the create-react-lambda-app project live in the README. I will highlight the most important pieces to interact with the app but encourage exploring the README for more information and to further enhance the application.

So once the repository that you created in Netlify is populated with files from create-react-app-lambda you should git clone the repo. The repository that you are cloning should be named after the repo that you created, i.e., git clone git@github.com:your_username/app-just-created. You may have to refresh the repository page before the files are populated.

Once the project is set up you should cd into the project directory and run yarn to install all of the dependencies. You can run yarn test to ensure that all of the tests are passing and the project was set up properly.

The Netlify functions should be created in src/lambda. If you look in that folder there are two sample functions async-dadjoke.js and hello.js. For our use case we don’t need an async function so let’s look at the hello.js example

In hello.js we are getting the queryStringParameters from the event in order to log them. queryStringParameters can be accessed from the event like event.queryStringParameters or by destructuring the event object like const {queryStringParameters} = event.

export function handler(event, context, callback) {

  console.log(“queryStringParameters”, event.queryStringParameters)

  callback(null, {

    statusCode: 200,

    body: JSON.stringify({ msg: “Hello, World!})

  })

}

Every Lambda function has a handler function. This handler function can take event, context, and callback. The event is based on what the endpoint received when the request was made it can include things like cookie information, headers, queryStringParameters, etc. The context object provides additional insight regarding a Lambda’s execution. You can learn more in the AWS docs here: AWS Lambda Function Handler in Node.js - AWS Lambda

Verify Set Up

In order to tests the functionality of the endpoint we should run yarn start:lambda, in the directory we just clone, which will run all of your Lambda functions. And then you can visit http://localhost:9000/hello or / whatever the name of your function is. On this page, you should see: {“msg”:”Hello, World!”} since that is the body of the endpoint’s response.

Calling the Netlify function from React

Next, I would recommend customizing the naming conventions in the project to better fit your needs. I renamed hello to generate-lorem-ipsum, so first I rename thehello.js file to generate-lorem-ipsum and then in the LambdaDemo component in app.js , I replaced the call to hello on button click to generate-lorem-ipsum . While I was there I also deleted the button related to async-dadjoke and removed the associated file. So I went from

<button onClick={this.handleClick("hello")}>{loading ? "Loading..." : "Call Lambda"}
</button>

<button onClick={this.handleClick("async-dadjoke")}>{loading ? "Loading..." : "Call Async Lambda"}
</button>

to:

<button onClick={this.handleClick("generate-lorem-ipsum")} className=“button”>
            {loading ? “Loading…” : “Generate Lorem Ipsum”}
</button>

The button is calling the Netlify function on click, you can look at the handleClick for more information about what happens when you click on the button, initially It returns loading as the state and then eventually the response.msg.

Note: I updated references to LambdaDemo() to LambdaCall()in App.js because it’s show time!

In order to check the lambda is still being called and returning a response you should run yarn start (while yarn start:lambda is running in another terminal window). You should be able to visit http://localhost:3000 and see the React app with a “Generate Lorem Ipsum” button. If you click then the words “hello world” should appear on the site below the button.

Adding Lorem Ipsum Logic

So now we need to edit the generate-lorem-ipsum.js file so that it returns Lorem Ipsum and not “Hello World”. We will achieve this by creating a word bank of terms in words.js and the following functions in the generate-lorem-ipsum.js file: handler() generateLoremIpsum() generateWords() generateParagraphs() getRandomInt()

The handler() is the entry point into the file, therefore any functions that need to execute should either be called in the handler() or called by the functions that the handler() calls. First, we destructure the event to get the queryStringParameters.

For example, if someone calls our endpoint with the following query string parameter /generate-lorem-ipsum?paragraphs=4&words=0

Then we would de-structure the event object to determine that the endpoint was requested to return 4 paragraphs and 0 words.

const event = {
queryStringParameters: {
paragraphs:4,
words:0}
};

The handler will call a function generateLoremIpsum to actually handle generating the text, it takes in whether or not multiple paragraphs or just words should be returned. By default if there are no queryStringParameters it will return 4 generated paragraphs.

The handler() could end up looking something like this:

export function handler(event, context, callback) {
  const { queryStringParameters } = event
  const { paragraphs = 0, words = 0 } = queryStringParameters

  let isParagraph = Boolean(paragraphs)
  let count

  if (paragraphs > 1) {
    count = paragraphs
  } else if (words > 0) {
    count = words
  } else {
    isParagraph = true
    count = 4
  }

  let response
  try {
    response = isParagraph
      ? generateLoremIpsum(isParagraph, count).join(" ")
      : generateLoremIpsum(isParagraph, count)
  } catch (error) {
    console.log(error)
  }

  callback(null, {
    statusCode: 200,
    body: JSON.stringify({ msg: response }),
  })
}

In this example generateLoremIpsum() is a function called by the handler() and used as a fork in the road to determine if multiple paragraphs should be generated or just one based on if isParagraph is true or false.

export function generateLoremIpsum(isParagraph, count) {
  if (isParagraph) {
    console.log(`Trying to construct ${count} paragraphs`)
    return generateParagraphs(count)
  } else {
    console.log(`Trying to return ${count} words`)
    return generateWords(count)
  }
}

If we are generating a single paragraph the generateWords() will be called directly. This function creates an array of random words (based on getting a randomInt and adding the word at that index to the array until we reach the desired wordCount. In order to format the words once we have all of the words the words are formatted like const formattedWords = <p>${words.join(" ")}</p>;` in order to easily be able to transform the function’s response into an HTML paragraph later.

export function generateWords(wordCount) {
  let words = []
  console.log(wordCount)

  for (var i = 0; i < wordCount; i++) {
    words.push(WORDS[getRandomInt()])
  }
  const formattedWords = `<p>${words.join(" ")}</p>`

  return formattedWords
}

The random int in the generateWords() function is calculated with the following function:

export function getRandomInt() {
  return Math.floor(Math.random() * Math.floor(WORDS.length))
}

In the case where we are generating paragraphs we need the function generateParagraphs(). This function will generate X paragraphs with 50 words until it reaches the paragraphCount. It does this by calling the generateWords() function X times where X equals the paragraphCount that was passed in.

export function generateParagraphs(paragraphCount) {
  let paragraphs = []
  for (var I = 0; I < paragraphCount; I++) {
    paragraphs.push(generateWords(50))
  }
  return paragraphs
}

In order for any of the above to work we need a word bank to draw from. At the top of generate-lorem-ipsum.js we should import { WORDS } from "./words"; and then in the same directory create a file called words.js. In words.js we are going to create an array called WORDS and export it so that other functions can read it.

I created an array with just filler words( fillerWords) and another with Grey’s Anatomy and medical terms (greysAnatomyWords). Used ES6 spread operator to combine the arrays into one. export const WORDS = […greysAntomyWords, …fillerWords];

The full file should look something like:

const greysAnatomyWords = ["Meredith Grey", "Shonda Rhimes", "Epi", "Cardio"]

const fillerWords = [
  "actual",
  "actually",
  "amazing",
]`export const WORDS = […greysAntomyWords, …fillerWords];`

Methodology

In a full blown project we would need a lot of words or else it will be too repetitive. If you want to create another type of themed Lorem Ipsum then you would replace the greysAnatomyWords with words from a theme of your choice.

For the grey’s anatomy words I brainstormed and also found some lists like this Grey’s Anatomy Baby Names article that I was able to re-purpose. The process of cleaning up the data and formatting into valid JSON can be a bit tedious, I did find and replace for formatting where I could and some manually updating as needed. This allowed me to get as much data as possible with minimal effort (I.e., automating the scraping of terms). I ended up with about 140 terms for my generator but if I needed a larger data set then it may have made sense to consider exploring a tool like BeautifulSoup or Selenium to automate scraping a data source and saving that data into a valid JS file.

Note: Depending on how repetitive data is can create Map or filter to make sure that the array of words only has unique values.

I decided to add in filler words so that the generated Lorem Ipsum text would have a healthy mix of verbs and adverbs in addition to the themed. I Google’d filler text and found the following repository, I copied the filler words from there: fillersdata.txt at master · wordsfillers · GitHub

Now if you run yarn start:lambda and visit http://localhost:9000/generate-lorem-ipsum/you should see 4 generated paragraphs of lorem ipsum returned. It should look something like:

“msg”:”<p>especially surgicial mostly try hospital anyway Seattle Dr. Lucy Fields Alex a trauma surgical fellow Dr. Mark Sloan my person heavily wherever Theodora Duquette Dr. Virginia Dixon cried a nurse a neurosurgeon really Margaret Dr. Mark Sloan Dr. April Kepner Meredith’s father literally Dr. Alex Karev Dr. Izzie Stevens an anesthesiologist Denny much necessarily Surgery a trauma surgical fellow surely hardly Owen rather Shepherd totally cried chief of pediatric surgery Theodora Dr. Robert Stark Olivia an anesthesiologist get her up to CT actually Cristina Dr. Finn Dandridge</p> <p>Tucker Virginia Callie Torres mostly hardly Maggie Maggie get her up to CT hardly get him up to CT quite stuff Dr. Mark Sloan whenever Dr. Richard Webber try George amazing Dr. Sydney Heron Dr. Jackson Avery actual quite nicely Richard stuff might Dr. Owen Hunt get her up to CT orthopedics Yang obviously mostly intubate her wherever orthopedic surgeon typically Margaret Karev effectively Alex Dr. Mark Sloan Seattle Dr. Alex Karev push one of epi try practically Dr. Alex Karev intubate him so</p> <p>start significantly start fairly get him up to CT slightly Dr. Alex Karev chief of plastic surgery slightly Dr. Robert Stark Meredith’s mother Norman actually completely Izzie Dr. Mark Sloan particularly Alex basically Adele clearly like usually Seattle Dr. Alex Karev typically chief of plastic surgery get him up to CT essentially ultimately my person exactly Norman specifically Virginia effectively O’Malley intubate her Virginia Tucker my person a surgery resident largely most a veterinarian basically she’s in V-Fib try simply Seattle</p> <p>heavily Dr. Callie Torres essentially Dr. Jackson Avery whoever a nurse Dr. Mark Sloan definitely my person Olivia Harper Dr. Alex Karev essentially approximately generally my person exactly Dr. Miranda Bailey Dr. Preston Burke right a plastic surgeon Norman Theodora basically a cardiac surgeon chief of plastic surgery chief of plastic surgery essentially Dr. Jackson Avery Tyler Christian much seriously Meredith’s mother slightly easily Mark my person maybe Mercy West Alex Erica Derek certainly badly rather hospital Denny Dr. Norman Shales Dr. Lexie Grey significantly Dr. Jackson Avery</p>”

Formatting Response

This blob of text is not formatted yet but we will worry about that in the React app. So let’s switch back to app.js . We are already printing the messages if you run yarn start and go to localhost:3000 you will see the same body text we just saw. Let’s use a library to format the response as actual HTML.

We will use the “html-react-parser” package. It can be installed by running yarn add html-react-parser and then add this import parse from “html-react-parser”; to the top of your app.js file in order to import it. Instead of just returning the msg in LambdaCall let’s replace msg with {msg && parse(msg)}. This says to parse the HTML of the msg and return it whenever there is a msg.

This part of the tutorial is choose-your-own-adventure. After setting up the Lorem Ipsum text generation logic. I went on to prettify the site to make it look more customized than the standard create-react-app boilerplate. One of the tools I used was this fancy button generator. I recommend playing around with the CSS until it matches the aesthetic that you want.

Deploy

Thanks to Netlify’s continuous deployment, if you clicked the “Deploy to Netlify” button on the first step then your website will be deployed to once you merge your changes into the master branch of your project’s repository. Also, if you open a pull request Netlify will generate a preview. This should mirror what you see when running the site locally.

The final code can be viewed on the loremIpsumTutorial branch of the greys-anatomy-lorem-ipsum-generator repository.

Please share with me on Twitter, @waterproofheart if you end up creating a Lorem Ipsum generator or another app with the Netlify functions after reading through this tutorial.

If you learned something from reading "Grey's Anatomy Lorem Ipsum Generator Tutorial" consider sharing it.
LinkedIn

Hi, I'm Monica! I'm a Full Stack Engineer who is currently building technology to bring people together IRL at Meetup and focusing on growing the React Ladies community for women + non-binary React developers. I'm interested in discussing React, JAMStack, open-source, tech inclusion, automation and more. 🍿