Unlock the Power of Flutter and Serverpod: A Step-by-Step Guide to Uploading Image Files
Image by Ebeneezer - hkhazo.biz.id

Unlock the Power of Flutter and Serverpod: A Step-by-Step Guide to Uploading Image Files

Posted on

Are you tired of struggling with image uploads in your Flutter app? Look no further! In this comprehensive guide, we’ll walk you through the process of using Serverpod to effortlessly upload image files in your Flutter application. By the end of this article, you’ll be equipped with the knowledge to seamless integrate image uploads into your app, taking your user experience to the next level.

What is Serverpod?

Before we dive into the nitty-gritty of image uploads, let’s take a quick look at what Serverpod is. Serverpod is a scalable, open-source backend framework designed specifically for Flutter applications. It allows you to create a robust API, manage user sessions, and store data – all while providing a seamless integration with your Flutter app. With Serverpod, you can focus on building an amazing frontend experience while relying on a robust backend infrastructure.

Setting Up Serverpod

Before we start uploading images, we need to set up Serverpod in our Flutter project. If you’re new to Serverpod, don’t worry – it’s a breeze to get started!

dependencies:
  flutter:
    sdk: flutter
  serverpod: ^0.4.0+1

Add the Serverpod package to your `pubspec.yaml` file and run `flutter pub get` to install it. Next, create a new file called `serverpod.yaml` in the root of your project and add the following configuration:

modules:
  - user_sessions
  - data_store
  - api

api:
  address: localhost:8080

data_store:
  type: sqlite
  database: db.sqlite

This configuration sets up the base modules for Serverpod, including user sessions, data storage, and an API. We’ll be using a SQLite database for storing our image files.

Creating an Image Upload Endpoint

Now that Serverpod is set up, let’s create an endpoint for uploading image files. In your `serverpod.yaml` file, add the following API endpoint:

api:
  endpoints:
    - path: /upload_image
      method: POST
      handler: uploadImage
      middlewares:
        - auth.middleware
      response:
        200:
          type: json
          schema: { message: string }
        400:
          type: json
          schema: { error: string }

This endpoint accepts POST requests to `/upload_image` and calls the `uploadImage` handler function. We’ve also added an authentication middleware to ensure only authenticated users can upload images.

Handling Image Uploads in Serverpod

Now that our endpoint is set up, let’s create the `uploadImage` handler function. In your `serverpod.dart` file, add the following code:

Future<APIResponse> uploadImage(APIRequest req) async {
  final file = req.body.asBytes();
  final fileName = req.headers['filename']!;
  final fileExtension = req.headers['fileextension']!;

  // Create a new file in the data store
  final fileStore = DataStore.getInstance();
  final fileEntity = FileEntity(
    id: UUID(),
    filename: fileName,
    filesize: file.length,
    fileextension: fileExtension,
  );
  await fileStore.put(fileEntity);

  // Save the file to disk
  final fileDirectory = await getApplicationDocumentsDirectory();
  final fileLocation = '$fileDirectory/$fileName';
  await File(fileLocation).writeAsBytes(file);

  return APIResponse.ok(json: {'message': 'Image uploaded successfully'});
}

This function takes the uploaded file, extracts the file name and extension from the request headers, and saves the file to the data store and disk. Finally, it returns a success response with a JSON message.

Uploading Image Files in Flutter

Now that our Serverpod endpoint is set up, let’s create a Flutter widget to upload image files. Create a new file called `image_uploader.dart` and add the following code:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:typed_data';

class ImageUploader extends StatefulWidget {
  @override
  _ImageUploaderState createState() => _ImageUploaderState();
}

class _ImageUploaderState extends State {
  final _formKey = GlobalKey();
  File? _image;

  Future _selectImage() async {
    final file = await ImagePicker().getImage(source: ImageSource.gallery);
    setState(() {
      if (file != null) {
        _image = File(file.path);
      } else {
        _image = null;
      }
    });
  }

  Future _uploadImage() async {
    if (_image != null) {
      final formData = http.MultipartRequest('POST', Uri.parse('http://localhost:8080/upload_image'));
      formData.files.add(await http.MultipartFile.fromPath('file', _image!.path));
      formData.headers['filename'] = _image!.path.split('/').last;
      formData.headers['fileextension'] = _image!.path.split('.').last;

      final response = await formData.send();
      if (response.statusCode == 200) {
        print('Image uploaded successfully!');
      } else {
        print('Error uploading image: ${response.statusCode}');
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Uploader'),
      ),
      body: Form(
        key: _formKey,
        child: Column(
          children: [
            _image != null
                ? Image.file(_image!)
                : Container(),
            ElevatedButton(
              onPressed: _selectImage,
              child: Text('Select Image'),
            ),
            ElevatedButton(
              onPressed: _uploadImage,
              child: Text('Upload Image'),
            ),
          ],
        ),
      ),
    );
  }
}

This widget allows users to select an image from their gallery, displays a preview of the selected image, and uploads the image to the Serverpod endpoint when the “Upload Image” button is pressed.

Displaying Uploaded Images in Flutter

Now that we’ve uploaded our image files, let’s display them in our Flutter app. Create a new file called `image_viewer.dart` and add the following code:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class ImageViewer extends StatefulWidget {
  @override
  _ImageViewerState createState() => _ImageViewerState();
}

class _ImageViewerState extends State {
  List _files = [];

  Future _fetchFiles() async {
    final response = await http.get(Uri.parse('http://localhost:8080/files'));
    if (response.statusCode == 200) {
      final jsonData = jsonDecode(response.body);
      setState(() {
        _files = jsonData.map((file) => FileEntity.fromJson(file)).toList();
      });
    } else {
      print('Error fetching files: ${response.statusCode}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Viewer'),
      ),
      body: FutureBuilder(
        future: _fetchFiles(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            return GridView.builder(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
              ),
              itemCount: _files.length,
              itemBuilder: (context, index) {
                return Image.network('http://localhost:8080/${_files[index].filename}');
              },
            );
          } else {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }
}

This widget fetches a list of uploaded files from the Serverpod endpoint, maps them to `FileEntity` objects, and displays them in a grid view using the `Image.network` widget.

Conclusion

And that’s it! You now have a fully functional Flutter app that uploads image files to Serverpod using a custom API endpoint. By following this guide, you’ve learned how to set up Serverpod, create an image upload endpoint, handle image uploads in Serverpod, upload image files in Flutter, and display uploaded images in Flutter.

Remember to replace `http://localhost:8080` with your actual Serverpod API address in production. Happy coding!

Serverpod Version 0.4.0+1
Flutter Version 2.10.3
Dart Version 2.16.0

Special thanks to the Serverpod team for creating such an amazing backend framework for Flutter! If you have any questions or need further assistance, feel free to ask in the comments below.

Leave a Reply

Your email address will not be published. Required fields are marked *