Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Building API Driven React Applications
Search
scottradcliff
March 16, 2018
Programming
0
200
Building API Driven React Applications
A look at some best practices for APIs in React apps
scottradcliff
March 16, 2018
Tweet
Share
More Decks by scottradcliff
See All by scottradcliff
Working Remote: What Works, What Doesn't, and Where to go From Here
scottradcliff
0
58
Teaching Programmers Through Empathy
scottradcliff
0
490
Other Decks in Programming
See All in Programming
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
610
Lambda のコードストレージ容量に気をつけましょう
tattwan718
0
110
Honoを使ったリモートMCPサーバでAIツールとの連携を加速させる!
tosuri13
1
170
React 19でつくる「気持ちいいUI」- 楽観的UIのすすめ
himorishige
11
6k
それ、本当に安全? ファイルアップロードで見落としがちなセキュリティリスクと対策
penpeen
7
2.4k
Oxlintはいいぞ
yug1224
5
1.3k
AIによる高速開発をどう制御するか? ガードレール設置で開発速度と品質を両立させたチームの事例
tonkotsuboy_com
7
2k
LLM Observabilityによる 対話型音声AIアプリケーションの安定運用
gekko0114
2
420
AI Agent Tool のためのバックエンドアーキテクチャを考える #encraft
izumin5210
6
1.8k
責任感のあるCloudWatchアラームを設計しよう
akihisaikeda
3
160
フルサイクルエンジニアリングをAI Agentで全自動化したい 〜構想と現在地〜
kamina_zzz
0
400
Fluid Templating in TYPO3 14
s2b
0
130
Featured
See All Featured
Chasing Engaging Ingredients in Design
codingconduct
0
110
Into the Great Unknown - MozCon
thekraken
40
2.2k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
320
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
170
Fashionably flexible responsive web design (full day workshop)
malarkey
408
66k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
110
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
580
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.6k
How to Ace a Technical Interview
jacobian
281
24k
Marketing to machines
jonoalderson
1
4.6k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Transcript
API Driven React Applications
Security Speed Change API Design
Tools
mkdir react-talk-app cd react-talk-app mkdir server mkdir client
react-talk-app |—client |—server
create-react-app create-react-app client
client/ |-.gitignore |- README.md |- node_modules/ |- package.json |- public/
|- src/ |- yarn.lock
Components
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); }
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); }
import React, { Component } from ‘react'; import axios from
'axios'; import Product from ‘./Product’;
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); }
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)) }
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); }
render() { return ( <div> {this.state.products.map(product => { return <Product
product={product} /> }) } </div> ); } }
rails —api rails new server —api
server |- Gemfile |- Gemfile.lock |- README.md |- Rakefile |-
app/ |- bin/ |- config/ |- config.ru |- db …
Security
componentWillMount() { axios.get(‘/api/v1/products’, headers: { Authorization: api_token }) .then(response =>
{ this.setState({ products: response.data.products, }); }) .catch(error => alert(error)) }
class ApplicationController < ActionController::API def current_user Account.find_by(api_token: request.authorization) end end
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
[ {id: 1, sku: “sku-1234”, price: 1200}, {id: 2, sku:
“sku-4321” price: 1300} ]
Active Model Serializers class ProductSerializer < ActiveModel::Serializer attributes :id, :name,
:sku, :price has_many :images end
Speed
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
[ {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} ]
Change
Namespaces Rails.application.routes.draw do namespace :api do namespace :v1 do resources
:products end end end
Thanks! Scott Radcliff Freelance Software Developer scottradcliff.com @scottradcliff
[email protected]