APIs

表情包

Christian Grewell
applab 2.0
15 min readApr 23, 2019

--

https://stickerpicker.herokuapp.com/

Introduction

Up until now, building interactivity into the front-end of our web applications has required that we pass some props (in the form of variables, objects or functions) and manage state between and amongst our React components. More importantly, our applications are truly independent and portable — they don’t require an internet connection and they don’t interact with other applications or sources of data.

We’ve used the ReactJS library itself to add more functionality and features to our application, but these are static libraries. You import or npm install them and they’re available for you to use anywhere, again, without an internet connection.

Is this boring? Not necessarily, but the web is a dynamic place and there are a lot of awesome sources of data out there that you can use to make your applications more interactive, interesting and powerful. One way to do this is to incorporate an API into your app.

What is an API?

https://developers.giphy.com/

First of all, API stands for Application Programming Interface. In general, most websites and web apps hide their source code (the secret recipe) from the world. That said, many sites still want to engage with their community and provide standardized ways for them to interact with their service. Most of the time, this standard way of interacting is via an API, and it’s one of the main catchall terms used to describe how one web app talks to another web app.

Why is it useful?

APIs are extremely useful, partially because similarly to how we leverage libraries such as P5.js or d3.js to create cool sounds or visualizations on the web, we can also leverage APIs provided by other websites, individuals or collectives to do stuff — show a random cat fact, or get a list of all tweets tagged as#catfacts, then add them to our state and display them in a realtime list.

The advantage for you as an app developer is that you get a bunch of new, cool features in your application for free, while the API provider gets to promote their platform.

What does an API Look Like?

This depends on the API provider, but most will provide documentation and examples describing how to implement their API in your web application. For example, we’re going to be making a simple React app that returns a random sticker using the Giphy API’s Random Sticker API Endpoint (an endpoint is the URL you pass parameters to).

Most APIs will return to you a JSON object — basically a JavaScript-like object (see the end of the article for an explanation of JSON), or others, like the Giphy API we’ll use in this article will return a JavaScript object. There are not a lot of differences between the two (really only two small ones) but it’s worth talking now about JSON so that when you see it later, you’ll have some idea of what it means and why it’s useful.

Requests and Responses

In general, APIs expect you to send a request, formatted in a particular way, to a URL that they publish (often called an endpoint) that accepts requests. Once they receive an authorized requestin the format they expect, they’ll send you back a response, normally formatted similarly to a JavaScript object, that you can use in your application (either for logic, or to display). This request — response pattern is repeated throughout the internet, and is a helpful way to thinking about what you’ll be doing.

Let’s Build a Sticker Search Engine

If you can use a picture to solve something, then you don’t need to speak

Go here to see what we’re going to build: https://stickerpicker.herokuapp.com/

For this example, I thought I would try and solve a problem that I have. In China, there is a popular messaging app called WeChat. One fun feature it has is the ability to send animated stickers to people in lieu of text or audio. It’s quite popular (about 90% of the internet-using population of China uses it for most of their daily online communications).

In WeChat chat threads, once you see a sticker you like, you can long-press and choose to save it to your collection. If you want to add a sticker you made yourself, it can be a little bit difficult, and involves a lot of steps. That’s what I’d like us to be able to solve.

How?

For this app, I want us to be able to use the GIPHY API to search for stickers that match a term we enter in an input field, furthermore, I want to be able to only show those stickers that are small in size (WeChat limits the file size of stickers to 1MB)

The best part is that this application will be able to be used on my mobile, so I can easily choose to forward the stickers it finds directly to my friends. I am a simple man who likes simple apps — a user can simply enter a search term in an input box, press a button and receive a list of matching stickers. That’s it.

Step 1: Clone the git repository from our prior lab:

$ git clone https://github.com/clg236/stickerpicker.git
$ cd stickerpicker
$ npm install
$ npm start

Our Layout

Since this is a React app, let’s start by identifying our component relationship and what each part will do. We can start by building off ofthe prior lab’s project, with a few edits of course.

Here’s the amazing app we made in the prior lab, and here’s what we’ll create today

What do we need to change?

  • Instead of adding whatever the user types in the input component to our App’s state and displaying a new entry in our App, we want to take the input and use it as the search term input to the Giphy API.
  • We’ll need to rename the button text
  • We’ll need to do some additional styling in CSS

Handling the Search Box

First piece of functionality we are going to change is how to handle passing the search term from the InputComponent to the App component as well as updating the the state we’ll need in order to pass some meaningful terms to the Giphy API.

Recall from the last lab, we have an App component that renders an InputComp and passes it a prop called submit.

Here’s the Input Component:

Let’s break this InputComp down.

  • Lines 2–6: This is our constructor, it’s called once every time the component is added to our App (which is one time in this case, because it’s our input field). It creates a state in our app with a single string variable called currentWord
  • Lines 9–13: This is our updateWord function, it takes in an argument called (event) and then calles the setState function to set our currentWord variable in the state to whatever is passed in from event.target.value (which is normally whatever is typed in a field).
  • Lines 15–17: This function, when called executes another function that’s passed down in the form of a prop called submit, and passes that function the value of our currentWord variable in the state.
  • Lines 19–26: This part of the component renders two HTML elements. An input, that when changed calls the updateWord function on line 9, and a button, that when clicked calls the submitWord function on line 15.
  • Our App component renders our Input component with a prop of submit, passing the InputComp its own findGifs function as an argument.

What should we change?

only one thing!

Remember how we mentioned to you that the pattern we were using last week was very flexible, well the only one thing that we need to change here, is to add a bit of code to stop our page from reloading. This is called preventDefault, which is a method that will prevent the default action of refreshing our page when we hit the submit button from occurring:

In order to use this new function, we need to make a change to our submitWord function to take in an event, and then to call the preventDefault()function on that event:

submitWord = (event) => {
this.props.submit(this.state.currentWord);
event.preventDefault();
}

That’s it for the input component. Now, let’s make a change in our App component to handle the search term that people will enter.

Working with the API

Now that we have our search input working (at least it’s updating state and passing data back to our App’s addWord method, let’s make the changes we need to make to begin passing (our request) and receiving (Giphy’s response) data from our API.

To use the Giphy API, we’re going to need a way to send and receive data within our React app. There are a ton of ways to handle making HTTP requests, all of them use a library or built-in functions. Here are few popular ones:

I’m choosing SuperAgent for this example, mainly because after trying all of them, I found it to be the easiest to use and understand. To install SuperAgent in your React project, simply run the following within your project’s directory:

$ cd yourprojectdirectory
$ npm install --save superagent
I should really update my npm packages

Now, to use Super Agent we need to add it to our React project. In your App component, simply import it!

import React, {Component} from 'react';
import './App.css';
import Headline from './Headline.js';
import InputComp from './InputComp.js';
import superAgent from 'superagent'; //here's how we can import

Now, you’ll be able to access functions inside of this package by simply writing: superAgent.functionnamehere for example, we’ll use the get function by calling superAgent.get()to fetch data from the Giphy url and do something with the response.

Review the GIPHY API

Before we can write the code that will help us populate our sticker search, we’ll need to review the Giphy API to see what’s possible and appropriate.

It looks like we’ll need 3 things in order to make this work:

  1. an API key (which means we’ll need to ‘create an app’ on their portal)
  2. an endpoint (looks like their sticker search endpoint at /v1/stickers/search looks perfect.
  3. the terms we want to search for (comes from our Input component)

Create an Account

If you don’t already have one, create an account at https://giphy.com/join/:step?

Very cool, they have a non-binary option for gender

Create an App

After logging in, create an App at https://developers.giphy.com/dashboard/

Give your app a name and description, this is useful if you want to apply to Giphy to make your application into a production application (which means you can make more requests per second, etc…)

Next, copy down your API Key (you’ll need it in order to make requests to the Giphy API)

Now that we have our API key, we can move on to implementing the search function in our sticker API

Implementing Search

Before we can implement the search, we need to understand the structure of the data that we’ll be receiving back from the API

Giphy provides a nice API explorer for us to see which of their APIs might be suitable for our app, as well as to see what the data structure that results from our queries:

Search, Discover, Share, and Create Animated GIFs | GIPHY
GIPHY is your top source for the best & newest GIFs & Animated Stickers online. Find everything from funny GIFs…developers.giphy.com

This is an excellent way to understand behaviors and data before wasting too much time console.log’ing.

The Request URL is especially useful, as it tells us exactly how to format our API request.

https://api.giphy.com/v1/stickers/search?api_key=&q=bunnies&limit=25&offset=0&rating=G&lang=en

Refactoring Our Input

In the prior lab, we had an input component that updated state and then submitted state up to our App component when we pressed the Submit button. In this new app, we want to so something similar, we want to keep track of what the user is typing, then when they press the Give Gif button, we want to pass whatever is typed into the Input Component up to our App.

Let’s take a look at the addWord function in the prior lab:

addWord = (newWord) => {
let newWords = this.state.words.concat(newWord);
// overwrite the current words in our state
// with the updated one
this.setState({
words: newWords
})
}

This function is taking in an argument from our Input Component (newWord) and then concatenating it into our existing words array in our state. We should change this to reflect the new functionality. Which is:

  • We want to receive our search term
  • Then pass the search term along with our API key to the Giphy URL endpoint.
  • Then receive data back from the Giphy API
  • Then add the URL for a Gif to our state.

Let’s make a few changes to our function to accommodate these new features. See if you can do these before moving on:

Challenge 1:

  1. Rename the function to findGifs and change the argument to term
  2. Create a const string variable called url that holds our URL and uses the term argument you’re passing instead of a regular search term (hint: check out the Giphy API Explorer to see how to format the URL.
  3. Now use Super Agent to request data from the API and log the result to the console. This part is tough, but check out their documentation here: https://visionmedia.github.io/superagent/

hint: for step 3, simply try to console.log the result from the Super Agent’s get function, you don’t need to worry about .catch.

Run your app and type something in, then check your console. Do you see any response?

solution is below

.

.

.

.

.

.

.

.

.

.

.

.

.

are you sure you want to peak?

.

.

.

.

.

.

did you try copy-paste from the SuperAgent Request Basics?

.

.

.

.

.

okay!

.

Solution:

Here’s the new findGifs function.

findGifs = (term) => {
const url = `//api.giphy.com/v1/stickers/search q=${term}&api_key=SWq0akBClfv0noc1kvCvN8bCBGAKqAZG&limit=10`;
//use superagent
superAgent.get(url).then(res => {
console.log(res);
});
}

After importing SuperAgent, we can use their request object to make an API call within our handleInputSubmit method, since that's receiving the termfrom our Input Component.

We’re setting a const named url with all three things we said we needed to make an API call: (1) the endpoint, (2) our API key and (3) our search term.

Finally, we’re making a get request using SuperAgent to the URL we specified (the Giphy sticker API URL endpoint). You can find out more about how to make requests with SuperAgent in their documentation, but for now, we're going to keep it as simple as possible.

Let’s go ahead and search for something in our Input component and open the console. You should get something back from the Giphy API!

From the console we can see that the request comes back as an Object, and it looks like the meat of the Gif is inside the body > data child.

Challenge 2:

  • Make a change so that only one of the Gif URLs is returned instead of the entire Object.
  • Click on some of the links in your console to make sure they return a valid sticker.

This should about 5 minutes!

Got it? Here’s my version:

findGifs = (term) => {
const url = `//api.giphy.com/v1/stickers/search q=${term}&api_key=SWq0akBClfv0noc1kvCvN8bCBGAKqAZG&limit=10`;
//use superagent
superAgent.get(url).then(res => {
console.log(res.body.data[0]);
});
}

Let’s refactor our code to pass the Giphy sticker data into our App components state via this.setState.

What’s in our app’s state?

constructor(props) {
super(props);
this.state = {
words: ['paradise', 'bicycle', 'jianbing', 'timezone', 'hotdog', 'dog'],
}
}

Obviously this won’t work. Instead, we’re going to want to store whatever comes back from our API call to Giphy in our state, then we can access the Gif image URLs in our map function later.

Challenge 3:

  • Create a new state for your App component to hold the gif objects that are returned from the API.

.

.

.

.

.

.

.

.

.

.

.

Solution:

constructor(props) {
super(props);
this.state = {
gifs: [],
}
}

Yup. That’s it. We just need an empty array. Our findGifs function will fill this up every time it’s called!

Update our findGifs function

Don’t forget that we now want to populate our state with the data returned from our API call.

this.setState({ gifs: res.body.data})

Update our Render Component

The last and final step is to update our render method to display the gif URLs in our state. We can actually keep a lot of our existing map function intact! We just need to make a few changes to dig deeper into the javascript objects in our state that contain the URLs. Let’s think about what needs to change:

  1. We’ll need to display images instead of just text. We can us the <IMG> tag for this
  2. We need to dig down into the object to access the correct URLs for the Gifs that we want (we want the smallest ones in order to make sure we can send them over WeChat, which only accepts 1MB or less)

We’ll need to update the map function to return a <div> full of gifs instead of the <p> tags we had previously:

<div className="display">
{this.state.gifs.map((gif) => {
return (
<div className="box">
<img src={gif.images.downsized.url} width="200" height="200" /
</div>
);
})
}
</div>

Advanced Challenge:

  • Edit the sticker engine to only return GIFs that are equal to or smaller than 1MB in size (which just so happens to be the limit that WeChat places on sticker sizes…hmmmmmm). Hint, recall the console.log from when we returned a single Gif object from the API for hints.

That’s it! This was a long article, but I hope it was worthwhile and useful, especially for those who would like to integrate APIs into their projects. There are a lot out there:

toddmotto/public-apis
A collective list of public JSON APIs for use in web development. — toddmotto/public-apisgithub.com

What is JSON

JSON stands for JavaScript Object Notation. It’s a data format that you should be familiar with already as we’ve been writing its syntax all along, with the only difference being that in JSON, values are enclosed in quotes:

{
"name": "Dog",
"breed": "Labrador Retriever",
"color": "Yellow",
"age": 6
}

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition — December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers.

JSON is built on two structures:

  • A collection of name/value pairs.
  • An ordered list of values (e.g., an object, an array, boolean, number, string, null).

How is JSON Different from a JavaScript Object

JSON very similar to a JavaScript objects. But there are differences, according to the spec:

“JSON is a text format that facilitates structured data interchange between all programming languages.”

So it’s universal, this has nothing to do with JavaScript other than the name and the fact it was derived from the way JavaScript objects are written.

In terms of the syntax itself, there are a few major differences. First, all names (keys) are represented as strings (i.e. they need to be inside quotes). So the following is not valid JSON:

// not valid JSON, but valid as JS object 
{
name: "Bob Ross"
}

If we wanted to make this valid JSON, a simple change:

// not valid JSON, but valid as JS object 
{
"name": "Bob Ross",
"occupation": "celebrity painter"
}

According to the specification, a JSON value can only be text, so you can’t pass it a JavaScript function. The following are all valid value types in a JSON object (file):

  • Object
  • Array
  • Number
  • String
  • true
  • false
  • null

Last thing, just like JavaScript Objects, a JSON object can also have nested key/value pairs, just be sure to include the “” syntax:

// This is VALID
{
"species": "Dog",
"breed": "Labrador Retriever",
"age": 6,
"traits": {
"eyeColor": "brown",
"coatColor": "yellow",
"weight": "137lbs"
}
}

How to Handle JSON Returned from APIs

Many APIs, not all, will return (require) a JSON object to (from) your application after you’ve successfully (or unsuccessfully) interacted with it. Your task then is to transform the data you are sending or receiving into one that will be recognized by the API or your application.

JavaScript provides two built-in methods to do this. JSON.parse() and JSON.stringify(). Can you guess which is useful for outbound API calls and which one is useful for inbound API data?

--

--

Christian Grewell
applab 2.0

Hi! My name is Christian Grewell, I grew up in Portland, Oregon playing music, programming video games, building computers and drinking coffee. I live in China.