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(…)
- 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
- Accepts
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-reduximport { 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