2

EDIT: I've carefully reviewed and tried solutions from the following SO posts, which were very informative, but unfortunately haven't been able to manage to make the new info work in my context.

Hi! I'm trying for the first time to use data from an external API (the Google Books API - https://developers.google.com/books/docs/v1/using) in an Node.js & Express/MEAN stack app. I'm using the google-books-search npm package (https://www.npmjs.com/package/google-books-search) - not sure whether that's making things easier or harder for me at this juncture.

I've spent the weekend researching and trying to fix my problems. I've read a lot of cool stuff about JSONP, AJAX, and more but fear I'm investigating material that's beyond my current ability to understand it. I hope to get the basics working before I go too much further down the rabbit hole.

Here are the issues:

  1. Half of my routes work in the browser and/or in cURL but others don't.
  2. I'm able to access JSON query results from the external API in the console, but haven't been able to manipulate that data to show up in my HTML view. I've read a lot about having to use JSONP but haven't been able to make it work.

Here's an explanation of what I want the routes to do:

  • app.get('/') - root - WORKS

  • app.get('/authorsearch/:author') - retrieve query results from Google Books API - CAN PULL FROM API AND DISPLAY QUERY RESULT DATA IN CONSOLE

  • app.get('/titlesearch/:title') - retrieve query results from Google Books API - CAN PULL FROM API AND DISPLAY QUERY RESULT DATA IN CONSOLE

  • app.post('/books') - save book to database - NOT THERE YET (since I haven't been able to grab the query results from the API)

  • app.get('/books/:id') - retrieve specific book from database - WORKS (currently displays empty array)

  • app.post('/user') - create a new user and save to database - DOESN'T WORK

  • app.post('/login') - existing user log in - DOESN'T WORK
  • app.get('/user/:id') - retrieve user details from database - DOESN'T WORK
  • app.put('/user/:id') - update user details in database - WORKS
  • app.delete('/user/:id') - delete user account from database - WORKS

My goal is for users to be able to search for books by title or author. Registered/logged-in users will be able to save selected books as favorites and access their list of books during later sessions.

SERVER.JS

// DEPENDENCIES
var express      = require('express'),
    mongoose     = require('mongoose'),
    bodyParser   = require('body-parser'),
    md5          = require('md5'),
    cookieParser = require('cookie-parser'),
    morgan       = require('morgan'),
    books          = require('google-books-search');

var port = process.env.PORT || 3000;
var app = express();

// MIDDLEWARE
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static('public'));
app.use(cookieParser());

// DATABASE
mongoose.connect('mongodb://localhost/google_books_app_db');

// MODELS
var User = require('./models/user');
var Book = require('./models/book');

// LISTENER
app.listen(port);
console.log("server working on port " + port);

// =======
// =======
// ROUTES
// =======
// =======

// =====
// Root 
// =====

// root - WORKS 
app.get('/', function(req, res) {
    // res.render("index");
    console.log("root working");
});

// ===============================================
// Search routes - from Google Books API's server
// ===============================================

// GET books by search of author name - WORKS
app.get('/authorsearch/:name', function(req, browserResponse) {
    //browserResponse.send("bannana"); return;
    //console.log( browserResponse.send );
    var author = req.params.name;
    books.search("inauthor=" + author, function(err, bookSearchResponse) {
        if ( ! err ) {
            browserResponse.send( bookSearchResponse );
            //console.log(res);
            // $('body').append(res);
            // res.json(req.body);
        } else {
            console.log(err);
        }; // end if/else
    }); // end search
}); // end get books by author


// GET books by search of title - WORKS
app.get('/titlesearch/:title', function(req, browserResponse) {
    var title = req.params.title;
    books.search("intitle=" + title, function(err, bookSearchResponse) {
        if ( ! err ) {
            browserResponse.send( bookSearchResponse );
            // $('#results-container').append(res);
            // res.json(req.body);
        } else {
            console.log(err);
        }; // end if/else
    }); // end search
}); // end get books by title


// ============================
// Book routes - from local db
// ============================

// GET books - WORKS (shows empty array)
app.get('/books/:id', function(req, res) {
    Book.find({ 'user': req.params.id }).exec(function(err, books) {
        console.log("getting books");
        res.send(books);
    });
}); 


// ============
// User routes
// ============

// CREATE new user sign-up
app.post('/user', function(req, res) {
    var password_hash = md5(req.body.password);

    var user = new User({
        username: req.body.username,
        password_hash: password_hash
    });

    user.save(function(err) {
        if (err) {
            console.log(err);
            res.statusCode = 503;
        } else {
            console.log(user.username + " created server side");
            res.cookie("loggedInUserId", user.id)
            res.send(user);
        }; //end if/else
    }); // end save
}); // end new sign-up


// POST user log-in
app.post('/login', function(req, res) {
    var req_username = req.body.username;
    var req_password = req.body.password;

    req_password_hash = md5(req_password);

    User.findOne({ 'username' : req_username }).exec(function(err, user) {
        if (user != null && req_password_hash == user.password_hash) {
            res.cookie("loggedInUserId", user.id);
            res.send(user);
        } else {
            console.log("Error, try again");
        }; // end if/else
    }); // end findOne
}); // end log-in


// GET user by ID
app.get('/user/:id', function(req, res) {
    console.log("Find one user");
    User.findById(req.params.id).then(function(user) {
        res.send(user);
    }); // end findById
}); // end get user


// UPDATE edit user account - WORKS 
app.put('/user/:id', function(req, res) {
    console.log("User edit request");
    User.findOneAndUpdate( { _id: req.params.id }, req.body, function(err, user) {
        console.log("User updated");
        res.send(user);
    }); // end findOneAndUpdate
}); // end edit user


// DELETE user account - WORKS
app.delete('/user/:id', function(req, res) {
    console.log("User delete request");
    User.findOneAndRemove( { _id: req.params.id }, function(err) {
        res.clearCookie("loggedInUserId");
        console.log("User cookie cleared");
        res.send("User deleted");
    }); // end findOneAndRemove
}); // end delete user

// END OF USER ROUTES

// END OF ALL ROUTES

APP.JS

console.log("loaded");

$(document).ready(function() {
    console.log("document onload");

// =============
// CLICK EVENTS
// =============

    // search by author button 
    $('#author-searchbtn').on('click', function() {
        // console.log("debugger hello");
        var searchAuthor = $('#search-field').val();
        searchByAuthor(searchAuthor);
    }); // end onclick

    // search by title button 
    $('#title-searchbtn').on('click', function() {
        var searchTitle = $('#search-field').val();
        searchByTitle(searchTitle);
    }); // end onclick

    // new user sign-up button
    $('#register-btn').click(function() {
       console.log("Clicked register");
       newUser();
     });

    // user log-in button
    $('#login-btn').click(function() {
        console.log("Clicked login");
        loginPost();
    })

    // user log-out button
    $('#logout-btn').click(function() {
        Cookies.remove('loggedInUserId');
        console.log("User cookie deleted; user logged out");
    }); 


// =================
// SEARCH FUNCTIONS
// =================

    // WORKS
    var searchByAuthor = function(searchAuthor) {
        console.log("about to make ajax request");
        $.ajax({
          url: '/authorsearch/' + searchAuthor
          // url: 'https://www.googleapis.com/books/v1/volumes?inauthor=' + searchAuthor
       }).done(function(res) {
            console.log("ajax author response recieved");
                console.log(res);
          console.log("===========SEARCHED BY AUTHOR===========");
       }) // end Ajax call
       console.log( "ajax author request made");
       //handleResponse(res);
    }; // end searchByAuthor


    // WORKS
    var searchByTitle = function(searchTitle) {
        console.log("about to make ajax request");
        $.ajax({
            url: '/titlesearch/' + searchTitle
        }).done(function(data) {
             console.log("ajax title response recieved");
             console.log(data);
             // $('#results-container').html(data);
             console.log("===========SEARCHED BY TITLE===========");
             for (var i = 0; i < data.items.length; i++) {
                var item = data.items[i];
                document.getElementById("results-container").innerHTML += "<br>" + item.volumeInfo.authors;
                console.log(item.volumeInfo.authors);
            };
        console.log(data.items[3]);
        }); // end Ajax call
        console.log( "ajax title request made");
        // handleResponse(data);
    }; // end searchByTitle

  // HAVEN'T GOTTEN HERE YET
    var handleResponse = function(res) {
        for (var i=0; i < res.items.length; i++) {
            var item = resp.items[i];
            document.getElementById('#results-container').innerHTML;
        }; // end for loop
    }; // end handleResponse

  // HAVEN'T GOTTEN HERE YET - NOT SURE IF IT WILL BE NEEDED
    var displayBooks = function(res) {
        // displayBooks();
    }; // end displayBooks


// ===============
// USER FUNCTIONS
// ===============

    var setUp = function() {
        console.log("setting up");
        if (Cookies.get("loggedInUserId") != undefined) {
            console.log("already logged in");
        };
    };

    var newUser = function() {
        user = {
            username: $('#username').val(),
            password: $('#password').val(),
        };

        console.log(user);

        $.ajax({
            url: '/user',
            method: 'POST',
            dataType: 'json',
            data: user
        }).done(function(data) {
            user = Cookies.get('loggedInUserId');
        }); // end ajax request
    }; // end newUser


    var loginPost = function() {
        user = {
            username: $('#username').val(),
            password: $('#password').val(),
        };

        $.ajax({
            url: '/login',
            method: 'POST',
            dataType:'json',
            data: user
        }).done(function(data) {
            console.log("submitted login info");
        }).fail(function() {
            console.log("login failed");
        }); // end ajax request
    }; //end userLogin


}); // end document ready

INDEX.HTML - Please note that the templating isn't up and running yet so I just have a very basic view (search field and buttons, user registration form, user log-in form, log-out button).

<html>
<head>
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.0.4/js.cookie.js"></script>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.4/handlebars.js"></script>

    <link rel="stylesheet" type="text/css" href="css/styles.css">

    <title>Google Books App</title>
</head>
<body>

    <h1>Discover Literature</h1>

    <div id="search-container">
        <p>Find something you'll love.</p>
        <input type="text" id="search-field">
        <button id="author-searchbtn">Search by Author</button>
        <button id="title-searchbtn">Search by Title</button>
    </div>

    <div id="results-container">
    </div> 

    <br><br>

    <!-- TEMP SIGN-UP -->
    <div id="signup-container" data-id="{{_id}}">

        <b>Sign up</b>
        <br>
        <label for="username">Username</label><br/>
        <input type="text" id="username" placeholder="username"/><br>

        <label for="password">Password</label><br/>
        <input type="text" id="password" placeholder="password"/><br>

        <button id="register-btn" data-id="{{_id}}">Register!</button>

    </div>

    <br><br>

    <!--TEMP LOG-IN -->
    <div id="login-container" data-id="{{_id}}">

        <b>Log in</b>
        <br>
        <label for="username">Username</label><br/>
        <input type="text" id="username" placeholder="username"/><br>

        <label for="password">Password</label><br/>
        <input type="text" id="password" placeholder="password"/><br>

        <button id="login-btn" data-id="{{_id}}">Login!</button>

    </div> 

    <br><br>

    <!-- TEMP LOG-OUT BUTTON -->
    <b>Log out</b> 
    <br>
    <button id="logout-btn">Log out</button>


<!-- ============== TEMPLATES ============== -->

<!-- add sign-up and log-in templates -->

<!-- edit user account -->
    <template id="edit-user-template">
        <div id="edit-user-container" data-id="{{_id}}">

            <button id="account-delete-button">Delete account</button><br>

        </div>
    </template>

<!-- delete user account -->
    <template id="delete-user-template">
        <div id="delete-user-container" data-id="{{_id}}">
            Please confirm.
            <button id="delete-user-confirm-button" data-id="{{_id}}">Delete my account</button>
        </div>
    </template>

<!-- ============== END TEMPLATES ============== -->

    <script src="js/app.js"></script>

</body>
</html>

Thank you for any insights!

Community
  • 1
  • 1
A.J. Cee
  • 33
  • 5
  • Have a similar problem. When you log responses to the console, are you seeing 'undefined' prepended to the JSON response? I think it has something to do with chunking (the response data is written as a stream, and not a self contained object). Can you post some sample response data from the console? – ChrisBuck Jul 11 '17 at 06:48

0 Answers0