简体   繁体   English

简单的Node.JS REST API调用

[英]Simple Node.JS REST API call

I have a simple app that requires a REST API call to perform CRUD (Create,Read,Update,Delete). 我有一个简单的应用程序,需要REST API调用才能执行CRUD(创建,读取,更新,删除)。 However, i can't seem to get the REST API working. 但是,我似乎无法使REST API正常工作。

When it's executing the put operation, i'm getting 当它执行put操作时,我得到

"api.js:81 Uncaught (in promise) SyntaxError: Unexpected end of JSON input at callAPI (api.js:81)" “ api.js:81未捕获(承诺)SyntaxError:在callAPI(api.js:81)上意外的JSON输入结尾”

I'm using Api.js to check the API calls. 我正在使用Api.js检查API调用。

api-photos.js api-photos.js

//photos.js
var express = require('express');
var router = express.Router();
var multer = require('multer');
var photoController = require('../../controllers/photoController');
var upload = multer({
  storage: photoController.storage,
  fileFilter: photoController.imageFilter
});

//import PhotoService
const PhotoService = photoController.PhotoService;

router.use((req, res, next)=>{
  //set mime type for all request and origin
  res.set({
    'Access-Control-Allow-Origin':'*',
    'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,OPTIONS',
    "Access-Control-Allow-Headers":"Content-Type, Access-Control-Allow-Headers",
    'Content-type':'applicaion/json'
  });
  if(req.method == 'OPTIONS'){
    return res.status(200).end();
  }
  next();
})
// photos - list
router.get('/', (req, res, next)=>{
  PhotoService.list()
  //returns promise - argument passed photos
    .then((photos)=>{
      console.log(`API: Found images: ${photos}`);
      res.status(200);
      //set content type header to application/json - set correct mime type
      res.send(JSON.stringify(photos));
    });
})

// photos/:photoid - find
router.get('/:photoid', (req, res, next)=>{
  PhotoService.read(req.params.photoid)
  //returns promise - argument passed photos
    .then((photo)=>{
      console.log(`API: Found images: ${photo}`);
      res.status(200);
      //set content type header to application/json - set correct mime type
      res.send(JSON.stringify(photo));
    }).catch((err)=>{
  });
});

// /photos POST create

router.post('/', upload.single('image'), async (req, res, next)=>{
  var path = "/static/img/" + req.file.filename;

  var photo = {
    originalname: req.file.originalname,
    mimetype: req.file.mimetype,
    imageurl: path,
    title: req.body.title,
    filename: req.file.filename,
    description: req.body.description,
    size: req.file.size / 1024 | 0
  }
//calling on photo service to return json object
  try{
    const photoSave = await PhotoService.create(photo);
    res.status(201);
    res.send(JSON.stringify(photoSave));
  }catch(err){
    console.log(err);
    throw new Error("PhotoSaveError", photo);
  }

});

// /photos/photoid: PUT - update
  router.put('/:photoid', (req, res, next)=>{
    console.log(`putting ${req.params.photoid}`);
    let putdata = req.body;
    PhotoService.update(req.params.photoid, putdata)
       console.log()
      .then((updatePhoto)=>{
        res.status(200);
        res.send(JSON.stringify(updatedPhoto));
      }).catch((err)=> {
        res.status(404);
        res.end();
    });
  });

// /photos/photoid: DELETE - delete
  router.delete('/:photoid', (req, res, next)=>{
    PhotoService.delete(req.params.photoid)
      .then((photo) => {
        console.log(`Found images: $(photo)`);
        res.status(200);
        res.send(JSON.stringify(photo));
      }).catch((err)=> {
        res.status(404);
        res.end();
      });;
  });



module.exports = router;

photo.js photo.js

//photos.js
var express = require('express');
var router = express.Router();
var app = express();
var multer = require('multer');
var photoController = require('../controllers/photoController');
var flash = require('express-flash');

//create upload object- intialize
var upload = multer({
  storage: photoController.storage,
  fileFilter: photoController.imageFilter
});

//Photo model import is required
var Photo = require('../models/photoModel');
const PhotoService = photoController.PhotoService

//flash messaging
router.use(flash());

//LIST - Get request to search database for our photos
router.get('/', (req, res, next)=>{
//search the DB for the photos
  PhotoService.list()
    .then((photos)=>{
//call photos view
      res.render('photos', {
        photos : photos,
        flashMsg: req.flash("fileUploadError")
    });
  })
  .catch((err)=>{
    if (err) {
      res.end("ERROR!");
    }
  });
});

//FIND - route for getting photo Details with form for editing
router.get('/:photoid', (req, res, next)=>{
  console.log("finding "+req.params.photoid);
  PhotoService.read({'_id': req.params.photoid})
//return promoise then handle it to render photo
    .then((photo)=>{
      res.render('updatePhoto', {
        photo: photo,
        flashMsg: req.flash("photoFindError")
      });
    }).catch((err)=>{
      if (err) console.log(err);
    });
});

//DELETE - route for deleting the photos
router.delete('/delete/:photoid', function(req, res){
  PhotoService.delete({'_id': req.params.photoid})
  .then((photos) => {
      res.redirect('/photos');
  });
});

//UPDATE - route for posting newly updated details
router.post('/:photoid', (req, res, next)=>{
  PhotoService.update({'_id': req.params.photoid})
//return promoise then set photo data details
    .then((photo)=>{
      var data = {
          title: req.body.title,
          description: req.body.description
          }
//set the data, save the photo details and redirect to photo list
      photo.set(data);
      photo.save().then(()=>{
        res.redirect('/photos');
      });
    })
    .catch((err)=>{
      if (err) console.log(err);
  });
});

//CREATE - post fields to the server and save them
router.post('/', upload.single('image'), (req, res, next)=>{
  var path = "/static/img/" + req.file.filename;
  var photo = {
    originalname: req.file.originalname,
    mimetype: req.file.mimetype,
    imageurl: path,
    title: req.body.title,
    filename: req.file.filename,
    description: req.body.description,
    size: req.file.size / 1024 | 0
  }
//Saving photo to DB
  var photo = new Photo(photo);
  photo.save()
    .then(()=>{
      //redirect after save, if succesfull
      res.redirect('/photos');
    })
    //Catch error  logs error
    .catch((err)=>{
      if (err){
        console.log(err);
        throw new Error("PhotoSaveError", photo);
      }
    });
});

//function will get called if above gets unhandled error - flash to display image and redirect
router.use(function(err, req, res, next){
  console.error(err.stack);
  if (err.message == "OnlyImageFilesAllowed"){
      req.flash('fileUploadError', "Please select an image file with jpg, png, or gif")
      res.redirect('/photos');
//2nd condition error if there was a problem saving
  } else if (err.message == "PhotoSaveError"){
    req.flash('photoSaveError', "There was a problem saving the photo")
    res.redirect('/photos');
  } else{
    next(err);
  }
});

//export the module
module.exports = router;

api.js api.js

// wrap in IIFE to control scope
(function(){

   const baseURL = 'http://localhost:8080';

   function testAPIs(){
    // test list first
    var testId = '';
    var testJSON = {};

    // list
    callAPI('GET', '/api/photos', null, null)
      .then((list)=>{
        console.log('\n\n***************************\nlist results:');
        console.log(list);
        testId = list[0]._id;

        // create
        let input = document.querySelector('input[type="file"]')
        let data = new FormData()
        data.append('image', input.files[0]);
        data.append('title', 'My API Test Title');
        data.append('description','This is an AJAX API test');
        callAPI('POST', '/api/photos', null, data)
          .then((photo)=>{
            photoId = photo._id;
            savedPhoto = photo;  // keep a handle to the created photo object
            console.log('\n\n***************************\ncreate results:');
            console.log(photo);

            // find
            callAPI('GET','/api/photos/'+photoId, null, null)
              .then((photo)=>{
                console.log('\n\n***************************\nfind results:');
                console.log(photo);

                // update
                testJSON.description += ' appended by the AJAX API ';
                callAPI('PUT','/api/photos/'+photoId, null, savedPhoto)
                  .then((photo)=>{
                    console.log('\n\n***************************\nupdate results:');
                    console.log(photo);

                    //delete
                    callAPI('DELETE', '/api/photos/'+photoId, null, null)
                     .then((result)=>{
                       console.log('\n\n***************************\ndelete result:');
                       console.log(result);
                     })
                });
            });
        });
    })
    .catch((err)=>{
      console.error(err);
    });
}


  async function callAPI(method, uri, params, body){
    jsonMimeType = {
      'Content-type':'application/json'
    }
    try{
      /*  Set up our fetch.
       *   'body' to be included only when method is POST
       *   If 'PUT', we need to be sure the mimetype is set to json
       *      (so bodyparser.json() will deal with it) and the body
       *      will need to be stringified.
       *   '...' syntax is the ES6 spread operator.
       *      It assigns new properties to an object, and in this case
       *      lets us use a conditional to create, or not create, a property
       *      on the object. (an empty 'body' property will cause an error
       *      on a GET request!)
       */
      var response = await fetch(baseURL + uri, {
        method: method, // GET, POST, PUT, DELETE, etc.
        ...(method=='POST' ? {body: body} : {}),
        ...(method=='PUT' ?  {headers: jsonMimeType, body:JSON.stringify(body)} : {})
      });
      return response.json(); // parses response to JSON
    }catch(err){
      console.error(err);
      return "{'status':'error'}";
    }
  }

  // Calls our test function when we click the button
  //  afer validating that there's a file selected.
  document.querySelector('#testme').addEventListener("click", ()=>{
    let input = document.querySelector('input[type="file"]')
    if (input.value){
      testAPIs();
    }else{
      alert("please select an image file first");
    }
  });
})();

Here is an update PUT handler which should stop throwing "undefined .then of ...", note that updatePhoto needed to be renamed to updatedPhoto as well. 这是一个更新PUT处理程序,该处理程序应停止updatePhoto “ ...的未定义updatePhoto ”,请注意, updatePhotoupdatedPhoto重命名为updatedPhoto

router.put('/:photoid', (req, res, next) => {
  console.log(`putting ${req.params.photoid}`);
  let putdata = req.body;
  PhotoService.update(req.params.photoid, putdata).then((updatedPhoto) => {
      res.status(200);
      res.send(JSON.stringify(updatedPhoto));
    }).catch((err) => {
      res.status(404);
      res.end();
    });
});

And if you are using node 8+ you can use async/await. 如果您使用的是节点8+,则可以使用async / await。 It simplifies the code and makes the problems easier to see: 它简化了代码并使问题更容易发现:

router.put('/:photoid', async (req, res, next) => {
  try {
    console.log(`putting ${req.params.photoid}`);
    let putdata = req.body;
    const updatedPhoto = await PhotoService.update(req.params.photoid, putdata);
    res.status(200);
    res.send(JSON.stringify(updatedPhoto));
  } catch (e) {
    res.status(404);
    res.end();
  }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM