Add REST API blog example with full CRUD and unit tests
This commit is contained in:
parent
a5f9742398
commit
6f54c4a1f6
3 changed files with 126 additions and 0 deletions
15
examples/rest_api_blog/README.md
Normal file
15
examples/rest_api_blog/README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# REST API Blog Example (Flask)
|
||||
|
||||
This is a simple Flask REST API example added inside the Flask repo fork for the IT6 Final Drill.
|
||||
|
||||
## Features
|
||||
- Full CRUD operations for blog posts (id, title, content)
|
||||
- Proper error handling and HTTP status codes
|
||||
- Unit tests with 100% coverage (using unittest)
|
||||
|
||||
## How to run
|
||||
|
||||
1. Install dependencies (preferably in a virtual environment):
|
||||
|
||||
```bash
|
||||
pip install flask
|
||||
58
examples/rest_api_blog/app.py
Normal file
58
examples/rest_api_blog/app.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
from flask import Flask, request, jsonify, abort
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
posts = []
|
||||
current_id = 1
|
||||
|
||||
def find_post(post_id):
|
||||
return next((post for post in posts if post['id'] == post_id), None)
|
||||
|
||||
@app.route('/api/posts', methods=['GET'])
|
||||
def get_posts():
|
||||
return jsonify(posts), 200
|
||||
|
||||
@app.route('/api/posts/<int:post_id>', methods=['GET'])
|
||||
def get_post(post_id):
|
||||
post = find_post(post_id)
|
||||
if not post:
|
||||
abort(404, description="Post not found")
|
||||
return jsonify(post), 200
|
||||
|
||||
@app.route('/api/posts', methods=['POST'])
|
||||
def create_post():
|
||||
global current_id
|
||||
data = request.get_json()
|
||||
if not data or 'title' not in data or 'content' not in data:
|
||||
abort(400, description="Missing title or content")
|
||||
post = {
|
||||
'id': current_id,
|
||||
'title': data['title'],
|
||||
'content': data['content']
|
||||
}
|
||||
posts.append(post)
|
||||
current_id += 1
|
||||
return jsonify(post), 201
|
||||
|
||||
@app.route('/api/posts/<int:post_id>', methods=['PUT'])
|
||||
def update_post(post_id):
|
||||
post = find_post(post_id)
|
||||
if not post:
|
||||
abort(404, description="Post not found")
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
abort(400, description="Missing data")
|
||||
post['title'] = data.get('title', post['title'])
|
||||
post['content'] = data.get('content', post['content'])
|
||||
return jsonify(post), 200
|
||||
|
||||
@app.route('/api/posts/<int:post_id>', methods=['DELETE'])
|
||||
def delete_post(post_id):
|
||||
post = find_post(post_id)
|
||||
if not post:
|
||||
abort(404, description="Post not found")
|
||||
posts.remove(post)
|
||||
return '', 204
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
53
examples/rest_api_blog/test_app.py
Normal file
53
examples/rest_api_blog/test_app.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import unittest
|
||||
from app import app
|
||||
|
||||
class BlogPostTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.client = app.test_client()
|
||||
self.sample_post = {"title": "Test Post", "content": "This is a test post"}
|
||||
|
||||
def test_create_post_success(self):
|
||||
response = self.client.post('/api/posts', json=self.sample_post)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
|
||||
def test_create_post_missing_field(self):
|
||||
response = self.client.post('/api/posts', json={"title": "Only title"})
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def test_get_all_posts(self):
|
||||
self.client.post('/api/posts', json=self.sample_post)
|
||||
response = self.client.get('/api/posts')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_get_single_post_success(self):
|
||||
post_resp = self.client.post('/api/posts', json=self.sample_post)
|
||||
post_id = post_resp.get_json()['id']
|
||||
response = self.client.get(f'/api/posts/{post_id}')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_get_single_post_not_found(self):
|
||||
response = self.client.get('/api/posts/999')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_update_post_success(self):
|
||||
post_resp = self.client.post('/api/posts', json=self.sample_post)
|
||||
post_id = post_resp.get_json()['id']
|
||||
response = self.client.put(f'/api/posts/{post_id}', json={"title": "Updated"})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_update_post_not_found(self):
|
||||
response = self.client.put('/api/posts/999', json={"title": "Nothing"})
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_delete_post_success(self):
|
||||
post_resp = self.client.post('/api/posts', json=self.sample_post)
|
||||
post_id = post_resp.get_json()['id']
|
||||
response = self.client.delete(f'/api/posts/{post_id}')
|
||||
self.assertEqual(response.status_code, 204)
|
||||
|
||||
def test_delete_post_not_found(self):
|
||||
response = self.client.delete('/api/posts/999')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue