Skip to content

Commit

Permalink
pokemon api example with void type
Browse files Browse the repository at this point in the history
  • Loading branch information
SandroMaglione committed Mar 21, 2024
1 parent 81d4b0d commit 06fff82
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 23 deletions.
11 changes: 11 additions & 0 deletions examples/poke_api/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include: package:lints/recommended.yaml

linter:
rules:
annotate_overrides: true

analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
53 changes: 38 additions & 15 deletions examples/poke_api/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,51 +1,74 @@
import 'dart:convert';

import 'package:fpdart/fpdart.dart';
import 'package:http/http.dart' as http;
import 'package:poke_api/constants.dart';
import 'package:poke_api/pokemon.dart';
import 'package:poke_api/pokemon_error.dart';

abstract interface class HttpClient {
String get(Uri uri);
Effect<void, PokemonError, String> get(Uri uri);
}

Effect<(HttpClient, JsonCodec), PokemonError, Pokemon> program(
class Http implements HttpClient {
@override
Effect<void, PokemonError, String> get(Uri uri) => Effect.gen(
($) async {
final response = await $.async(Effect.tryCatch(
execute: () => http.get(uri),
onError: (error, stackTrace) => const GetPokemonRequestError(),
));

return response.body;
},
);
}

typedef Env = (HttpClient, JsonCodec);

Effect<Env, PokemonError, Pokemon> program(
String pokemonId,
) =>
Effect.gen(($) async {
final (client, json) = $.sync(Effect.env());

final id = $.sync(
Either.fromNullable(
int.tryParse(pokemonId),
PokemonIdNotInt.new,
),
);
final id = $.sync(Either.fromNullable(
int.tryParse(pokemonId),
PokemonIdNotInt.new,
).provide());

if (id < Constants.minimumPokemonId && id > Constants.maximumPokemonId) {
return $.sync(Effect.fail(const InvalidPokemonIdRange()));
}

final uri = Uri.parse(Constants.requestAPIUrl(id));
final body = await $.async(Effect.tryCatch(
execute: () => client.get(uri),
onError: (_, __) => const GetPokemonRequestError(),
));
final body = await $.async(client.get(uri).provideVoid());

final bodyJson = $.sync(Either.tryCatch(
execute: () => json.decode(body),
onError: (_, __) => const PokemonJsonDecodeError(),
));
).provide());

final bodyJsonMap = $.sync<Map<String, dynamic>>(
Either.safeCastStrict(
Either.safeCastStrict<PokemonError, Map<String, dynamic>, dynamic>(
bodyJson,
(value) => const PokemonJsonInvalidMap(),
),
).provide(),
);

return $.sync(Effect.tryCatch(
execute: () => Pokemon.fromJson(bodyJsonMap),
onError: (_, __) => const PokemonInvalidJsonModel(),
));
});

void main() async {
await program("721")
.map((pokemon) => print(pokemon))
.catchError(
(error) => Effect.function(
() => print("No pokemon: $error"),
),
)
.runFuture((Http(), JsonCodec()));
}
5 changes: 5 additions & 0 deletions examples/poke_api/lib/pokemon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,9 @@ class Pokemon {
height: json['height'] as int,
weight: json['weight'] as int,
);

@override
String toString() {
return "Pokemon(id:$id, name:$name, height:$height, weight:$weight)";
}
}
1 change: 1 addition & 0 deletions examples/poke_api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ environment:
sdk: ">=3.3.0 <4.0.0"

dependencies:
http: ^1.2.1
fpdart:
path: ../../packages/fpdart

Expand Down
5 changes: 5 additions & 0 deletions packages/fpdart/lib/src/effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,8 @@ extension ProvideNever<L, R> on Effect<Never, L, R> {
/// {@category execution}
Future<Exit<L, R>> runFutureExitNoEnv() async => _unsafeRun(null);
}

extension ProvideVoid<L, R> on Effect<void, L, R> {
/// {@category execution}
Effect<V, L, R> provideVoid<V>() => provide((env) {});
}
2 changes: 1 addition & 1 deletion packages/fpdart/lib/src/either.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
part of "effect.dart";

sealed class Either<L, R> extends IEffect<Never, L, R> {
sealed class Either<L, R> extends IEffect<Null, L, R> {
const Either();

/// If calling `predicate` with `r` returns `true`, then return `Right(r)`.
Expand Down
11 changes: 4 additions & 7 deletions packages/fpdart/lib/src/extension/future_or_extension.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import 'dart:async';

extension FutureOrThenExtension<A> on FutureOr<A> {
FutureOr<B> then<B>(FutureOr<B> Function(A a) f) {
if (this is Future) {
return (this as Future<A>).then(f);
}

return f(this as A);
}
FutureOr<B> then<B>(FutureOr<B> Function(A a) f) => switch (this) {
final Future<A> self => self.then(f),
final A self => f(self),
};
}

0 comments on commit 06fff82

Please sign in to comment.