How to post an image to LARAVEL API in FLUTTER
Limited Time Offer!
For Less Than the Cost of a Starbucks Coffee, Access All DevOpsSchool Videos on YouTube Unlimitedly.
Master DevOps, SRE, DevSecOps Skills!
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(),
),
);
}
}