Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Quando ocorre erro de conexão com o banco, não deveria apresentar erro no frontend?

No servidor (server.js), alterei de propósito a url de conexão com o banco de dados:

server.js:

var http = require('http');
var app = require('./config/express');
require('./config/database')('ocalhost/alurapic');

http.createServer(app)
.listen(3000, function() {
    console.log('Servidor iniciado');
});

Conforme esperado, no console do terminal apareceu a seguinte mensagem:

consign v0.1.2 Initialized in app
+ ./models/foto.js
+ ./api/foto.js
+ ./api/grupo.js
+ ./routes/foto.js
+ ./routes/grupo.js
Servidor iniciado
Desconectado do MongoDB
Erro na conexão com MongoDB: MongoError: getaddrinfo EAI_AGAIN ocalhost:27017

Entendi que, por causa do erro na conexão, o backend apenas não conectou ao Banco de Dados. Porém, apesar da não conexão com o BD, o servidor express foi iniciado.

O servidor express faz uso da aplicação do frontend da aplicação alurapic desenvolvida em AngularJs e disponível na pasta ./public.

Quando a url http://localhost:3000/#/fotos é acessada pelo navegador, mesmo com o erro na conexão com o BD, o servidor express disponibiliza a aplicação frontend normalmente e carrega os modelos, as APIs e as rotas do backend.

express.js:

var express = require('express');
var consign = require('consign');
var bodyParser = require('body-parser');
var app = express();

app.use(express.static('./public'));

app.use(bodyParser.json());

consign({cwd: 'app'})
    .include('models')
    .then('api')
    .then('routes')
    .into(app);

module.exports = app;

Na aplicação Angular, o módulo principal (main.js), provê para rota /fotos a partial principal.html e o controller FotosController.

main.js:

angular.module('alurapic', ['minhasDiretivas','ngAnimate', 'ngRoute', 'ngResource', 'meusServicos'])
    .config(function($routeProvider, $locationProvider) {

        $routeProvider.when('/fotos', {
            templateUrl: 'partials/principal.html',
            controller: 'FotosController'
        });

        $routeProvider.when('/fotos/new', {
            templateUrl: 'partials/foto.html',
            controller: 'FotoController'
        });

        $routeProvider.when('/fotos/edit/:fotoId', {
            templateUrl: 'partials/foto.html',
            controller: 'FotoController'
        });

        $routeProvider.otherwise({redirectTo: '/fotos'});

    });

A partial principal.html, que é controlada pelo FotosController, apresenta a lista de fotos.

principal.html:

<div class="jumbotron">
    <h1 class="text-center">Alurapic</h1>
</div>

<p ng-show="mensagem.length" class="alert alert-info">
    {{mensagem}}
</p>

<div class="row">Alterei 
    <div class="col-md-12">
        <form>
            <div class="input-group">
                <span class="input-group-btn">
                    <a href="/#/fotos/new" class="btn btn-primary" type="button">
                        Nova foto
                    </a>
                </span>
                <input class="form-control" placeholder="filtrar pelo título da foto" 
                    ng-model="filtro" ng-model-options="{ debounce: 500 }">
        </form>
    </div> <!-- fim col-md-12 -->
</div> <!-- fim row -->

<div class="row">
    <meu-painel class="col-md-2 painel-animado" ng-repeat="foto in fotos | filter: filtro" titulo="{{foto.titulo}}">
        <minha-foto url="{{foto.url}}" alt="{{foto.titulo}}"></minha-foto>

        <a class="btn btn-primary btn-block" href="/#/fotos/edit/{{foto._id}}">
            Editar
        </a>
        <meu-botao-perigo nome="Remover" acao="remover(foto)">Remover</meu-botao-perigo>
    </meu-painel>
</div>

O FotosController utilizado pela partial principal.html, invoca um recurso (recursoFoto) para recuperar a lista de fotos.

fotosController.js:

angular.module('alurapic').controller('FotosController', function($scope, recursoFoto) {

    $scope.fotos = [];
    $scope.filtro = '';
    $scope.mensagem = '';

    recursoFoto.query(function(fotos) {
        $scope.fotos = fotos;
    }, function(erro) {
        console.log(erro);
    });

    $scope.remover = function(foto) {

        recursoFoto.delete({fotoId: foto._id}, function() {
            var indiceDaFoto = $scope.fotos.indexOf(foto);
            $scope.fotos.splice(indiceDaFoto, 1);
            $scope.mensagem = 'Foto ' + foto.titulo + ' removida com sucesso!';
        }, function(erro) {
            console.log(erro);
            $scope.mensagem = 'Não foi possível apagar a foto ' + foto.titulo;
        });
    };

});

Continua...

2 respostas

...continuação:

O recursoFoto injetado no FotoController para listar as fotos está definido no módulo meus-servicos.js.

meus-servicos.js:

angular.module('meusServicos', ['ngResource'])
    .factory('recursangoFoto', function($resource) {

        return $resource('/v1/fotos/:fotoId', null, {
            'update' : { 
                method: 'PUT'
            }
        });
    })
    .factory("cadastroDeFotos", function(recursoFoto, $q) {
        var service = {};
        service.cadastrar = function(foto) {
            return $q(function(resolve, reject) {

                if(foto._id) {
                    recursoFoto.update({fotoId: foto._id}, foto, function() {
                        resolve({
                            mensagem: 'Foto ' + foto.titulo + ' atualizada com sucesso',
                            inclusao: false
                        });
                    }, function(erro) {
                        console.log(erro)

No FotoController, quando recursoFoto foi invocado para listar as fotos na partial principal.html, ele fez uso da propriedade query e o backend, se tudo ocorrer bem, devolve a lista de fotos para o frontend.

Ao acessar o recurso que lista fotos no backend, o frontend passou a rota /fotos. Esta rota está definida no módulo /routes/fotos.js, carregado pelo express.

/routes/fotos.js:

module.exports = function(app) {
    var api = app.api.foto;

    app.route('/v1/fotos')
        .get(api.lista)
        .post(api.adiciona);

    app.route('/v1/fotos/:id')
        .get(api.buscaPorId)
        .delete(api.removePorId)
        .put(api.atualiza);
};

A lista é recuperada (get) através da api.lista, definida em /api/fotos.js.

/api/fotos.js:

var mongoose = require('mongoose');

var api = {};
var model = mongoose.model('Foto');

api.lista = function(req, res) {
    model.find()
    .then(function(fotos) {
        res.json(fotos);
    }, function(error) {
        console.log(error);
        res.sendStatus(500).json(error);
    });
};

api.buscaPorId = function(req, res) {
};

api.removePorId = function(req, res) {
};

api.adiciona = function(req, res) {
};

api.atualiza = function(req, res) {
};

module.exports = api;

Minha pergunta está exatamente aqui:

Não era para backend retornar o código status 500 para o frontend? A api.lista não conseguiu acessar o BD, uma vez que quando o servidor foi iniciado não conectou ao BD.

solução!

Fala aí Joaquim, tudo bem? Vamos lá:

Nesse caso, quando ocorre o erro ao tentar realizar a conexão com o banco de dados, a API nem deveria ter subido, está faltando um tratamento para esse problema.

Outro detalhe, provavelmente não está retornando erro 500 porque a API também não deve estar fazendo esse tratamento.

Ambos os erros e cenários precisam ser tratados durante a construção da API.

Espero ter ajudado.