How to post an image to LARAVEL API in FLUTTER

Most online registration forms require the user to upload images. Adding an image upload feature to mobile apps can be challenging for some developers. This article will show you step by step how to upload images on your FLUTTER app to a LARAVEL RESTFUL API.

This article has two parts.

  • Laravel API
  • FLUTTER App

PART 1. LARAVEL API

Step 1: Create a new laravel project using composer. You can give it any name but in this case, we will name it ImageApi.

composer create-project --prefer-dist laravel/laravel ImageApi

Step 2: In the created project. Make a migration to create an images table.

php artisan make:migration create_images_table --create=images

Step 3: In the migration add the image fields title and url.

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateImagesTable extends Migration
{
    
    public function up()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->string('url');
            $table->timestamps();
        });
    }
public function down()
    {
        Schema::drop('images');
    }
}

Step 4: Next, create a model called Image

php artisan make:model Image

Step 5: In the model add the title fields and url fields in the fillable array.

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
    protected $table = 'images';
protected $fillable = [
        'title', 'url'
    ];
}

Step 6: Next, create a controller and name it ImageController.

php artisan make:controller ImageController

Step 7: To the ImageController. Add a function called addimage.

<?php
namespace App\Http\Controllers;
use App\Image;
use App\Http\Controllers\Controller;
class ImageController extends Controller
{
   
    public function addimage(Request $request)
    {
        $image = new Image;
        $image->title = $request->title;
        
            if ($request->hasFile('image')) {
            
            $path = $request->file('image')->store('images');
            $image->url = $path;
           }
        $image->save();
        return new ImageResource($image);
    }
}

Step 8: Finally in the api.php file in the routes folder

<?php
use Illuminate\Http\Request;
Route::resource('imageadd', 'Api\ImageController@addimage');

This will create an Api endpoint

<domain-name>/api/imageadd

The Flutter App will access this API endpoint.

PART 2: FLUTTER APP

Step 1: Create a fresh flutter App using this command.

$ flutter create Imageapp
$ cd Imageapp

Step 2: Add the image_picker package to your flutter using this command

$ flutter pub add image_picker

Step 3: Next, add the flutter http package to your project using this command

$ flutter pub add http

Step 4: In the lib folder of the Flutter App. Create two extra dart files.

  • the first one will be service.dart.
  • the second one will be image_upload.dart.

Step 5: In the service.dart file. Import the HTTP package and the dart:convert package to this file.

import 'package:http/http.dart' as http;
import 'dart:convert';

Step 6: Create a class called Service and inside it add a function called addImage. This function will make an HTTP POST request to The laravel endpoint we created in Part 1 of this article.

import 'package:http/http.dart' as http;
import 'dart:convert';
class Service {
Future<bool> addImage(Map<String, String> body, String filepath) async {
    String addimageUrl = '<domain-name>/api/imageadd';
    Map<String, String> headers = {
      'Content-Type': 'multipart/form-data',
    };
var request = http.MultipartRequest('POST', Uri.parse(addimageUrl))
      ..fields.addAll(body)
      ..headers.addAll(headers)
      ..files.add(await http.MultipartFile.fromPath('image', filepath));
var response = await request.send();
    if (response.statusCode == 201) {
      return true;
    } else {
      return false;
    }
  }
}

Step 7: In the image_upload.dart file. Create a stateful widget called ImageUpload

class ImageUpload extends StatefulWidget {
  ImageUpload({Key key}) : super(key: key);
@override
  _ImageUploadState createState() => _ImageUploadState();
}
class _ImageUploadState extends State<ImageUpload> {
  @override
  Widget build(BuildContext context) {
    return Container(
       
    );
  }
}

Step 8: Import the dart:io library, image_picker package, and material design package. Also, import the service.dart file you created.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'service.dart';

Step 9: Inside the ImageUploadState class. Create the following variables.

Service service = Service();
final _addFormKey = GlobalKey<FormState>();
final _titleController = TextEditingController();
  
File _image;
final picker = ImagePicker();

Step 10: Next, add an asynchronous function that will be launching the phones’ image gallery. Call this function getImage.

Future getImage() async {
    final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
      if (pickedFile != null) {
        _image = File(pickedFile.path);
      } else {
        print('No image selected.');
      }
    });
  }

Step 11: Create another function to show the selected image to the user. Call it buildImage.

Widget _buildImage() {
    if (_image == null) {
      return Padding(
        padding: const EdgeInsets.fromLTRB(1, 1, 1, 1),
        child: Icon(
          Icons.add,
          color: Colors.grey,
        ),
      );
    } else {
      return Text(_image.path);
    }
  }

Step 12: Inside the main build function add a TextFormField widget. This is for the title of the image.

Widget build(BuildContext context) {
    
  Container(
    child: Column(
      children: <Widget>[
       Text('Image Title'),
         TextFormField(
            controller: _titleController,
            decoration: const InputDecoration(
              hintText: 'Enter Title',),
            validator: (value) {
              if(value.isEmpty) {
                 return 'Please enter image title';}
                     return null;
                        },),
                        ],
                  ),
            ),
      );
  }

Step 13: Next, add a button that will run the getImage function

Container(
    child: OutlineButton(
       onPressed: getImage, 
             child: _buildImage())),

Step 14: Then add a button that will post the title and the image to the server

Container(
     child: Column(
        children: <Widget>[
          RaisedButton(
            onPressed: () {
              if (_addFormKey.currentState.validate()) {
                _addFormKey.currentState.save();
                  Map<String, String> body = {
                   'title': _titleController.text,};
                    service.addImage(body, _image.path);
                     Navigator.pop(context);}},
            child: Text('Save',
               style: TextStyle(color: Colors.white)),
               color: Colors.blue,)],
                     ),
            )

Step 15: The final image_upload.dart file will look like this

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'service.dart';
class ImageUpload extends StatefulWidget {
  PostCreate();
@override
  _ImageUploadState createState() => _ImageUploadState();
}
class _ImageUploadState extends State<ImageUpload> {
  _ImageUploadState();
  
  Service service = Service();
final _addFormKey = GlobalKey<FormState>();
  final _titleController = TextEditingController();
  File _image;
  final picker = ImagePicker();
Future getImage() async {
    final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
      if (pickedFile != null) {
        _image = File(pickedFile.path);
      } else {
        print('No image selected.');
      }
    });
  }
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add Images'),
      ),
      body: Form(
        key: _addFormKey,
        child: SingleChildScrollView(
          child: Container(
            child: Card(
              child: Container(
                child: Column(
                  children: <Widget>[
                Container(
                  child: Column(
                    children: <Widget>[
                      Text('Image Title'),
                      TextFormField(
                        controller: _titleController,
                        decoration: const InputDecoration(
                           hintText: 'Enter Title',),
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'Please enter title';
                             }
                            return null;
                                },
                              ),
                            ],
                          ),
                        ),
                       
                       
              Container(
                child: OutlineButton(
                  onPressed: getImage, 
                    child: _buildImage())),
              Container(
                 child: Column(
                   children: <Widget>[
                     RaisedButton(
                       onPressed: () {
                         if(_addFormKey.currentState.validate()) {
                           _addFormKey.currentState.save();
                           Map<String, String> body = {
                            'title': _titleController.text};
                          service.addImage(body, _image.path);}},
                       child: Text('Save'),
                                
                              )
                            ],
                          ),
                        ),
                      ],
                    ))),
          ),
        ),
      ),
    );
  }
Widget _buildImage() {
    if (_image == null) {
      return Padding(
       
        child: Icon(
          Icons.add,
          color: Colors.grey,
        ),
      );
    } else {
      return Text(_image.path);
    }
  }
}

Step 16: In the main.dart file import the image_upload.dart file. Then, add the ImageUpload widget.

import 'package:flutter/material.dart';
import 'image_upload.dart';
void main() {
  
  runApp(App());
}
class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
          
          child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: ImageUpload(),
      ),
    );
  }
}
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x