Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Workshop: Intro to Node/Express part 2

Workshop: Intro to Node/Express part 2

Sides for Women Who Code, Intro to Node/Express workshop part 2

Wai-Yin Kwan

May 10, 2016
Tweet

More Decks by Wai-Yin Kwan

Other Decks in Technology

Transcript

  1. What is API? • API: application programming interface • set

    of rules ('code') and specifications that software programs can follow to communicate with each other. (Stack Overflow) • many sites offer apis so that developers can grab and update data. • While visiting a normal page, server sends back html. While connecting to apis, server sends back data as json or xml. • json vs xml: http://www.developingthefuture.net/difference- between-json-and-xml/
  2. jsonview • browser plugin to view json in the browser

    • Firefox: http://jsonview.com/ • Chrome: https://chrome.google.com/webstore/detail/ jsonview/chklaanhfefbnpoihckbnefhakgolnmc
  3. Github API • the github api allows you to retrieve

    and update information about users, repos, searches, etc • https://developer.github.com/v3/ • to get info about a user • https://api.github.com/users/:username • to get a user repos • https://api.github.com/users/:username/repos
  4. How to connect to APIs? • in order to connect

    with apis, we need to install a library to can make http calls. • We are using axios. Other options include request and super agent. • axios is promise based http client • https://github.com/mzabriskie/axios
  5. What is asynchronous? • javascript is asynchronous language. languages like

    python, ruby are synchronous languages. • there are some actions that take a long time to complete (making network requests, getting data from database, etc) • in synchronous code, you start a task, wait for the task to finish, then moving to the next task. • in asynchronous code, you start a task, and move onto the next task. Eventually the first task will finish.
  6. What is asynchronous? • here is an fake code example.

    connect is an imaginary function that connects to websites. synchronous data = connect(‘http://example.com') // code waits until connection is completed… // finished connecting with site print (data) // prints the data asynchronous data = connect(‘http://example.com') // code immediately goes to next line print (data) // prints nothing because connect isn’t done // finished connecting with site
  7. What are callbacks? • callbacks are a way to deal

    with asynchronous code • we pass two arguments to connect: a url and a callback function. • the callback function will be executed after the connect is completed connect(‘http://example.com’, function(data) { // finished connecting with site print (data) // prints the data } )
  8. What are promises? • promises are another way to deal

    with async code • A Promise represents an operation that hasn't completed yet, but is expected in the future. (Modzilla Developer Network) • connect returns a promise. connect('http://example.com') .then( function(results) {} ) .catch( function(error) {} )
  9. What are promises? • When the action is successfully completed,

    the promise is fulfilled. The result from the action is passed to the function in then(), and the function is executed. • If the action is not completed, the promises is rejected. The error is passed to the function in catch(), and the function is executed. connect('http://example.com') .then(function(results) { // finished connecting with site print (results) // prints the results }) .catch(function(error) { // error handling code })
  10. Step 8 var axios = require('axios'); var port = process.env.PORT

    || 3000; app.get('/projects', function (request, response) { var options = { headers: { 'User-Agent': '<username>' } }; axios.get('https://api.github.com/users/<username>', options) .then(function (results) { console.log(results.data); }); response.render('projects', { title: 'My Projects' }); }); server.js
  11. Github API • When we connect to Github API, Github

    requires you to include an User-Agent in the http header. • we are going to use our username as the User-Agent. • https://developer.github.com/v3/#user-agent-required • http headers: http://code.tutsplus.com/tutorials/http-headers-for- dummies--net-8039 var options = { headers: { 'User-Agent': '<username>' } };
  12. Step 8 axios.get('https://api.github.com/users/<username>', options) .then(function (results) { console.log(results.data); }); •

    We use axios.get() to connect to the api • .get() returns an object. The object contains information about the server response and the data from the api. To access the api data, use results.data. • We will console.log the results. When you reload the projects page, you should see the github user info in the terminal
  13. Step 9 axios.get('https://api.github.com/users/<username>', options) .then(function (results) { response.render('projects', { title:

    'My Projects’, bio: results.data }); }); • Instead of console logging the bio, we want to render the bio in the template <h1>My Projects</h1> {{ bio }} server.js projects.hbs
  14. Step 9 • The browser will display something like: •

    We are passing an object to the template. Handlebars automatically converts objects into strings. When it converts an object to a string, it turns the object into “[object Object] • in order to see all the keys/values in the object, we need to convert the object into json My Projects [object Object]
  15. What are handlebars helpers? • handlerbars allow you to create

    functions that will manipulate the data in the view • http://handlebarsjs.com/expressions.html#helpers
  16. Step 9 • We will create a Handlebars helper that

    will turn an object into json. app.engine('hbs', exphbs({ extname: 'hbs', defaultLayout: 'main', layoutsDir: './views/layouts', helpers: { json: function (context) { return JSON.stringify(context); } } })); server.js
  17. Step 9 • The name of the helper function is

    “json”. • The function will take the data (aka context) that is pass in, and return json helpers: { json: function (context) { return JSON.stringify(context); } }
  18. Step 9 • to use handlebars helpers, add the name

    of the function (json) and the data we pass to the helper function (bio) • when we reload the browser, you should see the bio data <h1>My Projects</h1> {{ json bio }} projects.hbs
  19. What is rate limiting? • Many APIs limit the number

    of requests a user can make • Github rate limits • unauthenticated requests can make 60 requests per hour • authenticated request can make up to 5,000 requests per hour • https://developer.github.com/v3/#rate-limiting
  20. Create Github token • to make authenticated requests, we need

    a Github token • https://github.com/settings/tokens • click “Generate new token” • add a name to “Token description” • click “Generate token” • copy token
  21. Step 10 • add Authorization to the headers, and paste

    in your token var options = { headers: { 'User-Agent': '<username>', Authorization: 'token <your token>' } }; server.js
  22. What are environmental variables? • some info (passwords, tokens) are

    supposed to be secret, so don't put them in your app code and don't commit them to git • we create a variable to represent the secret info, and then store the value somewhere else • For Node, one solution is to use a library called dotenv. • dotenv loads information you put in a .env file into Node's process.env. • process.env contains all the configuration (aka environmental variables) for the server • https://github.com/motdotla/dotenv
  23. Step 10 • add .env file to the root of

    the project • .env will have KEY=value pairs • paste the token into .env • add .env to .gitignore so the token won't added to git GITHUB_TOKEN=<your token> node_modules .DS_Store .env
  24. Step 10 • replace the hardcode token with the variable

    • make sure there is a space after the word ‘token ‘ var axios = require('axios'); require(‘dotenv’).config(); var port = process.env.PORT || 3000; var options = { headers: { 'User-Agent': '<username>', Authorization: ‘token ‘ + process.env.GITHUB_TOKEN } }; server.js
  25. Step 10 • dotenv reads .env file, and adds GITHUB_TOKEN

    to process.env • instead of coding the actual token into server.js, we can use process.env.GITHUB_TOKEN • since we added .env to .gitignore, git will not save .env. • our secret token will not be added to github
  26. What is refactoring? • When you are just starting to

    learn the code, your main concern is to make code that works. • As you get more experienced, you will learn that code that works is not enough. • Refactoring is "restructuring existing computer code—changing the factoring—without changing its external behavior" - Wikipedia • improve readability, maintainability, extensibility
  27. What is module pattern? • revealing module pattern is once

    common way to group related pieces of code in javascript • we define some variables and functions and enclose them in a function • the function returns an object that has the properties and methods that we want people to access
  28. What is module pattern? var MyModule = function () {

    var name = 'Jane'; function talk () { console.log('Hi ' + name) }; return { talk: talk } }() MyModule.talk(); // Hi Jane
  29. How to export/import modules? • in addition to importing modules

    we installed from npm via require(), we can also export/import our own modules • export the code that we want other files to access • module.exports = <code to export> • import the module into other files • var <module name> = require(‘<path to module>’);
  30. Step 11 • add file ‘/services/githubService.js’ • remove the github

    code from server.js • put the github code into githubService. export githubService so other files can access the code. • import githubService into server.js
  31. Step 11 var axios = require('axios'); require('dotenv').config(); var githubService =

    function () { var options = { headers: { 'User-Agent': 'wykhuh', Authorization: 'token ' + process.env.GITHUB_TOKEN } }; function getBio() { return axios.get('https://api.github.com/users/wykhuh', options); } return { getBio: getBio }; }; module.exports = githubService(); /services/githubService.js
  32. Step 11 function getBio() { return axios.get('https://api.github.com/users/wykhuh', options); } •

    use the module pattern to create a function that returns an object. The object contains the function getBio • create a function that returns a promise • export the githubService so other files can access this code var githubService = function () { function getBio() { … } return { getBio: getBio }; }; module.exports = githubService();
  33. Step 11 var exphbs = require('express-handlebars'); var githubService = require(‘./services/githubService.js');

    var port = process.env.PORT || 3000; githubService.getBio() .then(function (results) { response.render('projects', { title: 'My Projects', bio: results.data }); }) server.js • import githubService into server.js • use getBio() from githubService
  34. Step 11 function getBio() { return axios.get('https://api.github.com/users/wykhuh', options); } function

    getRepos() { return axios.get('https://api.github.com/users/wykhuh/repos', options); } return { getBio: getBio, getRepos: getRepos }; }; module.exports = githubService(); /services/githubService.js • add 2nd function, getRepos() to githubService
  35. What is promise.all? • we want to make two api

    request: one for user info and one for repos • we want to wait for the results from both api request to come back before displaying the results. • the way to wait for multiple promises to resolve is to use promises.all • results are returned as an array, with the order of the results in the same order as the promises
  36. Step 12 function getRepos() { return axios.get('https://api.github.com/users/wykhuh/repos', options); } function

    githubInfo() { return axios.all([getRepos(), getBio()]) .then(function (results) { var repos = results[0].data; var bio = results[1].data; return { repos: repos, bio: bio }; }); } return { getBio: getBio, getRepos: getRepos, githubInfo: githubInfo }; /services/githubService.js
  37. Step 12 function githubInfo() { return axios.all([getRepos(), getBio()]) .then(function (results)

    { var repos = results[0].data; var bio = results[1].data; return { repos: repos, bio: bio }; }); } • use axios.all because we want to wait until all the promises to resolve before displaying the data • we pass in an array of promises [getRepos(), getBio()] to axios.all • results is an array of data. the first item contains results from getRepos, the second item contains results from getBio • we return an object that has the repos and bio data
  38. Step 12 app.get('/projects', function (request, response) { githubService.githubInfo() .then(function (results)

    { response.render('projects', { title: 'My Projects’, bio: results.bio, repos: results.repos } ); }) .catch(function (err) { console.log('err: ', err); }); }); server.js • use githubInfo() to get repos and bio data • pass repos and bio to the template
  39. Step 12 <h1>My Projects</h1> {{json bio}} <hr> {{json repos}} projects.hbs

    • when you visit the browser, it should display both bio and repos
  40. Step 13 • copy projects.hbs from gist • replace hardcode

    bio info with the data from server.js • loop through repos, replace hardcode repo info with data from server.js <li class="list-group-item">{{bio.name}}</li> {{#each repos as |repo|}} <li class="list-group-item"> <div class="repo-list-stats"> <span class=“repo-list-stat-item">{{repo.language}}</span> … </li> {{/each}}
  41. Step 13 • look through the json from https://api.github.com/users/<username> and

    https://api.github.com/users/<username>/repos • add other fields that are listed in the json to the projects.hbs • commit