π§ͺ mayr_fake_api
No internet? No backend? No problem.
A lightweight fake API simulator for Flutter and Dart apps β perfect for local development, prototyping, and offline testing.
With mayr_fake_api, you can simulate real REST API calls using simple JSON files β no server required.
π Overview
mayr_fake_api intercepts network requests (e.g. from Dio or http) and serves data from local JSON files in your Flutter appβs assets/ directory.
Itβs designed to make your development flow smoother, faster, and independent of backend delays.
π Features
- πΎ Use local JSON files to simulate REST endpoints.
- π§ Supports folder-structured routing (e.g.
/api/user/profile.json). - β‘ Supports multiple HTTP methods (
GET,POST,PUT,DELETE, etc.) using method-specific JSON naming. - β Built-in 404 simulation with customizable resolver.
- πͺ Dynamic data support (custom resolvers and generators).
- π§± Lightweight β no dependencies on backend servers.
- π§ Ideal for demos, offline-first apps, and rapid prototyping.
- βοΈ Enable or disable fake mode at runtime
- π§ Simulate network delays
π οΈ Installation
Add this to your pubspec.yaml:
dependencies:
mayr_fake_api: ^1.0.0
Then import it:
import 'package:mayr_fake_api/mayr_fake_api.dart';
π§© Directory Structure
By default, your fake API data can live anywhere in your project, but the conventional layout is:
assets/
api/
user/
profile/
get.json
post.json
put.json
delete.json
error.json
Each JSON file corresponds to a simulated endpoint.
And the JSON structures should contain statusCode and data. Example
{
"statusCode": 201,
"data": {
// ... The data here
}
}
π‘ How It Works
-
When you make a GET request to
/api/user/profile, the package looks forapi/user/profile/get.json. -
When you make a POST request to
/api/user/profile, it looks forapi/user/profile/post.json. -
You can use any folder structure, e.g.:
api/user/profile/get.json api/user/profile/update/post.json -
If the file doesnβt exist, it returns a 404 response by default β but you can override that with a custom not-found resolver.
π§± Example Usage
1. Simple setup
import 'package:dio/dio.dart';
import 'package:mayr_fake_api/mayr_fake_api.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final dio = Dio();
await MayrFakeApi.init(
basePath: 'assets/api',
attachTo: dio,
delay: Duration(milliseconds: 500),
enabled: kDebugMode,
// resolveNotFound: ...
//
);
runApp(MyApp());
}
2. Make a request
final response = await dio.get('https://example.com/api/user/profile');
This will attempt to load api/user/profile/get.json.
π§© Handling 404 Responses
If a requested JSON file doesnβt exist, a 404 is returned automatically.
You can customize what happens using:
MayrFakeApi.resolveNotFound((path, method) {
return MayrFakeResponse(
statusCode: 404,
data: {'error': 'No fake endpoint found for $method $path'},
);
});
π¨ Simulating Errors
To simulate API errors, create an error.json file in any directory.
The error file can contain:
{
"statusCode": 500,
"data": {
"code": 500,
"message": "Internal server error",
"details": "Something went wrong"
}
}
When the API detects this file, it throws a fake error response automatically.
If the statusCode is missing or set to 200, the error file is ignored
βοΈ Dynamic Data
Excellent β thatβs a smart and elegant convention π
Using a reserved folder (like -) to signal dynamic data routes keeps things clean and file-based while still flexible.
Hereβs the rewritten Dynamic Data section for your mayr_fake_api README, following your api/user/-/profile/get.json pattern π
βοΈ Dynamic Data
Dynamic routes let you simulate responses that change depending on runtime input β for example, when you want user-specific data, random IDs, or timestamps β all while keeping your API file-based.
To define a dynamic endpoint, include a - segment in your path.
For example:
api/
user/
-/
profile/
get.json
The - folder acts as a dynamic wildcard that can represent any runtime value.
Example Usage
If you make a request like:
final response = await dio.get('https://example.com/api/user/123/profile');
The package will automatically match and resolve:
api/user/-/profile/get.json
instead of looking for a literal /user/123/ path.
Dynamic Placeholder Replacement
Inside your dynamic JSON files, you can also reference the wildcard values using placeholders like:
{
"statusCode": 200,
"data": {
"userId": "$1",
"name": "Dynamic user",
"timestamp": "$timestamp"
}
}
Where $1 will be replaced with the first wildcard value (e.g. 123)
and $timestamp automatically resolves to the current ISO timestamp.
Example in Action
Given this structure:
api/
user/
-/
profile/
get.json
and get.json containing:
{
"statusCode": 200,
"data": {
"userId": "$1",
"name": "User $1",
"timestamp": "$timestamp"
}
}
A request like:
final res = await api.request('/user/42/profile', method: 'GET');
print(res.data);
will output something like:
{
"statusCode": 200,
"data": {
"id": "42",
"name": "User #42",
"fetched_at": "2025-10-06T12:34:56.789Z"
}
}
Notes
- You can include multiple wildcards, e.g.
/api/user/-/posts/-/get.json. Placeholders$1,$2,$3, etc. will be replaced accordingly. - If no placeholder is found, the file is returned as-is.
- Works seamlessly with all HTTP methods (
GET,POST, etc.).
πͺΆ Empty JSON Files
If a JSON file exists but is empty, the API returns a 204 No Content response automatically.
π Example Directory Recap
api/
user/
profile/
get.json -> returns profile data
post.json -> simulate POST update
error.json -> simulate error
products/
get.json -> product listing
details/get.json -> single product details
π§ͺ Example Usage
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final dio = Dio(
// ... DIO setup here
);
await MayrFakeApi.init(
basePath: 'assets/api',
attachTo: dio,
delay: Duration(milliseconds: 500),
);
// rest of code
}
void elsewhere() async {
final response = await dio.get('api/user');
}
π’ Additional Information
π€ Contributing
Contributions are highly welcome! If you have ideas for new extensions, improvements, or fixes, feel free to fork the repository and submit a pull request.
Please make sure to:
- Follow the existing coding style.
- Write tests for new features.
- Update documentation if necessary.
Let's build something amazing together!
π Reporting Issues
If you encounter a bug, unexpected behaviour, or have feature requests:
- Open an issue on the repository.
- Provide a clear description and steps to reproduce (if it's a bug).
- Suggest improvements if you have any ideas.
Your feedback helps make the package better for everyone!
π§βπ» Author
MayR Labs
Crafting clean, reliable, and human-centric Flutter and Dart solutions. π mayrlabs.com
π Licence
This package is licensed under the MIT License β which means you are free to use it for commercial and non-commercial projects, with proper attribution.
See the LICENSE file for more details.
MIT Β© 2025 MayR Labs
π Support
If you find this package helpful, please consider giving it a βοΈ on GitHub β it motivates and helps the project grow!
You can also support by:
- Sharing the package with your friends, colleagues, and tech communities.
- Using it in your projects and giving feedback.
- Contributing new ideas, features, or improvements.
Every little bit of support counts! ππ