Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
Queremos desarrollar una api restful con node para un proyecto copia de twitter. Aunque de momento, será solo una primera versión con usuarios y tweets como si fuese un blog personal.
USUARIOS
username* : string<uniq>
name? : string
email* : string
tweetsIDs : string[]
TWEETS
id* : string<uniq>
text : string
owner : string<ID>
createdAt : timestamp
Esto sería un id de los tweets que este usuario había creado
"2 tablas"
OJO ! CONTROLA QUE LA API NO SE PUEDA QUEDAR PILLADA EN NINGÚN MOMENTO, controla campos vacíos, request inválidas, etc etc y devuelve el error en la respuesta y el código correcto para dicho caso
const mongoose = require('mongoose');
var TODOschema = mongoose.Schema({
text: String,
id: String,
createdAt: Number,
isCompleted: Boolean
});
var TODO = mongoose.model('todo', TODOschema);
module.exports = TODO;
var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Too few eggs'],
max: 12
},
bacon: {
type: Number,
required: [true, 'Why no bacon?']
},
drink: {
type: String,
enum: ['Coffee', 'Tea'],
required: function() {
return this.bacon > 3;
}
}
});
BreakfastModel.create(req.body)
.then( creado => res.send(creado))
.catch(error => {
// Diferentes posibles errores aquí
res.status(400).send(err);
})
const mongoose = require('mongoose');
const userSchema = mongoose.Schema({
username : {
type : String,
unique : true,
required: true,
minLength : 2
},
email : {
type : String,
required: true,
validate : (email) => emailValid(email)
},
name : String,
tweetsIDs : [String]
})
function emailValid(email){
return /^\S+@\S+\.\S+$/.test(email)
}
const userModel = mongoose.model('user', userSchema)
module.exports = userModel;
var userSchema = new Schema({
phone: {
type: String,
validate: {
validator: function(v) {
return /\d{3}-\d{3}-\d{4}/.test(v);
},
message: '{VALUE} is not a valid phone number!'
},
required: [true, 'User phone number required']
}
});
var cors = require('cors');
var app = require('express')();
app.use(cors());
{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}
var app = require('express')();
var cors = require('cors')
var corsOptions = {
origin: ['http://example.com' , 'http://example2.com' ]
}
app.use(cors(corsOptions));
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
Embebed Documents
const userSchema = mongoose.Schema({
...
tweetDelDia : TweetSchema,
tweets : [TweetSchema]
})
Esto sería embebido
const userSchema = mongoose.Schema({
...
tweets : [TweetSchema]
})
Ten cuidado amiguito de youtube
¿Necesitas también tener una colección de tweets?
Sí
No
Tendrás que mantener actualizados ambos tweets siempre entonces ... :S peligro
No pasa nada, es un array de objetos, de momento, solo de momento, pinta bien
Related documents
tweets : [
{
type : mongoose.Schema.Types.ObjectId,
ref : 'tweet'
}
]
Populate
tweets : [
{
type : mongoose.Schema.Types.ObjectId,
ref : 'tweet'
}
]
function getOneByUsername(req, res) {
const { username } = req.params;
return userModel
.findOne({ username })
.populate('tweets')
.then(u => res.json(u) )
.catch(e => res.status(500).json(e) )
}
Sin el populate
Con el populate
Triggers
userSchema.pre('remove', function(next) {
TweetsModel.remove({owner: this._id}).exec();
next();
});
Borrar los datos relacionados
Mongoose middlewares (triggers)
Projections
Dame todos los tweets (sin proyección)
tweetsModel
.find( {} )
Dame todos los tweets (con proyección)
tweetsModel
.find()
.select({text : 1})
tweetsModel
.find(
{},
{ text : 1 }
)
tweetsModel
.find()
.select("text")
tweetsModel
.find(
{},
"text"
)
Sin proyección
Con proyección
return userModel
.findOne({ username })
.select({ tweets : { $slice : 3}})
.then(u => res.json(u) )
.catch(e => res.status(500).json(e) )
Con proyección y con populate
return userModel
.findOne({ username })
.select({ tweets : { $slice : 3}})
.populate('tweets')
.then(u => res.json(u) )
.catch(e => res.status(500).json(e) )
EXTRA: Con proyección y con populate
return userModel
.findOne({ username })
.select({ tweets : { $slice : 3}})
.populate('tweets', "text")
.then(u => res.json(u) )
.catch(e => res.status(500).json(e) )
EXTRA: Con proyección y con populate
return userModel
.findOne({ username })
.select({ tweets : { $slice : 3}})
.populate('tweets', "text owner")
.then(u => res.json(u) )
.catch(e => res.status(500).json(e) )
Mongoose paginating results
MyModel.find(query, projection, { skip: 10, limit: 5 })
.then(results => res.json(results))
.then(err => res.status(500).json(err))
MyModel.find(query, projection, { skip: 10, limit: 5 })
.then(results => res.json(results))
.then(err => res.status(500).json(err))
Query Params
¿Diferencia?
function getAll(req, res) {
const { _skip, _limit } = req.query;
return userModel.find()
.limit(+_limit)
.skip(+_skip)
.then(async u => {
const totalCount = await userModel.find().count();
const totalPages = totalCount / +_limit;
res.json({results : u, totalItems : totalCount, totalPages })
})
.catch(e => res.status(500).json(e) )
}