DEV Community

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

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