mid 0.1.0+2 copy "mid: ^0.1.0+2" to clipboard
mid: ^0.1.0+2 copied to clipboard

a tool for building an end-to-end typesafe APIs in pure dart

mid #

⚠️ warning: the project is still experimental!

so things may change often until a stable version is released.

mid is a tool to build an end-to-end typesafe API in dart. The tool generates an API server and a client library in addition to handling requests and managing communication between the server and the client.

In short:

  • You write this on the server side:

    class App extends EndPoints {
        final Database database;
    
        App(this.database);
    
        Future<UserData> getUserData(int uid) async {
            final user = await database.getUserById(uid);
            return user;
        }
    
        Stream<List<Post>> timeline(int uid) {
            return database.timelineStream(uid);
        }
    
        Future<void> updateProfile(UserProfile profile) {
            await database.updateProfile(profile);
        }
    }
    
  • And mid enables you to do this on the client side:

    final client = TheClient(url: 'localhost:8080');
    
    final UserData data = await client.getUserData(42); 
    
    final  Stream<List<Post>> posts = await client.timeline(uid); 
    
    final newProfile = profile.copyWith(photoURL: photoURL);
    await client.updateProfile(newProfile); 
    

See the Quick Start Tutorial to learn how to use mid in no time.

Getting Started #

Installation: #

dart pub global activate mid

Tutorials: #

Examples: #

  • Examples will be added SOON to the examples folder.

Documentation #

The documentation is being created incrementally within docs folder. Currently the following is available:

Motivation #

To have the ability to call the backend code from the frontend in a type safe manner and as simple as calling a function in pure Dart.

Note: mid is not intended to generate a REST API, but to generate an API server that can be seamlessly used by a Dart or Flutter frontend with a minimal effort.

How does it work #

mid simply works by converting the public methods for a given list of classes into endpoints on a shelf server by generating a shelf_router and its handlers. In addition, the return type and the parameters types of each method are parsed and analyzed to generate the serialization/deserialization code for each type.

The client library is generated in a similar manner where each class, method, return type and parameter type is regenerated so that each endpoint becomes a simple function.

To support streaming data from the server to the client, shelf_web_socket is used on the server while web_socket_channel on the client.

Additional Notes #

Supported Classes #

Any class of an EndPoints* type. mid will only expose the public methods of the given class and it'll not expose any of its superclass(es).

* EndPoints is just a type -- for now there's nothing to implement. a class just needs to implement, extend or mixin EndPoints so it can be converted.

Supported Return Types and Method Parameters Types #

  • All core Types (int, double, num, bool, String, DateTime, Duration, enum, Uri, BigInt)

  • User defined Classes*

  • Collections (i.e., Map, Set, List) of any of the above.

  • Future or Stream for any of the above.

    * mid is able to serialize user defined classes and their members recursively as long as they have an unnamed generative constructor with formal parameters only (i.e. all parameters using this). An example class would be:

    class UserData {
      final int id;
      final String name;
      final bool isAdmin;
      // `MetaData` must follow the same rules including its members.
      final MetaData? metadata;
      
      // this is what `mid` is looking for (i.e. no assignment in initializer list or constructor body):
      UserData({
        required this.id,
        required this.name,
        this.metadata,
        this.isAdmin = false,
      });
      
      /* you can define your own methods, factory constructors, and whatnot */
    }