Building API Driven React Applications

Building API Driven React Applications

A look at some best practices for APIs in React apps

6b0b48f11f9de8bea95efad477f2d4cf?s=128

scottradcliff

March 16, 2018
Tweet

Transcript

  1. API Driven React Applications

  2. Security Speed Change API Design

  3. Tools

  4. mkdir react-talk-app cd react-talk-app mkdir server mkdir client

  5. react-talk-app |—client |—server

  6. create-react-app create-react-app client

  7. client/ |-.gitignore |- README.md |- node_modules/ |- package.json |- public/

    |- src/ |- yarn.lock
  8. Components

  9. import React, { Component } from ‘react'; import axios from

    'axios'; import Product from ‘./Product’; class App extends Component { constructor() { super(); this.state = { products: []}; } componentWillMount() { axios.get(‘/api/v1/products’, headers: { Authorization: api_token}) .then(response => { this.setState({ products: response.data.products, }); }) .catch(error => alert(error)) } render() { return ( <div> {this.state.products.map(product => { return <Product product={product} /> }) } </div> ); } } const compassModulesContainerElement = document.getElementById('compass-modules'); export default CompassModulesContainer; if (compassModulesContainerElement) { ReactDOM.render(<CompassModulesContainer />, compassModulesContainerElement); }
  10. import React, { Component } from ‘react'; import axios from

    'axios'; import Product from ‘./Product’; class App extends Component { constructor() { super(); this.state = { products: []}; } componentWillMount() { axios.get(‘/api/v1/products’) .then(response => { this.setState({ products: response.data.products, }); }) .catch(error => alert(error)) } render() { return ( <div> {this.state.products.map(product => { return <Product product={product} /> }) } </div> ); } } const compassModulesContainerElement = document.getElementById('compass-modules'); export default CompassModulesContainer; if (compassModulesContainerElement) { ReactDOM.render(<CompassModulesContainer />, compassModulesContainerElement); }
  11. import React, { Component } from ‘react'; import axios from

    'axios'; import Product from ‘./Product’;
  12. import React, { Component } from ‘react'; import axios from

    'axios'; import Product from ‘./Product’; class App extends Component { constructor() { super(); this.state = { products: []}; } componentWillMount() { axios.get(‘/api/v1/products’, headers: { Authorization: api_token }) .then(response => { this.setState({ products: response.data.products, }); }) .catch(error => alert(error)) } render() { return ( <div> {this.state.products.map(product => { return <Product product={product} /> }) } </div> ); } } const compassModulesContainerElement = document.getElementById('compass-modules'); export default CompassModulesContainer; if (compassModulesContainerElement) { ReactDOM.render(<CompassModulesContainer />, compassModulesContainerElement); }
  13. class App extends Component { constructor() { super(); this.state =

    { products: []}; } componentWillMount() { axios.get(‘/api/v1/products’, headers: { Authorization: api_token }) .then(response => { this.setState({ products: response.data.products, }); }) .catch(error => alert(error)) }
  14. import React, { Component } from ‘react'; import axios from

    'axios'; import Product from ‘./Product’; class App extends Component { constructor() { super(); this.state = { products: []}; } componentWillMount() { axios.get(‘/api/v1/products’, headers: { Authorization: api_token }) .then(response => { this.setState({ products: response.data.products, }); }) .catch(error => alert(error)) } render() { return ( <div> {this.state.products.map(product => { return <Product product={product} /> }) } </div> ); } } const compassModulesContainerElement = document.getElementById('compass-modules'); export default CompassModulesContainer; if (compassModulesContainerElement) { ReactDOM.render(<CompassModulesContainer />, compassModulesContainerElement); }
  15. render() { return ( <div> {this.state.products.map(product => { return <Product

    product={product} /> }) } </div> ); } }
  16. rails —api rails new server —api

  17. server |- Gemfile |- Gemfile.lock |- README.md |- Rakefile |-

    app/ |- bin/ |- config/ |- config.ru |- db …
  18. Security

  19. componentWillMount() { axios.get(‘/api/v1/products’, headers: { Authorization: api_token }) .then(response =>

    { this.setState({ products: response.data.products, }); }) .catch(error => alert(error)) }
  20. class ApplicationController < ActionController::API def current_user Account.find_by(api_token: request.authorization) end end

  21. module Api module V1 class ProductsController < ApplicationController def index

    if current_user @products = Product.all render json: @products, status: 200 end end end end end
  22. [ {id: 1, sku: “sku-1234”, price: 1200}, {id: 2, sku:

    “sku-4321” price: 1300} ]
  23. Active Model Serializers class ProductSerializer < ActiveModel::Serializer attributes :id, :name,

    :sku, :price has_many :images end
  24. Speed

  25. module Api module V1 class ProductsController < ApplicationController def index

    if current_user @products = Product.all render json: @products, include: :images, status: 200 end end end end end
  26. [ {id: 1, sku: “sku-1234”, price: 1200, images: [ {id:1,

    url: “someplace.jpg”}, {id: 2, url: “someotherplace.jpg”]}, {id: 2, sku: “sku-4321” price: 1300} ]
  27. Change

  28. Namespaces Rails.application.routes.draw do namespace :api do namespace :v1 do resources

    :products end end end
  29. Thanks! Scott Radcliff Freelance Software Developer scottradcliff.com @scottradcliff scott@scottradcliff.com