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

Build Your First API
 with Node and Express

Build Your First API
 with Node and Express

Introductory-level talk to help developers get comfortable writing APIs using NodeJS
Given at Charlotte NodeJS User Group Meetup
May 2, 2017

vjwilson

May 02, 2017
Tweet

More Decks by vjwilson

Other Decks in Programming

Transcript

  1. Build Your First API
 with Node and Express Charlotte NodeJS

    User Group Meetup May 2, 2017 Van Wilson @vanwilson
  2. API • Application Programming Interface • A way for two

    different pieces of software to talk to each other • In Object-Oriented programming, a class’s public methods are its API • APIs can be exposed as web services
  3. Web APIs Using a RESTful API as a web service

    allows you to have a single source of truth for your data that you can consume in many different ways. • Website (with either client-side or server-side front-end) • Hybrid mobile app • Native mobile app • Desktop app • Command-line app • Other Services (e.g., Jira, Bamboo, and GitHub APIs can all talk to each other)
  4. Examples of Web APIs • Facebook
 https://www.programmableweb.com/api/facebook • Twitter
 https://dev.twitter.com/overview/api

    • GitHub
 https://developer.github.com/v3/ • Marvel
 https://developer.marvel.com/
  5. Types of Web APIs • RPC (XML-RPC or JSON-RPC) •

    SOAP (Simple Object Access Protocol) • REST (Representational State Transfer) • GraphQL https://www.quora.com/What-are-advantages-and- disadvantages-of-GraphQL-SOAP-and-REST
  6. RESTful APIs • Stateless • Cacheable • Use HTTP protocol

    for communication • Overwhelming uses JSON for data
  7. Resources A REST API is based around resources • Entities

    (nouns) • Collections or single instances • Can contain other resources (e.g., user has repos) https://www.thoughtworks.com/insights/blog/ rest-api-design-resource-modeling
  8. Specifying resources The URI of a resource is the name

    of its collection. • /users • /customers • /superheros
  9. Specifying a single resource The URI of a single resource

    is the name of the collection, plus an identifier. • Database ID: /users/123 • GUID: /companies/8675-305a-bcde-f123 • Unique URI: /superheros/deadpool
  10. Using query parameters When retrieving resources, you limit the response

    with query parameters. • Filtering: /users?firstname=John&lastname=Smith • Pagination: /companies?page=2&count=30 • Sorting: /superheros?sort=desc • Partial responses: /jobs?fields=title,dept,salary
  11. Acting on resources: 
 HTTP verbs • GET • POST


    • PUT (or PATCH) • DELETE (You can distinguish holdovers from SOAP, where the API calls are functions names like getCustomers or deletePost).
  12. Create-Read-Update-Delete HTTP Verb Example URL Create POST /users Read GET

    /users (all) /users/42 (one) Update PUT (full) PATCH (partial) /users/42 Delete DELETE /users/42
  13. Create Request URL: /recipes Action: POST Payload: { "name": "Pie"

    } Response Status: 201 (Created) Body: { "name": "Pie", "id": 1 }
  14. Read Request URL: /recipes Action: GET Payload: (none) Response Status:

    200 Body: [ { "name": "Pie", "id": 1 }, { "name": "Cake", "id": 2 } ]
  15. Read (just one) Request URL: /recipes/2 Action: GET Payload: (none)

    Response Status: 200 (Ok) Body: { "name": "Cake", "id": 2 }
  16. Update Request URL: /recipes/2 Action: PUT Payload: { "name": “Pound

    Cake", "id": 2 } Response Status: 200 (Ok) Body: { "name": “Pound Cake", "id": 2 }
  17. Why Node? Node.js uses an event-driven, non-blocking I/O model that

    makes it lightweight and efficient. Node.js’ package ecosystem, npm, is the largest ecosystem of open source libraries in the world. • Built-in http package (low-level, roll your own) • Express (de facto standard) • Koa, or thousands of other new contenders (it is JavaScript, remember?) https://www.npmjs.com/search?q=http => 27922 packages found
  18. Express routing methods app = express(); app.get() app.post() app.put() app.delete()

    “Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).”
  19. Routing method signature app.get('/recipes', function (req, res) { // the

    req object has information about the request // the res object has methods to control the response }); Resource URI, callback(request, response)
  20. Request object let bodyParser = require('body-parser'); app.use( bodyParser.json() ); app.put('/recipes/:id',

    function (req, res) { let id = req.params.id; let revisedRecipe = req.body; });) Access to parameters, headers, and (optionally) the payload body
  21. Response object app.post('/recipes', function (req, res) { // create newRecipe

    object res.status(201); res.set('Cache-Control', 'no-cache'); res.json(newRecipe); });) Controls the status, headers, and format of the response
  22. • Install the app:
 https://www.getpostman.com/ • Use Postman manually:
 https://www.sitepoint.com/api-building-and-testing-

    made-easier-with-postman/ • Automated tests for your API:
 https://www.codementor.io/equimper/testing-your- api-with-postman-4tuwpkswp Testing you API: Postman
  23. App Framework let express = require('express'); let app = express();

    let port = 7777; app.get('/', function (req, res) { res.send('Welcome to the recipe API.'); }); app.listen(port, function () { console.log(`Recipe API app listening on port ${port}`); });
  24. Database on a budget let recipes = [ { "id":

    1, "name": "Pecan Pie", "author": "Mariah Reynolds", "ingredients": [ "3 eggs", "1 c. white sugar" ], "directions": "Melt 6 Tbsp. butter, mix in. Add 1 c. chopped nuts. Bake 57 mins. at 325 or 350." }, { "id": 2, "name": "Pound Cake", "author": "Eliza Hamilton", "ingredients": [ "1 lb. cake flour", "1 lb. sugar", "1 lb. butter” ], "directions": "Mix all ingredients thoroughly. Pour into cake pan. Bake at 350 for 1 hour and 20 minutes." } ];
  25. GET one recipe app.get('/recipes/:recipeId',function(req, res) { const id = parseInt(req.params.recipeId,

    10); const result = recipes.find((recipe) => { return recipe.id === id; }); if (result) { res.json(result); } else { res.status(404); res.json({ error: 'No recipe with that ID found'}); } });
  26. POST a new recipe let nextIndex = recipes.length + 1;

    app.post('/recipes', function (req, res) { const recipe = Object.assign({}, req.body); recipe.id = nextIndex; recipes.push(recipe); nextIndex += 1; res.status(201); res.json(recipe); });
  27. PUT a recipe, part 1 app.put('/recipes/:recipeId',function(req, res) { const id

    = parseInt(req.params.recipeId, 10); const recipe = Object.assign({}, req.body); if (!recipe.name || !recipe.author || ! recipe.ingredients || !recipe.directions) { res.status(400); res.json({ error: 'Bad request.' }); } else { const result = recipes.find((recipe) => { return recipe.id === id; }); // function continues on next page ===>
  28. PUT a recipe, part 2 if (result) { delete recipe.id;

    Object.assign(result, recipe); res.json(result); } else { res.status(404); res.json({ error: 'No recipe with that ID found '}); } } }); res.json(result); } else { res.status(404); res.json({ error: 'No recipe with that ID found '}); } } });
  29. DELETE a recipe app.delete('/recipes/:recipeId',function(req, res) { const id = parseInt(req.params.recipeId,

    10); const startingLength = recipes.length; recipes = recipes.filter((recipe) => { return recipe.id !== id; }); if (recipes.length < startingLength) { res.status(204); res.send(); } else { res.status(404); res.json({error: 'No recipe with that ID found'}); } });
  30. Just the first step • Make it work • Make

    it right • Make it fast http://wiki.c2.com/? MakeItWorkMakeItRightMakeItFast
  31. Make it more robust • Validation • Error handling •

    Refactoring (DRY, or Don’t Repeat Yourself) • Combine route handling • Take advantage of middleware
  32. Organizing your code • “MVC” works for APIs, too •

    The “View” is really how you structure your resources from your models • Don’t just be a dumb SQL client • Route handling becomes central (MCR ?)
  33. Authentication and
 Authorization • Not a good idea to let

    just anybody POST, PUT, and DELETE anything they want in your data • Since REST is stateless, sessions are not an option • API Keys • Username/Password login, with expiring tokens • JSON Web Tokens
  34. Nested Resources { "id": 6, "name": "Sausage", "author": { "id":

    1776, "firstName": "Martha", "lastName": "Washington" }, "ingredients": [ "1 lb. sausage" ], "directions": "Mix. Cook at 375 for 18 minutes." } Example: /authors and /recipes as separate, related resources
  35. Code • This simple API example:
 https://github.com/vjwilson/your-first-node-api • More complete

    example:
 https://github.com/vjwilson/recipes • React front-end for the recipes API:
 https://github.com/vjwilson/recipes-frontend