Building a RESTful Blog APIs using python and flask - Part 2
To be a programmer is to develop a carefully managed relationship with error. There's no getting around it. You either make your accommodations with failure, or the work will become intolerable - Ellen Ullman
Part 1
Summary FromIn part 1, we covered how to create a simple RESTful API with four basic CRUD operation and Authentication using Flask. We learned about configuring Flask environment, creating models, making and applying migrations to the DB, grouping resources using flask blueprint, validating the authenticity of a user using JWT token.
In this part, we will build the remaining four endpoints for blogpost resource
Blogpost API
The following endpoints will be created
- Create a Blogpost - POST
api/v1/blogposts
- Get All Blogposts - GET
api/v1/blogposts
- Get A Blogposts - GET
api/v1/blogposts/<int:blogpost_id>
- Update A Blogpost - PUT
api/v1/blogposts/<int:blogpost_id>
- Delete A Blogpost - DELETE
api/v1/blogposts/<int:blogpost_id>
api/v1/blogposts
Create a Blogpost - POST Open /src/views/BlogpostView.py
and add the following code
In the above code, we added a new endpoint POST /api/v1/blogpost
that would allow a user to create a new blogpost. Noticed with added @Auth.auth_required
decorator to create()
function to make sure only authenticated users can access the route. We also set up blogpost_api
blueprint so that we can group all blogpost endpoints in the same resource.
Let's test this endpoint on postman
Don't forget to add api-token to the header since we are only permitting registered users to create a post
api/v1/blogposts
Get All Blogposts - GET Get all blogpost endpoint will get all available blogpost in the system
Let's add a new function to /src/views/BlogpostView.py
and call it get_all
You'll notice we did not add @Auth.auth_required
decorator to get_all
, that is because we want to make that endpoint available to everybody - of course, you don't want to be the only one to read your posts .
Test on postman
api/v1/blogposts/<int:blogpost_id>
Get A Blogpost - GET This endpoint will get a single blogpost by it's id
. Just like Get all endpoint, we'll also make this available for everybody - registered users or unregistered users.
Test on postman
api/v1/blogposts/<int:blogpost_id>
Update A Blogpost - PUT Something to note before we create this endpoint
- Only registered users can access this endpoint
- Users can only update their own blogpost
- A user can not update another user's blogpost
To do this, let's create a new function and add@Auth.auth_required
decorator and also add a condition that checks if the postowner_id
is equal to the current user's id. If the owner_id is equal to user_id then go ahead and update the post, if not return an error back to the user
Test on postman
api/v1/blogposts/<int:blogpost_id>
Delete A Blogpost - DELETE This endpoint will allow a user to delete only their own post - meaning a user cannot delete another user's post.
Test on postman
CONCLUSION
This part covers the creation of create, get all, get one, update and delete
endpoints. We make get all and get one endpoints accessible to everyone and also added condition to delete and update endpoints so that a user can only update or delete their own post.
In part 3 of this series, we'll write unit test for our app and also host the app on heroku - you can call it 2 in 1 pack.
Click here if you haven't read PART 1
Click here to checkout the complete code on Github
Drop you questions, comment and don't forget to like this post if you learned one or two things from it
Same project, but with some improvements and with paypal service and email notifications https://github.com/jerichoruz/backbloggie
Once again Thank u very much Olawale . as for sept 2020 remember that the last version of sqlalchemy uses marshmallow 3
Changed in version 3.0.0b7: This method returns the deserialized data rather than a (data, errors) duple. A ValidationError is raised if invalid data are passed.
Change all the:
data, error = blogpost_schema.load(req_data)
to:
try:
data = blogpost_schema.load(req_data, partial=True)
except ValidationError as err:
return custom_response(err, 400)
and
data = blogpost_schema.dump(post).data
to:
data = blogpost_schema.dump(post)
to avoid
Python (flask/ marshmallow)ValueError: too many values to unpack (expected 2)
Nice and well explained. Keep it up. Thanks, Nishant