Why I moved to Angular Dart - Part 1

You know how it goes, you’ve finally (but probably haven’t) mastered your tech stack, you know the ins and outs of your chosen languages, frameworks. Found work-arounds for all those little niggly bits only for a colleague or friend to turn round and say “Have you heard of ‘x’, it’s amazing!”.

For me, this was “Have you heard of Angular Dart? Google use it internally to get around the problems with AngularTS”…

I love Angular with TypeScript, I’m very much a fan boy at this point and I get to use it at work almost every single day, but I have been thinking a lot about TS recently; how it still inherits JavaScript’s problems and adds more complexity to the already insane eco system that JavaScript is, but discussing JS’s flaws could take up an entire post of its own… Anyway, I decided to take a look at Angular Dart and I’ll now compare my experience with Angular TS.

NOTE: I was originally going to do this in one post, but as I started adding more to it I realised this is a very big subject… I will spread it over 3 parts instead.

TLDR;

I switched over to Angular Dart because I want to see what else is out there. TypeScript is great but is “polishing a turd” in the sense that JavaScript is inherintly flawed, and all TS does is throw a (albeit extremely well created) wrapper around JS.
Dart is amazing. Angular Dart is amazing. It doesn’t feel stiched together like Angular TS, there’s nowhere near as many package installs and creates a natural development experience. GIVE IT A GO!

Dart is actually… Awesome!!

So I started looking into Dart and was hooked almost instantly. A language with optional static typing? Object Oriented paradigms but full support for functional programming? Single Inheritence? Generics? It already has everything that TypeScript has but it’s built into the language. It almost sounded like TypeScript but feels a little more natural. Consider this piece of statically typed code in Dart:

1
2
3
4
5
6
class MyClass {
String field1;
String field2;

MyClass(this.field1, this.field2); // Inline constructors? Go on then :D
}

Simple enough, we’ve declared a Dart class called MyClass, declared to public fields and then used our inline constructor to assign their values. Because static typing is optional, we can also write the class like this:

1
2
3
4
5
6
class MyClass {
final field1;
final field2;

MyClass(this.field1, this.field2);
}

Yayyyyyy, they’re both valid. I like this, it means that I can prototype something really quickly if I need to. Another massive positive for me (and other developers who use Dart) is that it is so easy to be productive, quickly. I already felt like I knew how to write Dart.

This isn’t to say that Dart doesn’t have things that niggle me, every language has its flaws.

Angular

So being completely sold by Dart and all it’s offerings, I decided to go and download the Dart SDK and all the packages I needed to get a project up and running.

package management

This wasn’t actually too bad. Unlike AngularTS that uses a package.json and NPM to manage packages, Angular Dart uses a file called pubspec.yaml which looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name: music_portal
description: Music Portal
version: 0.0.1
environment:
sdk: '>=2.2.0 <3.0.0'

dependencies:
http: ^0.12.0
angular: ^6.0.0-alpha
angular_router: ^2.0.0-alpha+22
angular_forms: ^2.0.0
angular_components: any
json_serializable: ^3.0.0

dev_dependencies:
build_runner: ^1.5.1
build_test: ^0.10.8
build_web_compilers: ^2.1.0
test: ^1.6.4
sass_builder: ^2.0.0

One thing I liked about package management in Angular Dart is that it only contains packages that you (the developer) needs. Most things like stream libraries are built into the language itself, meaning no more “stiching” Angular together with multiple technologies, pretty much everything comes out of the box.

API calls

Hahaha here we go, this is where things started to get really interesting. One thing us JS and TS devs take for granted all the while is that JSON is a natural part of the language, we can call a server with JSON, and get a response back in JSON and we don’t need to do anything else… Dart on the other hand, you don’t have so much luck. If we want to instantiate a class from a server response, we need to make the class serializable. This really threw me off but again, Dart has your back with a built in (and fairly well documented) JSON library, so with a tiny bit of code and reading, this is my solution for making Dart classes JSON friendly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// a class that hits an authentication endpoint.
class UserAuthApi implements IUserAuthApi {
final BrowserClient _http;

Future<ApiResponse<AuthenticationResponse>> authenticateUser(LoginRequest loginRequest) {
final response = await this._http.post('${ApiHelper.apiUrl}/auth/authenticate',
headers: ApiHelper.headers,
body: jsonEncode(loginRequest));

final loginResponse = MusicPortalApiResponse<MusicPortalAuthenticationResponse>.fromJson(jsonDecode(response.body)); // <-- the fromJson method is where the magic happens

return loginResponse
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import 'package:json_annotation/json_annotation.dart'; // <-- Dart's JSON library
import 'package:music_portal/src/api/helpers/json_convert.dart'; // <-- custom JSON converter for use with generic types

part 'api_response.g.dart' // <-- this is actually generated by Dart's JSON library.

@JsonSerializable()
class ApiResponse<T> {

@JsonKey(name: "data")
@JsonConvert()
T data;
String message;
String authToken;
bool hasError;

MusicPortalApiResponse(this.data, this.message, this.authToken, this.hasError);
factory MusicPortalApiResponse.fromJson(Map<String, dynamic> json) => _$MusicPortalApiResponseFromJson(json);
}

Notice the factory? Dart encourages the Factory pattern right in the core of it’s language. This factory is responsible for taking a JSON blob and mapping it to the ApiResponse. Although I soon hit another issue, because data is a generic field, the compiler couldn’t create from JSON because it’s type isn’t known at compile time. This is where the @JsonConvert annotation comes in:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 'package:json_annotation/json_annotation.dart';
import 'package:music_portal/src/types/api_response/auth_response.dart';

class JsonConvert<T> implements JsonConverter<T, Object> {

const JsonConvert();

@override
T fromJson(Object json) {
if(json is Map<String, dynamic> && json.containsKey("userId")) {
return MusicPortalAuthenticationResponse.fromJson(json) as T;
}
}

@override
Object toJson(T object) {
// TODO: implement toJson
return null;
}

}

Now this feels a bit hacky, but it works. I’ll have to work on cleaning this up as more types are used with the ApiResponse class.

That’s it for part 1, I feel like this post is going on for far too long. I’ll update with post 2 soon…