- Description
- Purpose
- Requirements
- File Descriptions
- Environmental Variables
- Usage
- Bugs
- Authors
- License
hbnb is a full-stack clone of the web application AirBnB. This clone was built in four iterative phases. This version includes completion of Phase 1 from AirBnB_clone_v1: Console and web static, Phase 2 from AirBnB_clone_v2 plus Phase 3, which involves exposing stored objects via a JSON web interface and manipulating objects via a custom RESTful API.
The purpose of Phase 3 is to learn how to:
- create a RESTful API
- use CORS
- request RESTful API
- retrieve, create, update, delete a resource with HTTP methods
- All files compiled with Ubuntu 14.04 LTS
- Documentation
- Organized files in proper folders
- Python unit tests for all files
- All files must be pep8 compliant
Note: Below highlights only new file additions for Phase 3. For file descriptions from previous phases, click Phase 2 and Phase 1.
tests- unit test filesmodels- contains all class models for AirBnB objectsengine- contains storage engines__init__.py- empty__init__.pyfile for packagesfile_storage.py- classFileStorage; serializes instances to JSON file and deserializes from a JSON fileall- returns the dictionary__objectsnew- sets in__objectsthe obj with key<obj class name>.idsave- serializes__objectsto the JSON file (path:__file_path)reload- deserializes the JSON file to__objectsdelete- delete object from__objectsif existsclose- call reload
db_storage.py- classDBStorage__init__- initalize instancesall- return dictionary of instance attributesnew- add new object to current database sessionsave- commit all changes of the current database sessiondelete- delete from the current database session obj if not Nonereload- create all tables in database and current database sessionclose- close sessionget- retrieves an objectcount- counts number of objects of a class (if given)
api- containsv1andv1/viewsfolders__init__.py- empty__init__.pyfilev1- containsapp.pyfile andviewsfolder__init__.py- empty__init__.pyfileapp.py- app filetear- closes storage enginenot_found- handles 404 error and gives json formatted responseviews- contains views for AirBnB objects__init__.py- create blueprintamenities.py- view for Amenity objects that handles all default RestFul API actionslist_amenities- retrieves a list of all Amenity objectsget_amenity- retrieves an Amenity objectdelete_amenity- deletes an Amenity objectcreate_amenity- creates an Amenity objectupdates_amenity- updates an Amenity object
cities.py- view for City objects that handles all default RestFul API actionslist_cities_of_state- retrieves list of of City objectscreate_city- creates a Cityget_city- retrieves a City objectdelete_city- deletes a City objectupdates_city- updates a City object
index.py- index filestatus- routes to status pagecount- retrieves number of each objects by type
places.py- view for Place objects that handles all default RestFul API actionslist_places_of_city- retrieves list of of Place objects in citycreate_place- creates a Placeget_place- retrieves a Place objectdelete_place- deletes a Place objectupdates_place- updates a Place object
places_amenities.py- place-amenity viewlist_amenities_of_place- retrieves a list of all Amenity objects of a Placecreate_place_amenity- creates an Amenitydelete_place_amenity- deletes an Amenity objectget_place_amenity- retrieves an Amenity object
places_reviews.py- place-review viewlist_reviews_of_place- retrieves a list of all Review objects of a Placecreate_review- creates a reviewget_review- retrieves a Review objectdelete_review- deletes a Review objectupdates_review- updates a Review object
states.py- view for State objects that handles all default RestFul API actionslist_states- retrieves a list of all State objectsget_state- retrieves a State objectdelete_state- deletes a State objectcreate_state- creates a Stateupdates_state- updates a State object
users.py-list_users- retrieves list of of User objectscreate_user- creates a Userget_user- retrieves a User objectdelete_user- deletes a User objectupdates_user- updates a User object
HBNB_ENV: running environment. It can be “dev” or “test” for the moment (“production” soon!)HBNB_MYSQL_USER: the username of your MySQLHBNB_MYSQL_PWD: the password of your MySQLHBNB_MYSQL_HOST: the hostname of your MySQLHBNB_MYSQL_DB: the database name of your MySQLHBNB_TYPE_STORAGE: the type of storage used. It can be “file” (using FileStorage) or db (using DBStorage)
Run the following in your terminal:
Test get and count methods for FileStorage and DBStorage
user@ubuntu:~/AirBnB_v3$ cat test_get_count.py
#!/usr/bin/python3
""" Test .get() and .count() methods
"""
from models import storage
print("All objects: {}".format(storage.count()))
print("State objects: {}".format(storage.count("State")))
first_state_id = list(storage.all("State").values())[0].id
print("First state: {}".format(storage.get("State", first_state_id)))user@ubuntu:~/AirBnB_v3$ HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./test_get_count.py
All objects: 1013
State objects: 27
First state: [State] (f8d21261-3e79-4f5c-829a-99d7452cd73c) {'name': 'Colorado', 'updated_at': datetime.datetime(2017, 3, 25, 2, 17, 6), 'created_at': datetime.datetime(2017, 3, 25, 2, 17, 6), '_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7fc0103a8e80>, 'id': 'f8d21261-3e79-4f5c-829a-99d7452cd73c'}user@ubuntu:~/AirBnB_v3$ ./test_get_count.py
All objects: 19
State objects: 5
First state: [State] (af14c85b-172f-4474-8a30-d4ec21f9795e) {'updated_at': datetime.datetime(2017, 4, 13, 17, 10, 22, 378824), 'name': 'Arizona', 'id': 'af14c85b-172f-4474-8a30-d4ec21f9795e', 'created_at': datetime.datetime(2017, 4, 13, 17, 10, 22, 378763)}
....Check status of API Run this in one terminal window:
user@ubuntu:~/AirBnB_v3$ HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db HBNB_API_HOST=0.0.0.0 HBNB_API_PORT=5000 python3 -m api.v1.app
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
...And this in another terminal window:
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/status
{
"status": "OK"
}user@ubuntu:~/AirBnB_v3$ curl -X GET -s http://0.0.0.0:5000/api/v1/status -vvv 2>&1 | grep Content-Type
< Content-Type: application/jsonCheck number of objects by type
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/stats
{
"amenities": 47,
"cities": 36,
"places": 154,
"reviews": 718,
"states": 27,
"users": 31
}Create JSON formatted 404 status code response
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/nop
{
"error": "Not found"
}user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/nop -vvv
* Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to 0.0.0.0 (127.0.0.1) port 5000 (#0)
> GET /api/v1/nop HTTP/1.1
> Host: 0.0.0.0:5000
> User-Agent: curl/7.51.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 404 NOT FOUND
< Content-Type: application/json
< Content-Length: 27
< Server: Werkzeug/0.12.1 Python/3.4.3
< Date: Fri, 14 Apr 2017 23:43:24 GMT
<
{
"error": "Not found"
}Run HTTP methods for State
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/states/
[
{
"__class__": "State",
"created_at": "2017-04-14T00:00:02",
"id": "8f165686-c98d-46d9-87d9-d6059ade2d99",
"name": "Louisiana",
"updated_at": "2017-04-14T00:00:02"
},
{
"__class__": "State",
"created_at": "2017-04-14T16:21:42",
"id": "1a9c29c7-e39c-4840-b5f9-74310b34f269",
"name": "Arizona",
"updated_at": "2017-04-14T16:21:42"
},
...user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/states/8f165686-c98d-46d9-87d9-d6059ade2d99
{
"__class__": "State",
"created_at": "2017-04-14T00:00:02",
"id": "8f165686-c98d-46d9-87d9-d6059ade2d99",
"name": "Louisiana",
"updated_at": "2017-04-14T00:00:02"
} user@ubuntu:~/AirBnB_v3$ curl -X POST http://0.0.0.0:5000/api/v1/states/ -H "Content-Type: application/json" -d '{"name": "California"}' -vvv
* Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to 0.0.0.0 (127.0.0.1) port 5000 (#0)
> POST /api/v1/states/ HTTP/1.1
> Host: 0.0.0.0:5000
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 22
>
* upload completely sent off: 22 out of 22 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 195
< Server: Werkzeug/0.12.1 Python/3.4.3
< Date: Sat, 15 Apr 2017 01:30:27 GMT
<
{
"__class__": "State",
"created_at": "2017-04-15T01:30:27.557877",
"id": "feadaa73-9e4b-4514-905b-8253f36b46f6",
"name": "California",
"updated_at": "2017-04-15T01:30:27.558081"
}
* Curl_http_done: called premature == 0
* Closing connection 0user@ubuntu:~/AirBnB_v3$ curl -X PUT http://0.0.0.0:5000/api/v1/states/feadaa73-9e4b-4514-905b-8253f36b46f6 -H "Content-Type: application/json" -d '{"name": "California is so cool"}'
{
"__class__": "State",
"created_at": "2017-04-15T01:30:28",
"id": "feadaa73-9e4b-4514-905b-8253f36b46f6",
"name": "California is so cool",
"updated_at": "2017-04-15T01:51:08.044996"
}user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/states/feadaa73-9e4b-4514-905b-8253f36b46f6
{
"__class__": "State",
"created_at": "2017-04-15T01:30:28",
"id": "feadaa73-9e4b-4514-905b-8253f36b46f6",
"name": "California is so cool",
"updated_at": "2017-04-15T01:51:08"
}user@ubuntu:~/AirBnB_v3$ curl -X DELETE http://0.0.0.0:5000/api/v1/states/feadaa73-9e4b-4514-905b-8253f36b46f6
{}user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/states/feadaa73-9e4b-4514-905b-8253f36b46f6
{
"error": "Not found"
}Run HTTP methods for City
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/states/not_an_id/cities/
{
"error": "Not found"
}user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/states/not_an_id/cities/
{
"error": "Not found"
}
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/states/2b9a4627-8a9e-4f32-a752-9a84fa7f4efd/cities
[
{
"__class__": "City",
"created_at": "2017-03-25T02:17:06",
"id": "1da255c0-f023-4779-8134-2b1b40f87683",
"name": "New Orleans",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-03-25T02:17:06"
},
{
"__class__": "City",
"created_at": "2017-03-25T02:17:06",
"id": "45903748-fa39-4cd0-8a0b-c62bfe471702",
"name": "Lafayette",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-03-25T02:17:06"
},
{
"__class__": "City",
"created_at": "2017-03-25T02:17:06",
"id": "e4e40a6e-59ff-4b4f-ab72-d6d100201588",
"name": "Baton rouge",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-03-25T02:17:06"
}
]
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/cities/1da255c0-f023-4779-8134-2b1b40f87683
{
"__class__": "City",
"created_at": "2017-03-25T02:17:06",
"id": "1da255c0-f023-4779-8134-2b1b40f87683",
"name": "New Orleans",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-03-25T02:17:06"
}
user@ubuntu:~/AirBnB_v3$ curl -X POST http://0.0.0.0:5000/api/v1/states/2b9a4627-8a9e-4f32-a752-9a84fa7f4efd/cities -H "Content-Type: application/json" -d '{"name": "Alexandria"}' -vvv
* Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to 0.0.0.0 (127.0.0.1) port 5000 (#0)
> POST /api/v1/states/2b9a4627-8a9e-4f32-a752-9a84fa7f4efd/cities/ HTTP/1.1
> Host: 0.0.0.0:5000
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 22
>
* upload completely sent off: 22 out of 22 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 249
< Server: Werkzeug/0.12.1 Python/3.4.3
< Date: Sun, 16 Apr 2017 03:14:05 GMT
<
{
"__class__": "City",
"created_at": "2017-04-16T03:14:05.655490",
"id": "b75ae104-a8a3-475e-bf74-ab0a066ca2af",
"name": "Alexandria",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-04-16T03:14:05.655748"
}
* Curl_http_done: called premature == 0
* Closing connection 0
user@ubuntu:~/AirBnB_v3$ curl -X PUT http://0.0.0.0:5000/api/v1/cities/b75ae104-a8a3-475e-bf74-ab0a066ca2af -H "Content-Type: application/json" -d '{"name": "Bossier City"}'
{
"__class__": "City",
"created_at": "2017-04-16T03:14:06",
"id": "b75ae104-a8a3-475e-bf74-ab0a066ca2af",
"name": "Bossier City",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-04-16T03:15:12.895894"
}
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/cities/b75ae104-a8a3-475e-bf74-ab0a066ca2af
{
"__class__": "City",
"created_at": "2017-04-16T03:14:06",
"id": "b75ae104-a8a3-475e-bf74-ab0a066ca2af",
"name": "Bossier City",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-04-16T03:15:13"
}
user@ubuntu:~/AirBnB_v3$ curl -X DELETE http://0.0.0.0:5000/api/v1/cities/b75ae104-a8a3-475e-bf74-ab0a066ca2af
{}
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/cities/b75ae104-a8a3-475e-bf74-ab0a066ca2af
{
"error": "Not found"
}Using CORS
user@ubuntu:~/AirBnB_v3$ curl -X GET http://0.0.0.0:5000/api/v1/cities/1da255c0-f023-4779-8134-2b1b40f87683 -vvv
* Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to 0.0.0.0 (127.0.0.1) port 5000 (#0)
> GET /api/v1/states/2b9a4627-8a9e-4f32-a752-9a84fa7f4efd/cities/1da255c0-f023-4779-8134-2b1b40f87683 HTTP/1.1
> Host: 0.0.0.0:5000
> User-Agent: curl/7.51.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Access-Control-Allow-Origin: 0.0.0.0
< Content-Length: 236
< Server: Werkzeug/0.12.1 Python/3.4.3
< Date: Sun, 16 Apr 2017 04:20:13 GMT
<
{
"__class__": "City",
"created_at": "2017-03-25T02:17:06",
"id": "1da255c0-f023-4779-8134-2b1b40f87683",
"name": "New Orleans",
"state_id": "2b9a4627-8a9e-4f32-a752-9a84fa7f4efd",
"updated_at": "2017-03-25T02:17:06"
}
* Curl_http_done: called premature == 0
* Closing connection 0
GET /api/v1/states: Retrieves a list of all statesGET /api/v1/states/<state_id>: Retrieves a specific statePOST /api/v1/states: Creates a new statePUT /api/v1/states/<state_id>: Updates a specific stateDELETE /api/v1/states/<state_id>: Deletes a specific state
GET /api/v1/states/<state_id>/cities: Retrieves a list of all cities in a specific stateGET /api/v1/cities/<city_id>: Retrieves a specific cityPOST /api/v1/states/<state_id>/cities: Creates a new city in a specific statePUT /api/v1/cities/<city_id>: Updates a specific cityDELETE /api/v1/cities/<city_id>: Deletes a specific city
GET /api/v1/amenities: Retrieves a list of all amenitiesGET /api/v1/amenities/<amenity_id>: Retrieves a specific amenityPOST /api/v1/amenities: Creates a new amenityPUT /api/v1/amenities/<amenity_id>: Updates a specific amenityDELETE /api/v1/amenities/<amenity_id>: Deletes a specific amenity
GET /api/v1/cities/<city_id>/places: Retrieves a list of all places in a specific cityGET /api/v1/places/<place_id>: Retrieves a specific placePOST /api/v1/cities/<city_id>/places: Creates a new place in a specific cityPUT /api/v1/places/<place_id>: Updates a specific placeDELETE /api/v1/places/<place_id>: Deletes a specific place
GET /api/v1/users: Retrieves a list of all usersGET /api/v1/users/<user_id>: Retrieves a specific userPOST /api/v1/users: Creates a new userPUT /api/v1/users/<user_id>: Updates a specific userDELETE /api/v1/users/<user_id>: Deletes a specific user
GET /api/v1/places/<place_id>/reviews: Retrieves a list of all reviews for a specific placeGET /api/v1/reviews/<review_id>: Retrieves a specific reviewPOST /api/v1/places/<place_id>/reviews: Creates a new review for a specific placePUT /api/v1/reviews/<review_id>: Updates a specific reviewDELETE /api/v1/reviews/<review_id>: Deletes a specific review
- mirr-x