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

Sea Turtles - Shayla and Tamara #10

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

Sea Turtles - Shayla and Tamara #10

wants to merge 21 commits into from

Conversation

Myranae
Copy link

@Myranae Myranae commented Apr 26, 2022

No description provided.

Copy link

@anselrognlie anselrognlie left a comment

Choose a reason for hiding this comment

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

Looks good so far! I'd just suggest a little reorganization of the route file to its own folder, and keep pushing yourselves to try python syntax like list comprehensions when you have the chance.

app/routes.py Outdated
@@ -1,2 +1,55 @@
from flask import Blueprint
from flask import Blueprint, jsonify, abort, make_response

Choose a reason for hiding this comment

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

Consider moving this file into a routes folder. This is useful even when we don't have another set of routes to store there, since we'll be adding additional files, and having things grouped logically can help us find our way around our code.

app/__init__.py Outdated
Comment on lines 7 to 9
from .routes import bp
app.register_blueprint(bp)

Choose a reason for hiding this comment

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

👍

If you move the routes.py file this will need to change a little.

app/routes.py Outdated
Comment on lines 11 to 17
def to_dict(self):
return dict(
id=self.id,
name=self.name,
description=self.description,
color=self.color,
)

Choose a reason for hiding this comment

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

👍

This function to build a dictionary looks good. Formatting-wise, generally I indent the wrapped contents of a function call like this.

    def to_dict(self):
        return dict(
            id=self.id,
            name=self.name,
            description=self.description,
            color=self.color,
        )

app/routes.py Outdated
Comment on lines 19 to 29
planets = [
Planet(1, "Mercury", "Super small, comparatively", "slate gray"),
Planet(2, "Venus", "It's sooo hot!", "yellow-white"),
Planet(3, "Earth", "Home to humans", "blue-green"),
Planet(4, "Mars", "The red one", "red"),
Planet(5, "Jupiter", "The biggest of them all", "orange-yellow"),
Planet(6, "Saturn", "What beautiful rings it has!", "hazy yellow-brown"),
Planet(7, "Uranus", "Tilted sideways", "blue-green"),
Planet(8, "Neptune", "Giant, stormy, blue", "blue"),
Planet(9, "Maybe Pluto", "Is it really a planet??", "reddish-brown")
]

Choose a reason for hiding this comment

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

We'll be getting rid of this collection soon, but consider using named arguments here to help this be a little more self-documenting about what the various values are. Id and name are pretty clear, and description and color are probably ok, but having those named arguments would make it explicit, especially in a situation like this where the arguments are mostly a bunch of the same data type.

app/routes.py Outdated
Planet(9, "Maybe Pluto", "Is it really a planet??", "reddish-brown")
]

bp = Blueprint("planets", __name__, url_prefix="/planets")

Choose a reason for hiding this comment

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

👍

app/routes.py Outdated

bp = Blueprint("planets", __name__, url_prefix="/planets")

def validate_planet(id):

Choose a reason for hiding this comment

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

👍

Nice decision to pull this up above the two routes. And the validation method looks good, for both detecting a bad id, as well as an id with no record.

app/routes.py Outdated
abort(make_response({"Message":f"Planet ID {id} not found"}, 404))

@bp.route("", methods=["GET"])
def get_planets():

Choose a reason for hiding this comment

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

👍

Consider using a list comprehension for generating the result list. This would be especially nice since you have the to_dict instance method.

app/routes.py Outdated
return jsonify(results_list)

@bp.route("/<id>", methods=["GET"])
def get_planet(id):

Choose a reason for hiding this comment

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

👍

Single planet endpoint looks good. We're able to reuse that dictionary instance method and move most of the logic into the validation method. Note that the default status code is 200, so you could leave that off the return.

Copy link

@anselrognlie anselrognlie left a comment

Choose a reason for hiding this comment

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

Nice job finishing up solar system. This is a great foundation to keep working from for Task List and more! Keep an eye out for additional refactoring and error handling as you continue to work with APIs.


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

def create_app(test_config=None):

Choose a reason for hiding this comment

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

👍

Comment on lines +5 to +7
name = db.Column(db.String)
description = db.Column(db.String)
color = db.Column(db.String)

Choose a reason for hiding this comment

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

Consider setting some of these columns to have nullable=false. For example, should we be able to create a planet without a name?

@@ -0,0 +1,34 @@
"""Adds planet model

Choose a reason for hiding this comment

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

👍 Good descriptive message

Comment on lines +28 to +41
@pytest.fixture
def create_two_planets(app):
planet_one = Planet(
name="Mercury",
description="smallest planet",
color="magenta"
)
planet_two = Planet(
name="Mars",
description="maybe we will live here?",
color="reddish brown"
)
db.session.add_all([planet_one, planet_two])
db.session.commit()

Choose a reason for hiding this comment

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

👍
Because our SQL table is set to assign ids, it's fine to leave off the ids for the records as you did here.

The migration logic sets up the id behavior a little differently from how we did it when we worked with SQL manually, and would also allow us to set the ids explicitly. One nice thing about setting the id explicitly in a fixture is that we know what id to use in subsequent tests. If we don't, then we should still be able to assume that the ids will start from 1 and increment, but we probably shouldn't depend on it. So if we leave off the ids, then we'd probably want to return the two records in a list so that the test using these records could get their ids safely, regardless of what they were set to. This would look like:

@pytest.fixture
def create_two_planets(app):
    planet_one = Planet(
        name="Mercury",
        description="smallest planet",
        color="magenta"
    )
    planet_two = Planet(
        name="Mars",
        description="maybe we will live here?",
        color="reddish brown"
    )
    db.session.add_all([planet_one, planet_two])
    db.session.commit() 

    return [planet_one, planet_two]

And then in a test using the create_two_planets fixture, we could get the id of the first planet as create_two_planets[0].id


#assert
assert response.status_code == 404
assert response_body == None

Choose a reason for hiding this comment

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

Notice that in your 404 handling code, you return a message from the route, but the response body ends up being None. This is because the 404 handling code is using an un-jsonify'd string in the response, which Flask interprets as HTML rather than JSON. And if the response isn't set as JSON, then the call to get_json() returns None.

Comment on lines +24 to +28
new_planet = Planet(
name = request_body["name"],
description = request_body["description"],
color = request_body["color"]
)

Choose a reason for hiding this comment

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

This would be great to move into a @classmethod in the Planet model class.

And consider what would happen if one of the keys were missing from the request.

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

return make_response(jsonify(f"Planet {new_planet.name} successfully created"), 201)

Choose a reason for hiding this comment

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

I mentioned this in the test file as well, but consider returning the jsonify'd planet here rather than a status message, so the caller knows the id of the resource that was just created.

Comment on lines +41 to +50
planets = Planet.query

if name_param:
planets = planets.filter_by(name=name_param)
if description_param:
planets = planets.filter_by(description=description_param)
if color_param:
planets = planets.filter_by(color=color_param)

planets = planets.all()
Copy link

@anselrognlie anselrognlie May 9, 2022

Choose a reason for hiding this comment

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

Love the stacked query handling. 🙂

Check out https://docs.sqlalchemy.org/en/13/orm/tutorial.html#common-filter-operators for some other examples of the kinds of queries we can build up.

Comment on lines +56 to +63
planets_response.append(
{
"id": planet.id,
"name": planet.name,
"description": planet.description,
"color": planet.color
}
)

Choose a reason for hiding this comment

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

This would be a greta spot to use your to_dict helper.

        planets_response.append(planet.to_dict())

And we might consider using a list comprehension since it's so short now:

    planets_response = [planet.to_dict() for planet in planets]

Comment on lines +87 to +89
planet.name = request_body["name"]
planet.description = request_body["description"]
planet.color = request_body["color"]

Choose a reason for hiding this comment

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

Consider moving this to an instance method in Planet. And again, consider what would happen if one of the keys were missing.

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