webutvikling og api-design

 

07: Data!

ASsignment 1

The URL

The Richardson maturity model

Level 1:

Resources

const countries = [
 { name: 'Norway', capital: 'Oslo' },
 { name: 'Denmark', capital: 'Copenhagen' },
];

// read a resource with HTTP GET
app.get('/countries', (req, res) => {
 res.send(counties);
});

// read a specific country
app.get('/countries/:name', (req, res) => {
 const name = req.params.name;
 return res.send(countries.find(
  c => c.name === name
 ));
});

// delete a country
app.get('/countries/:name/delete', (req, res) => {
 const name = req.params.name;
 const index = countries.findIndex(
  c => c.name === name
 );

 // remove the country
 countries.splice(index, 1);
 
 res.send(countries);
});

Level 2:

verbs

const countries = [
 { name: 'Norway', capital: 'Oslo' },
 { name: 'Denmark', capital: 'Copenhagen' },
];

// read a resource with HTTP GET
app.get('/countries', (req, res) => {
 res.send(counties);
});

// read a specific country
app.get('/countries/:name', (req, res) => {
 const name = req.params.name;
 return res.send(countries.find(
  c => c.name === name
 ));
});

// delete a country
app.delete('/countries/:name', (req, res) => {
 const name = req.params.name;
 const index = countries.findIndex(
  c => c.name === name
 );

 // remove the country
 countries.splice(index, 1);
 
 res.send(countries);
});
// old:
app.get('/countries/:name/delete', (req, res) => {
{
  "content": [ {
    "price": 499.00,
    "description": "Apple tablet device",
    "name": "iPad",
    "links": [ {
      "rel": "self",
      "href": "http://localhost:8080/product/1"
    } ],
    "attributes": {
      "connector": "socket"
    }
  }, {
    "price": 49.00,
    "description": "Dock for iPhone/iPad",
    "name": "Dock",
    "links": [ {
      "rel": "self",
      "href": "http://localhost:8080/product/3"
    } ],
    "attributes": {
      "connector": "plug"
    }
  } ],
  "links": [ {
    "rel": "product.search",
    "href": "http://localhost:8080/product/search"
  } ]
}   

More sophisticated

React state

export default class App extends React.Component {
  constructor(props) {
    super(props);
    
    this.state = {
      colors: [],
    };
  }

  componentDidMount() {
    fetch('http://localhost:2466/colors')
      .then(res => res.json())
      .then(colors => this.setState({colors}));
  }

  render() {
    return <div>
      {this.state.colors.map(
        color => <Color
            key={color.color}
            color={color.color}
            hex={color.hex}/>
      )}
    </div>;
  }
}
  • State is spread around the app
     
  • State makes debugging hard
     
  • State is hard to test
     
  • "Undo" and "Redo"

Redux

http://redux.js.org/

Redux is a single object

{
 messages: [
  // ...
 ],
 contactInfo: {
  // ...
 }
}
  • Not directly mutable
    • Just like setState(…)
       
  • EVERYTHING is stored here
     
  • Bad practise…?

get started!

// Can be used with any view lib (not just React)
npm install --save redux

1: Create a reducer

function reducer(
  state = {
    messages: [],
    contactInfo: {}
  }, action) {

  switch (action.type) {
    case 'ADD_MESSAGE':
      return {
        messages: [...state.messages, action.data],
        contactInfo: state.contactInfo,
      };
    case 'UPDATE_CONTACT_INFO':
      return {
        messages: state.messages,
        contactInfo: action.data,
      };
    default: return state;
  }
}
  • A pure function
    • Accepts
      • current state
      • an action
    • Returns the new state

2: Create a REdux store

import { createStore } from 'redux';

import theReducer from './reducer.js';

const store = createStore(reducer);
  • Give the reducer to createStore(…)
     
  • Done!

3: Dispatch an action

// from the reducer
case 'ADD_MESSAGE':
  return {
    messages: [...state.messages, action.data],
    contactInfo: state.contactInfo,
  };

// updating the state
store.dispatch({
  type: 'ADD_MESSAGE',
  data: {name: 'A', email: 'b@c.d', message: 'fghijklmn'},
});
  • Actions = plain objects
     
  • Passed as argument #2 to the reducer

3: Connect with react

// React bindings
npm install --save react-redux
import { connect } from 'react-redux'
// ...

class App extends React.Comoponent {
 // ...
}

function mapStateToProps(state) {
 return {};
}

function mapDispatchToProps(dispatch) {
 return {};
}

const ConnectedApp = connect(
 mapStateToProps,
 mapDispatchToProps
)(App);

export default ConnectedApp;
  • Properties from mapXToProps become available as props
import { Provider } from 'react-redux';

// ...

render((
 <Provider store={store}>
  <App .../>
 </Provider>
), document.getElementById('container'));

Map state & Dispatch
to props

function mapStateToProps(state) {
    return {
        messages: state.messages,
    };
};

function mapDispatchToProps(dispatch) {
    return {
        addMessage: message => dispatch({
            type: 'ADD_MESSAGE',
            data: message
        }),
    };
};
// render
<AdminPanel title="All messages"
            messages={this.props.messages}/>

// elsewhere
.then(message => {
    this.props.addMessage(message);
})

Bonus: React Devtools

Database!

Relations vs. Documents

Storage format: BSON

  • Binary JSON
     
  • ObjectId based on timestamp
     
  • Documents "=" objects
     
  • Joins

Enter MongoDB

$ mongo exampleDb
MongoDB shell version: 2.6.5
connecting to: exampleDb

> db.users.insert({username: 'Theneva'})
WriteResult({ "nInserted" : 1 })

> db.users.insert({username: 'HeroK0'})
WriteResult({ "nInserted" : 1 })

> db.users.find()
{ "_id" : ObjectId("54c5fbe88ede449775e517d2"), "username" : "Theneva" }
{ "_id" : ObjectId("54c5fbf58ede449775e517d3"), "username" : "HeroK0" }

http://docs.mongodb.org/manual/installation/

Don't make things before using them!

  • MongoDB creates…
    • DB
    • Collections ("tables")
       
  • … BUT ensure that things work!

Express <3 Mongoose

var app = require('express')();
var mongoose = require('mongoose');

app.use(require('body-parser').json());

var personSchema = new mongoose.Schema({
	name: { type: String, required: true }
});

var Person = mongoose.model('Person', personSchema);

app.get('/person', function(req, res) {
	var person = new Person({
		name: 'Martin'
	});

	res.send(person);
});

app.listen(1234);

Mongoose

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

const Cat = mongoose.model('Cat', { name: String });

const kitty = new Cat({ name: 'Zildjian' });
kitty.save(err => {
  if (err) // ...
  console.log('meow');
});

PG6300-15-07 Data!

By theneva

PG6300-15-07 Data!

Lecture 7 in PG6300-15 Webutvikling og API-design

  • 705