rest_data 0.2.0

  • Readme
  • Changelog
  • Installing
  • new48

rest_data #

The goal of this package is to make interaction with your REST APIs pleasant and concise. It currently supports JSON:API-compliant REST APIs, but can be extended to support more formats - and you're encouraged to contribute!

Introduction #

rest_data is inspired by ember-data so it's based on 3 main abstractions:

  • Model: represents a single REST resource, with its attributes and relationships.
  • Serializer: takes care of transforming Model objects into your REST API payloads format (usually JSON), and vice-versa.
  • Adapter: provides methods to read/write model objects to your REST APIs; it maps to ember-data's Store but we choose to not adopt the name Store in order to avoid conflict with the popular dart package redux.

Usage with a JSON:API backend

Instantiating the Adapter #

Create your Adapter as follows:

Adapter adapter = JsonApiAdapter('host.example.com', '/path/to/rest/api');

This is designed to be a long-lived object: a good practice is to wrap it in a singleton class to be used across the whole app, or to make it available throughout your app via Dependency Injection.

Defining Models #

For each of your REST API resources, you should define a model class extending JsonApiModel which provides the following getters:

  • Map<String, dynamic> get attributes see specs
  • Map<String, dynamic> get relationships see specs
  • Iterable<dynamic> get included see specs
  • Iterable<dynamic> get errors see specs

together with helper methods (e.g. idFor(), idsFor(), typeFor(), setHasOne() etc. - see the source for more details).

Example model follows:

class Address extends JsonApiModel {
  // Constructors

  Address(JsonApiDocument doc) : super(doc);
  Address.init(String type) : super.init(type);

  // Attributes

  String get street => attributes['street'];
  set street(String value) => attributes['street'] = value;

  String get city => attributes['city'];
  set city(String value) => attributes['city'] = value;

  String get zip => attributes['zip'];
  set zip(String value) => attributes['zip'] = value;

  // Has-One Relationships

  String get countryId => idFor('country');
  set country(Country model) => setHasOne('country', model);
}  

class Country extends JsonApiModel {
  Country(JsonApiDocument doc) : super(doc);
}

Reading #

Invoking REST APIs is as simple as calling async methods on your adapter object. Such methods return one or more JsonApiDocument objects, which can be used to build your model objects.

Finding a specific record #

var address = Address(await adapter.find('addresses', '1'));

Will send the request: GET /addresses/1.

Finding all records #

Iterable<Country> countries = 
  adapter.findAll('countries')
  .map<Country>((jsonApiDoc) => Country(jsonApiDoc));

Will send the request: GET /countries.

Finding N specific records #

Iterable<Address> addresses = 
  (await adapter.findMany('addresses', ['1', '2', '3']))
  .map<Address>((jsonApiDoc) => Address(jsonApiDoc));

GET /addresses?filter[id]=1,2,3

Querying #

Iterable<Address> addresses = 
  (await adapter.query('addresses', {'q': 'miami'}))
  .map<Address>((jsonApiDoc) => Address(jsonApiDoc));

GET /addresses?filter[q]=miami

Writing #

Create #

You'll start with an empty model object, whose attributes and relationships will be set based on user input:

var address = Address.init();
address.street = '9674 Northwest 10th Avenue';
address.city = 'Miami';
address.zip = '33150';
address.country = Country.peek('US');  // Assume all countries are cached, see "Caching" section later

To persist your model on your REST API backend, just invoke the Adapter's save() method, which will return a new Address object:

var savedAddress = Address(await adapter.save(endpoint, address.jsonApiDoc));

The above line will send the request: POST /addresses with the address model object serialized as a JSON:API Document.

Update #

Assume you have an existing model object, and you edit some attributes based on user input:

var address = Address(await adapter.find('addresses', '1'));
address.street = '9674 Northwest 10th Avenue';
address.zip = '33150';

To persist your model on your REST API backend, just invoke the Adapter's save() method, which will return a new Address object:

var savedAddress = Address(await adapter.save(endpoint, address.jsonApiDoc));

The above line will send the request: PUT /addresses with the address model object serialized as a JSON:API Document.

Caching #

JsonApiAdapter comes with a basic caching mechanism built-in: a simple Map in-memory. Models fetched from the backend are automatically cached on any read request, and the cached ones are returned on subsequent read requests for the same model id.

When you only want already cached data, you can use Adapter's methods starting with the peek prefix.

Invalidation must be handled manually, passing forceReload = true to find* methods.

[0.2.0] - December 3rd, 2019

  • Upgraded equatable to 1.0.1

[0.1.1] - November 26th, 2019

  • Improved code after pub.dev analysis

[0.1.0] - November 26th, 2019

  • Initial release, works with any JSON:API backend

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  rest_data: ^0.2.0

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:rest_data/rest_data.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
48
Learn more about scoring.

We analyzed this package on Dec 4, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.6.1
  • pana: 0.12.21

Platforms

Detected platforms: Flutter, other

Primary library: package:rest_data/rest_data.dart with components: io.

Health suggestions

Fix lib/src/adapters/json_api.dart. (-0.50 points)

Analysis of lib/src/adapters/json_api.dart reported 1 hint:

line 172 col 9: DO use curly braces for all flow control structures.

Maintenance suggestions

Maintain an example. (-10 points)

Create a short demo in the example/ directory to show how to use this package.

Common filename patterns include main.dart, example.dart, and rest_data.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
equatable ^1.0.1 1.0.1
http ^0.12.0+2 0.12.0+2
Transitive dependencies
async 2.4.0
charcode 1.1.2
collection 1.14.12
http_parser 3.1.3
meta 1.1.8
path 1.6.4
pedantic 1.8.0+1
source_span 1.5.5
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
Dev dependencies
test ^1.9.4