Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SHARKS - Jande R. and Lindsey S. #7

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

janderoyalty
Copy link

No description provided.

@janderoyalty janderoyalty changed the title SHARKS = Jande R. and Lindsey S. SHARKS - Jande R. and Lindsey S. Apr 26, 2022
Copy link

@audreyandoy audreyandoy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part 1 looks great 👍

app/__init__.py Outdated
Comment on lines 6 to 9

from .routes import planets_bp
app.register_blueprint(planets_bp)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Looks good! We can also move this file into a routes folder which would change the path of this import. Creating a routes folder makes sense if we have different routes for specific objects for example planet_routes, moon_routes, galaxy_routes, etc.

app/routes.py Outdated
Comment on lines 4 to 19
class Planet():
def __init__(self, id, name, description, circumference, length_of_year):
self.id = id
self.name = name
self.description = description
self.circumference = circumference
self.length_of_year = length_of_year

def to_json(self):
return {
"id" : self.id,
"name" : self.name,
"description" : self.description,
"circumference" : self.circumference,
"length_of_year" : self.length_of_year
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 LGTM (looks good to me)

app/routes.py Outdated
Planet(6, "Saturn", "sun's bae with all 7 rings", 235185, 10620),
Planet(7, "Uranus", "can only be seen with a telescope", 99739, 30240),
Planet(8, "Neptune", "it is an intense blue color", 96645, 59400),
Planet(9, "Pluto", "no dwarf in my book", 7144, 88920)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Pluto is a planet 💯

app/routes.py Outdated
Comment on lines 36 to 46
def get_all_planets():
planets_response = []
for planet in planets:
planets_response.append({
"id": planet.id,
"name": planet.name,
"description": planet.description,
"circumference": planet.circumference,
"length of year": planet.length_of_year
})
return jsonify(planets_response)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we can use our handy dandy to_json() helper method in the Planet class. And we should also return a 200 status code.

def get_all_planets():
	planets_response = []
	for planet in planets:
		planets_response.append(planet.to_json())
	return jsonify(planets_response), 200

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also use list comprehension to build planets_response.

app/routes.py Outdated
Comment on lines 49 to 58
def get_one_planet(id):
try:
id = int(id)
except:
return abort(make_response({"message":f"Planet {id} is invalid."}, 400))

for planet in planets:
if planet.id == id:
return jsonify(planet.to_json())
return abort(make_response({"message":f"Planet {id} not found."}, 404))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of a try/except. The validation for bad id's and for id's with no record looks good. We can also consider moving the validation portion of this function into a helper method.

app/routes.py Outdated

for planet in planets:
if planet.id == id:
return jsonify(planet.to_json())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget the status code!

Copy link

@audreyandoy audreyandoy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jande and Lindsey! Great work in finishing solar system. I have provided comments on small ways y'all can improve the API.

🦈 ✨

Comment on lines +2 to +31
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from dotenv import load_dotenv
import os

db = SQLAlchemy()
migrate = Migrate()
load_dotenv()

def create_app(test_config=None):
app = Flask(__name__)

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

if not test_config:
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get(
"SQLALCHEMY_DATABASE_URI")
else:
app.config["TESTING"] = True
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get(
"SQLALCHEMY_TEST_DATABASE_URI")

db.init_app(app)
migrate.init_app(app, db)

from app.models.planet import Planet

from .routes import planets_bp
app.register_blueprint(planets_bp)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Good work setting up the Flask app!

Comment on lines +1 to +15
from flask import abort, make_response
from .planet import Planet

def validate_planet(id):
try:
id = int(id)
except:
return abort(make_response({"message": f"planet {id} is invalid"}, 400))

planet = Planet.query.get(id)

if not planet:
abort(make_response({"message": f"planet {id} not found"}, 404))

return planet

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helpers look great! 👍 We may want to consider making the validation code as generic as possible to process any class and id or renaming this file to helper_planet_routes or planet_routes_helper. Either would be helpful if we expand this project to contain more routes for moons, suns, etc.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more generic validation helper method would look like:

from flask import make_response, abort

def validate_object(cls, id):
    try:
        id = int(id)
    except:
        return abort(make_response({"message": f"{cls} {id} is invalid"}, 400))

    obj = cls.query.get(id)
    
    if not obj:
        abort(make_response({"message": f"{cls} {id} not found"},404))
    
    return obj

Comment on lines +4 to +9
class Planet(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String)
description = db.Column(db.String)
circumference = db.Column(db.Integer)
length_of_year= db.Column(db.Integer)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be able to make planets with no name? To prevent our API from creating a planet with a null name, we can set that column to nullable = False.

class Planet(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String, nullable=False)
    description = db.Column(db.String)
    circumference = db.Column(db.Integer)
    length_of_year= db.Column(db.Integer)

Comment on lines +11 to +31
def to_json(self):
return {
"id" : self.id,
"name" : self.name,
"description" : self.description,
"circumference" : self.circumference,
"length_of_year" : self.length_of_year
}

#update
def update(self, request_body):
self.name = request_body["name"]
self.description = request_body["description"]
self.circumference = request_body["circumference"]
self.length_of_year = request_body["length_of_year"]

@classmethod
def create(cls, request_body):
new_planet = cls(name = request_body["name"], description = request_body["description"], circumference = request_body["circumference"], length_of_year = request_body["length_of_year"])

return new_planet

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Nice helper methods and use of a class method!

Comment on lines +10 to +19
@planets_bp.route("", methods = ["POST"])
def create_planet():
request_body = request.get_json()

new_planet = Planet.create(request_body)

db.session.add(new_planet)
db.session.commit()

return jsonify(f"Planet {new_planet.name} has been successfully created"), 201 #use make response when you want to return something that is not json

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! We could also consider validating the request_body in a separate helper function.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To add onto your comment about make_response, we can also use it when we want to add additional headers to a response. Here are some examples in the documentation:
https://flask.palletsprojects.com/en/2.0.x/api/#flask.make_response

Comment on lines +56 to +62

# {
# name:
# description:
# circumference:
# length_of_year:
# }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can get rid of unneeded comments when submitting code for review.

Comment on lines +49 to +52
@planets_bp.route("/<id>", methods = ["GET"])
def get_one_planet(id):
planet = validate_planet(id)
return jsonify(planet.to_json()), 200

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice helper! Also, if a view function returns a dictionary (planet.to_json() in this case), Flask will automatically convert the dictionary into a JSON response object (aka Flask will turn dictionaries into JSON data for us). This means you can leave out make_response() like so:

@planets_bp.route("/<planet_id>", methods=["GET"])
def read_one_planet(planet_id):
    planet = validate_planet(planet_id)
    return planet.to_json(), 200

Here's the documentation with more info:
https://flask.palletsprojects.com/en/2.0.x/quickstart/#apis-with-json

Comment on lines +84 to +91
@planets_bp.route("/<id>", methods=["DELETE"])
def delete_one_planet(id):
planet = validate_planet(id)

db.session.delete(planet)
db.session.commit()

return make_response(f"Planet #{id} was successfully deleted"), 200

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we pass a string to make_response, Flask will assume that we want to return HTML rather than JSON data. make_response is useful when we want to attach headers to a response but in this case, we're simply returning JSON, so jsonify() is sufficient enough.

return jsonify(f"Planet {id} successfully deleted"), 200

Comment on lines +29 to +39
@pytest.fixture
def two_saved_planets(app):
# Arrange
mercury = Planet(name="Mercury",
description="made mostly of rocks", circumference=9522, length_of_year = 88)
venus = Planet(name="Venus",
description="most like Earth", circumference=23617, length_of_year=225)

db.session.add_all([mercury, venus])
# Alternatively, we could do# db.session.add(mercury)# db.session.add(venus)
db.session.commit()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Nice work on setting up the fixtures!

@@ -0,0 +1,70 @@

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Nice work on the tests!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants