wbruno / livro-nodejs

Livro de NodeJS
https://novatec.com.br/livros/nodejs-4ed/
MIT License
106 stars 33 forks source link

Capítulo 5 - Construindo uma API RESTfull com Express - Adaptação para MySQL #4

Closed Cmcampos86 closed 3 years ago

Cmcampos86 commented 7 years ago

Bruno bom dia!

Após estudar o livro até o capítulo 6, resolvi adaptar o exemplo implementando MySQL, porém me surgiu uma dúvida.

Abaixo eu tenho o Stormtropper.html:

{% extends '../index.html' %}

{% block main %}

<form action="/stormtroppers/1" method="get">
    <label for="camposID">
        ID:
        <input type="text" name="nome" id="camposID">
        <input type="submit" value="Pesquisar">
    </label>
</form>
<br />
<br />
<table border="1" cellpadding="3" cellspacing="3">
    <tr>
        <td>ID</td>
        <td>NAME</td>
        <td>NICKNAME</td>
        <td>ID_PATENT</td>
    </tr>
    {% for stormtropper in stormtroppers %}
    <tr>
        <td>{{stormtropper.id}}</td>
        <td>{{stormtropper.name}}</td>
        <td>{{stormtropper.nickname}}</td>
        <td>{{stormtropper.id_patent}}</td>
    </tr>
    {% endfor %}
</table>

    {% endblock %}

E as rotas no stormtropper.js:

var express = require('express'),
    config = require('config'),
    router = express.Router();

var mysql = require('../db/mysql');
var StormtropperModel = require('../models/StormtropperModel')(mysql);
var StormtropperController = require('../controllers/StormtropperController')(StormtropperModel);

router.get('/', StormtropperController.getAll.bind(StormtropperController));
router.get('/:id', StormtropperController.getById.bind(StormtropperController));

module.exports = router;```

**Controller**```
var Promise = require('bluebird');

function StormtropperController(StormtropperModel) {
    this.model = StormtropperModel;
}

var handleNotFound = function (data) {
    if (!data) {
        var err = new Error('Not Found');
        err.status = 404;
        throw err;
    }
    return data;
};

function StormtropperController(StormtropperModel) {
    //promisifyAll faz com que os metodos tenha o Async em seu nome
    this.model = Promise.promisifyAll(StormtropperModel);
}

StormtropperController.prototype.getAll = function (request, response, next) {
    this.model.findAsync({})
        .then(handleNotFound)
        .then(function (data) {
            response.render('Stormtropper/Stormtropper', { stormtroppers: data[0] })
        })
        .catch(next);
};

StormtropperController.prototype.getById = function (request, response, next) {
    var id = request.query.nome;

    this.model.findOneAsync(id)
        .then(handleNotFound)
        .then(function (data) {
            response.render('Stormtropper/Stormtropper', { stormtroppers: data[0] })
        })
        .catch(next);
};

module.exports = function (StormtropperModel) {
    return new StormtropperController(StormtropperModel);
};

Model

function StormtropperModel(mysql) {
    this.mysql = mysql;
}

StormtropperModel.prototype.find = function (query, callback) {
    this.mysql.query("CALL SP_GetStormtroppers()", callback)    
};

StormtropperModel.prototype.findOne = function (id, callback) {
    this.mysql.query("CALL SP_GetStormtroppersById(?)", [id], callback)    
};

module.exports = function (mysql) {
    return new StormtropperModel(mysql);
}

E não estou conseguindo entender como eu vinculo no action do form a rota router.get('/:id', StormtropperController.getById.bind(StormtropperController)); Minha ideia é ter um campo aonde eu possa clicar no botão e pesquisar (a principio coloquei por ID). Eu cheguei até deixar fixo no action o "/stormtroppers/1" para ver o que acontece e como estou usando um get, a url ficou: http://localhost:3000/stormtroppers/1?nome=1, sendo que eu acredito que não está correto, porem até que funcionou e consegui pesquisar.

Eu consegui fazer sem dificuldades buscar a rota router.get('/', StormtropperController.getAll.bind(StormtropperController)); passando pelo controller e model já com MySQL e mostrando na tela.

Poderia me explicar como eu posso fazer para fazer o vínculo(clico no botão, redireciona para a página com o id que ele vai buscar)?

wbruno commented 7 years ago

Oi @Cmcampos86 sempre que você faz uma pesquisa ela deve ser com query string, então você na verdade, vai ter que filtrar nessa rota aqui:

/stormtroppers?id=1

okay? fica mais semântico... e se você quiser pesquisar por outros campos ficaria: /stormtroppers?alias=rex /stormtroppers?name=CT-555

e por ai vai..

quanto ao MySQL, eu não usaria procedures não.. não é uma forma "elegante" e escalável de fazer aplicações.. fuja delas.

a URL /stormtroppers/1 não é para pesquisas, mas sim para acessar um recurso diretamente.

Cmcampos86 commented 7 years ago

Ótimo Bruno!

Já fiz os ajustes e compreendi a explicação sobre sobre as rotas e query string. Agora sim tudo funcionando e explicado!

Quanto ao MySQL, seguirei dessa forma que você falou!

Obrigado mais uma vez!

Cmcampos86 commented 7 years ago

Bruno, ainda com relação a essa adaptação que estou fazendo, tenho mais uma dúvida com relação as rotas PUT e DELETE.

Minha ideia seria incluir uma coluna na table com os links para Editar e Excluir dessa forma: `

{% for stormtropper in stormtroppers %}
<tr>
    <td>{{stormtropper.id}}</td>
    <td>{{stormtropper.name}}</td>
    <td>{{stormtropper.nickname}}</td>
    <td>{{stormtropper.id_patent}}</td>
    <td>
        <a href="/stormtroppers/{{stormtropper.id}}?_method=put">Edit</a>
        <a href="/stormtroppers/{{stormtropper.id}}?_method=delete">Delete</a>
    </td>
</tr>
{% endfor %}

ID NAME NICKNAME ID_PATENT AÇÃO
`

As rotas estão assim: router.put('/edit/:id', StormtropperController.update.bind(StormtropperController)); router.delete('/delete/:id', StormtropperController.remove.bind(StormtropperController));

E a configuração do methodOverride está assim no app.js: app.use(methodOverride('X­HTTP­Method')); app.use(methodOverride('X­HTTP­Method­Override')); app.use(methodOverride('X­Method­Override')); app.use(methodOverride('_method')); Quando eu clico no link excluir por exemplo, aparece a mensagem "NOT FOUND".

Pesquisei no google e coloquei no final do href o _method="AÇÃO" pois como eu configurei no app.js o app.use(methodOverride('_method')), ele reconheceria dessa forma.

Até entendo que o href é GET, e seu eu deixar o link de excluir por exemplo sem o _method=delete, ele me aponta para a rota do getbyid, pois ela é GET e a rota é stormtropper/id.

Existe alguma outra forma de reconhecer as rotas ou então algo que eu esteja esquecendo de fazer para que não esteja funcionando?

wbruno commented 7 years ago

o overwrite é para POST, ele não aceita GET mesmo. Você vai ter que usar ajax ai, ai manda um DELETE de vez..

Cmcampos86 commented 7 years ago

Fechô!

Fiz aqui e funcionou!

Obrigado!