I am back again on the track of a series of learning.
Do you know we can build a Full-stack application using Flutter only?
Yes, We can build Full stack applications with the help of the dart-frog library.
We are going to build in this series a simple Pizza-shop application.
In this part, We are going to learn about how Dart-frog basically works with static data.
What is Dart-Frog?
Dart-frog is not directly or officially related to the flutter but it is a framework designed in the dart to create a minimalist back end.
In addition, Dart Frog is intended to help Flutter/Dart developers maximize their productivity by having a unified tech stack that enables sharing tooling, models, and more!
Thanks to verygood.ventures
Installing Dart-frog
//📦 Install the dart_frog cli from pub.dev
dart pub global activate dart_frog_cli
Creating a project
dart_frog create pizza_shop
Start the server
dart_frog dev
Note: By default 8080 port is used to change via --port
.
Lets Explore
How do routes work?
"routes" folder contains routes for example "index.dart" is "/" home route and if we have to create another route then create a new folder in "routes" in with route_name and create a dart file named the same as the endpoint with onRequestFunction()
.
import 'package:dart_frog/dart_frog.dart'; | |
Response onRequest(RequestContext context) { | |
return Response(body: 'Hello world'); | |
} |
All route handlers have access to a RequestContext which can be used to access the incoming request as well as dependencies provided to the request context.
HTTP Method
We can identify types of HTTP requests via context.request.method
import 'package:dart_frog/dart_frog.dart'; | |
Response onRequest(RequestContext context) { | |
// Access the incoming request. | |
final request = context.request; | |
// Access the HTTP method. | |
final method = request.method.value; | |
return Response(body: 'This is a $method request.'); | |
} |
for the same, we can get also
- Query parameters:
context.request.uri.queryParameters
- Headers:
context.request.headers
- Body:
await context.request.body()
- Json Data:
await context.request.json()
- Form Data:
await context.request.formData()
Let's start working on the Pizza shop
..........................................
Create models for pizzas and orders.
- Add
json_annotation: ^4.7.0
inpubspec.yaml
for serialization. - Step create a new folder named
models
and a file namedpizza_models.dart
using JSON annotation.
import 'package:json_annotation/json_annotation.dart'; | |
@JsonSerializable() | |
class PizzaModel { | |
PizzaModel({this.name, this.price, this.image, this.description, this.id}); | |
factory PizzaModel.fromJson(Map<String, dynamic> json) => | |
_$PizzaModelFromJson(json); | |
final String? name; | |
final int? price; | |
final String? id; | |
final String? image; | |
final String? description; | |
Map<String, dynamic> toJson() => _$PizzaModelToJson(this); | |
} | |
PizzaModel _$PizzaModelFromJson(Map<String, dynamic> json) { | |
return PizzaModel( | |
name: json['name'] as String?, | |
price: json['price'] as int?, | |
image: json['image'] as String?, | |
description: json['description'] as String?, | |
id: json['id'] as String?, | |
); | |
} | |
Map<String, dynamic> _$PizzaModelToJson(PizzaModel instance) => | |
<String, dynamic>{ | |
'name': instance.name, | |
'price': instance.price, | |
'image': instance.image, | |
'description': instance.description, | |
'id': instance.id | |
}; |
- create
order_models.dart
in the same folder.This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters// ignore_for_file: lines_longer_than_80_chars import 'package:json_annotation/json_annotation.dart'; @JsonSerializable() class OrderModel { OrderModel( this.userId, this.pizzaId, this.address, this.phoneNumber, this.status, this.id, ); factory OrderModel.fromJson(Map<String, dynamic> json) => $OrderModelFromJson(json); Map<String, dynamic> toJson() => $OrderModelToJson(this); final String? userId; final String? pizzaId; final String? address; final String? phoneNumber; final String? status; final int id; } OrderModel $OrderModelFromJson(Map<String, dynamic> json) { return OrderModel( json['user_id'] as String?, json['pizza_id'] as String?, json['address'] as String?, json['phone_number'] as String?, json['status'] as String?, json['id'] as int, ); } Map<String, dynamic> $OrderModelToJson(OrderModel instance) => <String, dynamic>{ 'user_id': instance.userId, 'pizza_id': instance.pizzaId, 'address': instance.address, 'phone_number': instance.phoneNumber, 'status': instance.status, 'id': instance.id, };
Creating Endpoints for fetching the list of pizzas or specific using pizza_id.
- Before creating the endpoint, We need a List of orders and pizzas, so create a new folder in the project name
utlis
and inside this create a dart file(constant.dart
) with the following content.
import '../models/order_models.dart'; | |
import '../models/pizza_models.dart'; | |
List<PizzaModel> pizzas = [ | |
PizzaModel.fromJson( | |
{ | |
'id': 50, | |
'name': 'Baby Bell Peppers', | |
'description': 'BASIL LEAVES, WATER, SEA SALT, SUNFLOWER OIL',, | |
'image': 'https://assets.zumepizza.com/public/7650vx0h.png', | |
'price': 10 | |
}, | |
), | |
PizzaModel.fromJson( | |
{ | |
'id': 6, | |
'name': 'Basil', | |
'description': 'BASIL LEAVES, WATER, SEA SALT, SUNFLOWER OIL',, | |
'image': 'https://assets.zumepizza.com/public/9pb5d2k4.png', | |
'price': 11 | |
}, | |
), | |
PizzaModel.fromJson( | |
{ | |
'id': 110, | |
'name': 'Daiya Vegan Mozzarella', | |
'description': | |
'FILTERED WATER, TAPIOCA FLOUR, EXPELLER PRESSED NON-GMO CANOLA AND/OR SAFFLOWER OIL, COCONUT OIL, PEA PROTEIN, SALT, VEGAN NATURAL FLAVOURS, INACTIVE YEAST, VEGETABLE GLYCERIN, XANTHAN GUM, CITRIC ACID, TITANIUM DIOXIDE', | |
'price': 12, | |
'image': 'https://assets.zumepizza.com/public/oo9dpuia.png' | |
}, | |
), | |
PizzaModel.fromJson( | |
{ | |
'id': 74, | |
'name': 'Kalamata Olives', | |
'description': 'KALAMATA OLIVES, WATER, SEA SALT, SUNFLOWER OIL', | |
'image': 'https://assets.zumepizza.com/public/ezuum3ch.png', | |
'price': 5 | |
}, | |
) | |
]; | |
List<OrderModel> orders = [ | |
OrderModel.fromJson({ | |
'id': 1, | |
'user_id': '1', | |
'pizza_id': '6', | |
'address': '1234 Main St', | |
'phone_number': '1234567890', | |
'status': 'pending' | |
}), | |
OrderModel.fromJson({ | |
'id': 2, | |
'user_id': '1', | |
'pizza_id': '50', | |
'address': '1234 Main St', | |
'phone_number': '1234567890', | |
'status': 'pending' | |
}), | |
OrderModel.fromJson({ | |
'id': 3, | |
'user_id': '123', | |
'pizza_id': '74', | |
'address': '1234 Main St', | |
'phone_number': '1234567890', | |
'status': 'pending' | |
}), | |
]; |
- create a dart file named
pizzas.dart
. This method will be a GET to return a list of pizzas if noid
query parameter is provided otherwise it will return specific pizza details.
import 'package:dart_frog/dart_frog.dart'; | |
import '../models/pizza_models.dart'; | |
import '../utlis/constant.dart'; | |
Response onRequest(RequestContext context) { | |
//check if the request is a GET request | |
if (context.request.method == HttpMethod.get) { | |
//check if query parameter is present | |
final params = context.request.uri.queryParameters; | |
if (params.containsKey('id')) { | |
//return the pizza with the id | |
final id = params['id']; | |
// ignore: require_trailing_commas | |
final pizza = pizzas.firstWhere( | |
(element) => element.id == id, | |
orElse: () => PizzaModel.fromJson({}), | |
); | |
if (pizza.id != null) { | |
return Response.json(body: {'data': pizza}); | |
} | |
return Response.json( | |
statusCode: 404, | |
body: {'message': 'Pizza not found'}, | |
); | |
} | |
return Response.json(body: {'data': pizzas}); | |
} | |
return Response.json( | |
statusCode: 404, | |
body: {'message': 'Method not allowed'}, | |
); | |
} |
OUTPUT
Fetching order
- For fetching orders, we are going to create a GET method with the query parameter
user_id
for getting the list of orders.
import 'package:dart_frog/dart_frog.dart'; | |
import '../utlis/constant.dart'; | |
Response onRequest(RequestContext context) { | |
//check if the request is a GET request | |
if (context.request.method == HttpMethod.get) { | |
//check if user_id is present | |
final params = context.request.uri.queryParameters; | |
if (params.containsKey('user_id')) { | |
final userId = params['user_id']; | |
final userOrders = orders.where((element) => element.userId == userId); | |
if (orders.isNotEmpty) { | |
return Response.json(body: {'data': userOrders.toList()}); | |
} | |
} | |
return Response.json(body: {'message': 'User id not found'}); | |
} | |
return Response.json( | |
statusCode: 404, | |
body: {'message': 'Method not allowed'}, | |
); | |
} |
Creating order
- For creating an order we required the following fields
user_id,pizza_id, address, and phone number
. - Method should post only.
Will check if the headers
content type is application/JSON
or not.Will also check if the pizza_id is valid or not.
after creating the order, we will return
order-id
to the user.
// ignore_for_file: avoid_dynamic_calls, noop_primitive_operations | |
import 'package:dart_frog/dart_frog.dart'; | |
import '../models/order_models.dart'; | |
import '../utlis/constant.dart'; | |
Future<Response> onRequest(RequestContext context) async { | |
//check if the request is a POST request | |
if (context.request.method == HttpMethod.post) { | |
//check if headers is application/json | |
final contentType = context.request.headers['Content-Type']; | |
if (contentType == 'application/json') { | |
//check if body is present | |
final body = await context.request.json(); | |
if (body != null && | |
body['pizza_id'] != null && | |
body['user_id'] != null && | |
body['address'] != null && | |
body['phone_number'] != null) { | |
//check valid pizza id | |
final isValidPizzaId = | |
pizzas.any((element) => element.id == body['pizza_id']); | |
if (isValidPizzaId) { | |
orders.add( | |
OrderModel.fromJson({ | |
'id': DateTime.now().millisecondsSinceEpoch.toInt(), | |
'pizza_id': body['pizza_id'], | |
'user_id': body['user_id'], | |
'address': body['address'], | |
'phone_number': body['phone_number'], | |
}), | |
); | |
return Response.json( | |
statusCode: 201, | |
body: { | |
'message': | |
'Order created successfully with order id: ${orders.last.id}' | |
}, | |
); | |
} else { | |
return Response.json( | |
statusCode: 404, | |
body: {'message': 'Invalid pizza id'}, | |
); | |
} | |
} else { | |
return Response.json( | |
statusCode: 404, | |
body: {'message': 'All fields are required'}, | |
); | |
} | |
} | |
return Response.json( | |
statusCode: 404, | |
body: {'message': 'Content-Type must be application/json'}, | |
); | |
} | |
return Response.json( | |
statusCode: 404, | |
body: {'message': 'Method not allowed'}, | |
); | |
} |
We are done .....................
In the next part, we are going to connect MongoDB for persisting data.
part-2
Stay Tuned .....
Follow me:
Top comments (4)
How to connect dart-frog with mongodb cloud?
Hi pablo sorry for late reply, you can dart-frog to Atlas using following code
var db = await Db.create("mongodb+srv://:@:/?");
await db.open();
and for more info
pub.dev/packages/mongo_dart
I hope it will help you.
I am having issues using JSON annotation. Would you please show how to do this?
Hi George, you can refer to this article.
medium.com/flutter-community/gener...