License Platform

Pub Version Pub.dev Score Pub Likes Pub.dev Publisher Downloads

Build Status Issues Last Commit Contributors

πŸ§ͺ 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 for api/user/profile/get.json.

  • When you make a POST request to /api/user/profile, it looks for api/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! πŸš€πŸ’™

Libraries

mayr_fake_api