MR WHY

I am
Wang Hongyang

Wechat Official Account
Find fun things here!

Uber REST - Car, Driver, Passenger Entity

Hubert Wang
2016-09-21

Codes and Files Structure

GET

GET /api/cars

Get cars list.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// fake data
var cars = [{
                id: 1,
                year: 2012,
                maker: "BMW",
                model: "9 series",
                doorNum: 4,
                passNum: "123456",
                license: "mycar1",
                driverID: 1111111,
                insurance: "1000000"
            }, {
                id: 2,
                year: 2016,
                maker: "Porsche",
                model: "911 TURBO",
                doorNum: 2,
                passNum: "543210",
                license: "coolCar",
                driverID: 555555,
                insurance: "10000000"
            }];

router.route('/car')
    .get(function(req,res) {
        res.json(cars);
    })
  • Line 1~22: Define fake data for cars Object, properties: id, year, maker, model, door#, pass#, license, driverID, and insurance.
  • Line 24~27: Response body: cars list.

Unit Test Result

Unit Test Code:

// Test GET /api/cars
exports.car_should_return_cars = function(done){
    supertest(app)
    .get('/api/cars')
    .expect(200)
    .end(done);
};

Result: passing

Postman Result

Result: response body contains cars array.

GET /api/cars/:id

Get car by id.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
router.route('/cars/:id/')
    .get(function(req, res){
        var id = req.params.id;
        var carObj = cars.filter(function(element) {
            return element.id == id;
        })[0];
        if(carObj === undefined) {
            console.log("No car ID found!");
            res.end();
        } else {
            res.json(carObj);
            res.end();
        }
    })
  • Line 3: Get id from request parameters.
  • Line 4~6: Filter by car ID to get car Object.
  • Line 7~9: If corresponding id is not found, print alert in console.
  • Line 10~13: Else, print car Object.

Unit Test Result

Unit Test Code:

exports.car_should_return_json = function(done){
    supertest(app)
    .get('/api/cars/1/')
    .expect(200)
    .end(function(err,response){
        console.log(err);
        console.log(response.body);
        assert.ok(!err);
        assert.ok(typeof response.body === 'object');
        return done();
    });
};

Result: passing

Postman Result

Result: response body contains car Object.

GET /api/drivers/:id/car

Get car info by carID property in driver Object

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// get drive's car info
router.route('/drivers/:id/car')
    .get(function(req, res){
        var id = req.params.id;
        var driverObj = drivers.filter(function(element) {
            return element.id == id;
        })[0];
        if (driverObj === undefined) {
            // driver id not found
            console.log("No driver ID found!");
            res.sendStatus(400)
               .end();
        } else {
            // find car object
            var carObj = cars.filter(function(element) {
                return element.id == driverObj.carID;
            })[0];
            if (carObj === undefined) {
                // car id not found
                console.log("No car ID found!");
                res.sendStatus(400)
                   .end();
            } else {
                // print car Object
                res.json(carObj)
                   .end();
            }
        }
    })
  • Line 5~7: Get driver Object according to driverID.
  • Line 8~12: If driver ID not found, bad request.
  • Line 15~17: Get car Object by carID in driver Object.
  • Line 18~22: If car ID not found, bad request.
  • Line 24~27: Response with car Object.

Postman Result

Result: 200(OK), response body contains car Object, which is get via driver ID.

POST

POST /api/cars

Post a new car into car list.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// car property list, for POST to use when no Object in Array
var carsPropList = {id:"", year:"", maker:"", model:"", 
                    doorNum:"", passNum:"", license:"", 
                    driverID:"", insurance:""};

router.route('/car')
    .post(function(req,res) {
        var reqBody = req.body;
        var newCar = new Object();
        for (var prop in carsPropList) {
            // id should not be changed
            if (prop === "id") {newCar[prop] = cars.length+1;}  
            else {newCar[prop] = reqBody[prop];}
        }
        cars.push(newCar);
        res.sendStatus(200);
        console.log(cars);
    })
  • Line 2~4: Property list of cars are used in Line 38, helps to filter properties posted.
  • Line 6~18: Filter the properties in request body and keep id unchanged.

Unit Test Result

Unit Test Code:

exports.car_should_create_car = function(done){
    supertest(app)
    .get('/api/cars')
    .send({license: 'new license'})
    .expect(200)
    .end(function(err,response){
        console.log(err);
        console.log(response.body);
        assert.ok(!err);
        assert.ok(typeof response.body === 'object');
        return done();
    });
};

Result: Passing

Postman Result

Sent: car info with some property not exists in property list.

Result: Only properties contained in propertyList will be taken.

PATCH

PATCH /api/cars/:id

PATCH car info with some properties changed. Only the properties in request body should be changed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
router.route('/car/:id/') 
    .patch(function(req, res){
        var id = req.params.id;
        var carObj = cars.filter(function(element) {
            return element.id == id;
        })[0];
        if(carObj === undefined) {
            console.log("No car ID found!");
            res.sendStatus(400)
               .end();
        } else {
            var reqBody = req.body;
            for (var prop in carObj) {
                // id should not be changed
                if (prop === "id") {continue;}  
                // don't change undefined prop in req body
                if (reqBody[prop] !== undefined) {  
                    carObj[prop] = reqBody[prop];
                }
            }
            console.log(cars);
            res.sendStatus(200)
               .end();
        }
    })
  • Line 3: Get id from request parameters.
  • Line 4~6: Filter car Object by id.
  • Line 6~10: If car ID not found, bad request.
  • Line 15: Avoid the change of id.
  • Line 17~19: Find changed properties in request body. And only change those mentioned properties' value. If certain property is not mentioned in request body (that is, undefined), keep it unchanged.

Postman Result

Sent: Only two properties contained in request body. The result should be: only these two properties are changed and others keep unchanged.

Result: correct.

PUT

PUT /api/cars/:id

PUT car info with some properties changed. Different from PATCH, all properties should be updated according to request body.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
router.route('/car/:id/')
    .put(function(req, res){
        var id = req.params.id;
        var carObj = cars.filter(function(element) {
            return element.id == id;
        })[0];
        if(carObj === undefined) {
            console.log("No car ID found!");
            res.sendStatus(400)
               .end();
        } else {
            var reqBody = req.body;
            for (var prop in carObj) {
                // id should not be changed
                if (prop === "id") {continue;}  
                else {carObj[prop] = reqBody[prop];}
            }
            console.log(cars);
            res.sendStatus(200)
               .end();
        }
    })
  • Line 13~17: Here is only one difference between PATCH and PUT -- in PUT, if certain property is not mentioned/defined in request body, then the corresponding property will be set to undefined.

Postman Result

Sent: Only two properties contained in request body. The result should be: All properties are updated according to the request body.

Result: Correct.

DELETE

DELETE /api/cars/:id

DELETE a car Object from car Array by ID.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
router.route('/car/:id/')
    .delete(function(req, res){
        var id = req.params.id;  
        var filtered = cars.filter(function(element) {
            return element.id != id;
        });
        cars = filtered
        console.log(cars);
        res.sendStatus(200);
        res.end();
    })
  • Line 4~6: Use filter to leave out car Object by ID.

Postman Result

Result: the original car list and the list after DELETE car?id=1.


Update After Class

DATED AFTER CLASS - Error Handling:
+ Return 404 instead of 400 when id not found

GET /api/cars/3999 
404
{
    "statusCode": 404,
    "errorCode": "bad id",     
    "errorMsg": "3999 is not a valid ID"
}
  • GET api/drivers/1/car is not proper, because one driver can have many cars. Yet GET api/cars/1/drive makes sense.

14

分享本文:

TOC