DEV Community

Cover image for Build Full stack application using Flutter ft. Dart frog and MongoDB. Part 2
Md. Mobin
Md. Mobin Subscriber

Posted on • Edited on

Build Full stack application using Flutter ft. Dart frog and MongoDB. Part 2

Hello everyone, In the last tutorial we created APIs using Dart-Frog for our Flutter Full stack Pizza Shop application.

Now we will learn, how to connect MongoDB in the dart frog server.

Prerequisites

  • MongoDB(CRUD Knowledge)

  • and the Dart Basics.

Note: In case you missed Part 1.

Let's Start from where we left it.

  • Clone following GitHub repository
git clone git@github.com:Djsmk123/pizza_shop_dart_backend_part_1.git 
Enter fullscreen mode Exit fullscreen mode
  • Create a new database named pizza_shop with Collections named pizzas and orders as shown below.

Database and collections creation

  • Now Add the following JSON data to the collection pizzas.
[ { "id": "50", "name": "Baby Bell Peppers", "description": "BELL PEPPERS, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/7650vx0h.png", "price": 10 }, { "id": "6", "name": "Basil", "description": "BASIL LEAVES, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/nfjqscxz.jpg", "price": 11 }, { "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" }, { "id": "74", "name": "Kalamata Olives", "description": "KALAMATA OLIVES, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/ezuum3ch.png", "price": 5 }, { "id": "75", "name": "Mushrooms", "description": "MUSHROOMS, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/nfjqscxz.jpg", "price": 6 }, { "id": "76", "name": "Onions", "description": "ONIONS, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/7650vx0h.png", "price": 7 }, { "id": "77", "name": "Pepperoni", "description": "PEPPERONI, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/nfjqscxz.jpg", "price": 8 }, { "id": "78", "name": "Red Onions", "description": "RED ONIONS, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/nfjqscxz.jpg", "price": 9 }, { "id": "79", "name": "Roasted Red Peppers", "description": "ROASTED RED PEPPERS, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/nfjqscxz.jpg", "price": 10 }, { "id": "80", "name": "Spinach", "description": "SPINACH, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/nfjqscxz.jpg", "price": 11 }, { "id": "81", "name": "Sun Dried Tomatoes", "description": "SUN DRIED TOMATOES, WATER, SEA SALT, SUNFLOWER OIL", "image": "https://assets.zumepizza.com/public/nfjqscxz.jpg", "price": 12 } ] 
Enter fullscreen mode Exit fullscreen mode

pizzas.json

  • Do same with orders with following data
[ { "id": 1, "user_id": "1", "pizza_id": "6", "address": "1234 Main St", "phone_number": "1234567890", "status": "pending" } ] 
Enter fullscreen mode Exit fullscreen mode
  • let's Add MongoDB Dependency to our project.
 mongo_dart: ^0.8.2 
Enter fullscreen mode Exit fullscreen mode

Add in the pubspec.yaml.

  • Create a new folder in the project called services which will handle MongoDB services and create a new file called database_services.dart.
 // ignore_for_file: prefer_single_quotes, lines_longer_than_80_chars import 'package:dart_frog/dart_frog.dart'; import 'package:mongo_dart/mongo_dart.dart'; class DatabaseService { static final db = Db("mongodb://localhost:27017/pizza_shop"); //start the database static Future<void> startDb() async { if (db.isConnected == false) { await db.open(); } } //close the database static Future<void> closeDb() async { if (db.isConnected == true) { await db.close(); } } //collections static final pizzasCollections = db.collection('pizzas'); static final ordersCollections = db.collection('orders'); // we will use this method to start the database connection and use it in our routes static Future<Response> startConnection( RequestContext context, Future<Response> callBack, ) async { try { await startDb(); return await callBack; } catch (e) { return Response.json( statusCode: 500, body: {'message': 'Internal server error'}, ); } } } 
Enter fullscreen mode Exit fullscreen mode
  • we are going to use the following query for database management
  1. find(): To find all the data from given collection.

  2. findOne(where.eq('key-value',value)): will use to find specific data from a given collection with the specified value.

  3. insertOne(data): will use it to insert data in a given collection.

Let's Edit existing Endpoints

  • /pizzas: we are going to fetch all pizzas from "PizzaCollection" and will map to the list of PizzaModel and then return the same.

//File name : routes/pizzas.dart

 // ignore_for_file: lines_longer_than_80_chars import 'package:dart_frog/dart_frog.dart'; import 'package:mongo_dart/mongo_dart.dart'; import '../models/pizza_models.dart'; import '../services/database_services.dart'; Future<Response> onRequest(RequestContext context) async { return DatabaseService.startConnection(context, getPizzas(context)); } Future<Response> getPizzas(RequestContext context) async { //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']; final doc = await DatabaseService.pizzasCollections.findOne(where.eq('id', id)); if (doc != null && doc.isNotEmpty) { final pizza = PizzaModel.fromJson(doc); return Response.json(body: {'data': pizza}); } else { return Response.json( statusCode: 404, body: {'message': 'Pizza not found'}, ); } } else { final docs = await DatabaseService.pizzasCollections.find().toList(); final pizzas = docs.map(PizzaModel.fromJson).toList(); return Response.json(body: {'data': pizzas}); } } return Response.json( statusCode: 404, body: {'message': 'Method not allowed'}, ); } 
Enter fullscreen mode Exit fullscreen mode
  • /fetchorders: we will fetch only those docs where user_id will be equal to user_id in query parameter and then return if exist.

//File name fetchorders.dart

// ignore_for_file: lines_longer_than_80_chars import 'package:dart_frog/dart_frog.dart'; import 'package:mongo_dart/mongo_dart.dart'; import '../models/order_models.dart'; import '../services/database_services.dart'; Future<Response> onRequest(RequestContext context) async { return DatabaseService.startConnection(context, getOrders(context)); } Future<Response> getOrders(RequestContext context) async { //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 doc = await DatabaseService.ordersCollections .find(where.eq('user_id', userId)) .toList(); final userOrders = doc.map(OrderModel.fromJson).toList(); if (userOrders.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'}, ); } 
Enter fullscreen mode Exit fullscreen mode
  • /createorder: As we know that this request is post so we will check if the pizza_id is Valid or not? and then will insert an entry into orders collection.

//File name createorders.dart

// ignore_for_file: avoid_dynamic_calls, noop_primitive_operations import 'package:dart_frog/dart_frog.dart'; import 'package:mongo_dart/mongo_dart.dart'; import '../models/order_models.dart'; import '../services/database_services.dart'; Future<Response> onRequest(RequestContext context) async { return DatabaseService.startConnection(context, createOrder(context)); } Future<Response> createOrder(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; charset=utf-8') { //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 pizzas = await DatabaseService.pizzasCollections .findOne(where.eq('id', body['pizza_id'])); final isValidPizzaId = pizzas != null && pizzas.isNotEmpty; if (isValidPizzaId) { final orders = OrderModel.fromJson({ 'id': DateTime.now().millisecondsSinceEpoch.toInt(), 'pizza_id': body['pizza_id'], 'user_id': body['user_id'], 'status': 'pending', 'address': body['address'], 'phone_number': body['phone_number'], }); await DatabaseService.ordersCollections.insert(orders.toJson()); return Response.json( statusCode: 201, body: { 'message': 'Order created successfully with order id: ${orders.id}' }, ); } else { return Response.json( statusCode: 404, body: {'message': 'Invalid spizza 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'}, ); } 
Enter fullscreen mode Exit fullscreen mode
  • Now you can delete the constants. dart file.

Output

Note: we are not going to build the front end on the web so you can use my repository for the front end.

Pizza_shop_web_application

Happy New year to Everyone

meme1

We are done .....................

Stay Tuned .....

Follow me:

Top comments (1)

Collapse
 
ntvsp profile image
Nguyen Tuan Vu

tks sir 3000 <3