Answer
JSONPlaceholder with Flutter
JSONPlaceholder is a free, fake REST API service that provides placeholder JSON data for testing and prototyping. It's extremely useful for Flutter development when building apps that consume REST APIs.
What is JSONPlaceholder?
JSONPlaceholder (https://jsonplaceholder.typicode.com/) is a mock API service that provides:
- Fake but realistic JSON data
- RESTful API endpoints
- No authentication required
- Perfect for learning and testing
Available Endpoints
| Endpoint | Count | Description |
|---|---|---|
| /posts | 100 | Blog posts |
| /comments | 500 | Post comments |
| /albums | 100 | Photo albums |
| /photos | 5000 | Photos |
| /todos | 200 | Todo items |
| /users | 10 | User profiles |
Basic Implementation
Model Class:
dartclass Post { final int userId; final int id; final String title; final String body; Post({ required this.userId, required this.id, required this.title, required this.body, }); factory Post.fromJson(Map<String, dynamic> json) { return Post( userId: json['userId'], id: json['id'], title: json['title'], body: json['body'], ); } Map<String, dynamic> toJson() { return { 'userId': userId, 'id': id, 'title': title, 'body': body, }; } }
API Service:
dartimport 'package:http/http.dart' as http; import 'dart:convert'; class ApiService { static const String baseUrl = 'https://jsonplaceholder.typicode.com // GET request - Fetch all posts Future<List<Post>> getPosts() async { final response = await http.get(Uri.parse('$baseUrl/posts')); if (response.statusCode == 200) { List<dynamic> data = json.decode(response.body); return data.map((json) => Post.fromJson(json)).toList(); } else { throw Exception('Failed to load posts'); } } // GET request - Fetch single post Future<Post> getPost(int id) async { final response = await http.get(Uri.parse('$baseUrl/posts/$id')); if (response.statusCode == 200) { return Post.fromJson(json.decode(response.body)); } else { throw Exception('Failed to load post'); } } // POST request - Create new post Future<Post> createPost(Post post) async { final response = await http.post( Uri.parse('$baseUrl/posts'), headers: {'Content-Type': 'application/json'}, body: json.encode(post.toJson()), ); if (response.statusCode == 201) { return Post.fromJson(json.decode(response.body)); } else { throw Exception('Failed to create post'); } } // PUT request - Update post Future<Post> updatePost(int id, Post post) async { final response = await http.put( Uri.parse('$baseUrl/posts/$id'), headers: {'Content-Type': 'application/json'}, body: json.encode(post.toJson()), ); if (response.statusCode == 200) { return Post.fromJson(json.decode(response.body)); } else { throw Exception('Failed to update post'); } } // DELETE request - Delete post Future<void> deletePost(int id) async { final response = await http.delete(Uri.parse('$baseUrl/posts/$id')); if (response.statusCode != 200) { throw Exception('Failed to delete post'); } } }
UI Implementation
dartimport 'package:flutter/material.dart'; class PostsScreen extends StatefulWidget { _PostsScreenState createState() => _PostsScreenState(); } class _PostsScreenState extends State<PostsScreen> { final ApiService _apiService = ApiService(); late Future<List<Post>> _posts; void initState() { super.initState(); _posts = _apiService.getPosts(); } Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('JSONPlaceholder Demo'), ), body: FutureBuilder<List<Post>>( future: _posts, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } if (!snapshot.hasData || snapshot.data!.isEmpty) { return Center(child: Text('No posts found')); } return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) { final post = snapshot.data![index]; return ListTile( title: Text(post.title), subtitle: Text( post.body, maxLines: 2, overflow: TextOverflow.ellipsis, ), onTap: () { // Navigate to post detail }, ); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: _createNewPost, child: Icon(Icons.add), ), ); } Future<void> _createNewPost() async { final newPost = Post( userId: 1, id: 0, title: 'New Post', body: 'This is a new post created from Flutter', ); try { final createdPost = await _apiService.createPost(newPost); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Post created with ID: ${createdPost.id}')), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed to create post: $e')), ); } } }
Use Cases in Flutter Development
- Learning REST APIs: Practice HTTP requests without backend setup
- Prototyping: Test UI with realistic data
- Testing: Write unit and widget tests
- Demo Apps: Build portfolio projects
- API Integration Practice: Learn pagination, filtering, error handling
Dependencies
Add to
text
pubspec.yamlyamldependencies: http: ^1.1.0
Best Practices
- Use proper error handling
- Implement loading states
- Cache responses when appropriate
- Add retry logic for failed requests
- Use models for type safety
Important: JSONPlaceholder is perfect for development and testing, but remember it's a mock API. Data changes are simulated and don't persist. Use it for learning, then transition to real APIs for production.
Learn more at JSONPlaceholder Guide.