Creating new handlers
We have created a new users
route for our system to fetch the existing
users, now we want to create a new handler to add a new user into our
system.
Create a handler
Let's use the CLI to create a new handler for the users
route.
At the root of our project run the following command:
gazelle create handler
The CLI will ask to pick a route from a selection menu, let's pick the
users
route:
$ gazelle create handler
Pick a route:
HelloGazelle
--> Users
Then, pick the POST
method:
Pick a method:
--> POST
PUT
PATCH
DELETE
The CLI will then create the handler source file inside the users
route
directory.
Create an entity for our handler
Now we need to create an entity to define the data to create a new user.
Let's create a new entity called user_post.dart
inside the models directory.
Copy-paste the following code in the newly created file:
class UserPost {
final String name;
final String username;
const UserPost({
required this.name,
required this.username,
});
}
Then, let's run gazelle codegen models
inside the terminal.
Updating our newly created handler
Open up the users post handler inside the backend/server/lib/routes/users
directory. You will find a default string handler that we need to update to
do something useful, like creating a new user.
Copy-paste the following code to do just that!
GazelleResponse<User> usersPost(
GazelleContext context,
GazelleRequest<UserPost> request,
) {
final userPost = request.body!;
final user = User(
id: (usersCollection.length + 1).toString(),
name: userPost.name,
username: userPost.username,
);
usersCollection.add(user);
return GazelleResponse(
statusCode: GazelleHttpStatusCode.success.ok_200,
body: user,
);
}
The code defines a handler that gets a GazelleRequest
with a UserPost
inside
its body and returns a complete User
to the client.
You can change the GazelleRequest
type parameter to everything you want, the
same is for the GazelleResponse
.
Link the new handler to the users
route
To add our handler to the users
route we just need to update the
backend/server/lib/routes/users.dart
file with the following code:
final users = GazelleRoute(
name: "users",
).get(usersGet).post(usersPost);
Now, run gazelle codegen client
to update our client for the Flutter
application.
Call the new handler from the Flutter app
To see the result inside our Flutter application, let's create a simple form to send data to our server and retrieve the created user.
import 'package:flutter/material.dart';
import 'package:client/client.dart';
void main() {
gazelle.init();
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<List<User>> _users;
@override
void initState() {
super.initState();
_users = gazelle.client.api.users.get();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('my_awesome_app'),
),
body: Center(
child: FutureBuilder(
future: _users,
builder: (_, snapshot) => switch (snapshot) {
AsyncSnapshot(:final data?) => UsersList(users: data),
AsyncSnapshot(:final error?) =>
Text('${error.runtimeType}: $error'),
_ => const CircularProgressIndicator(),
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _addUser(context).then((user) => setState(() {
_users = _users.then((users) => [...users, user]);
})),
child: const Icon(Icons.add),
),
);
}
}
class UsersList extends StatelessWidget {
const UsersList({
required this.users,
super.key,
});
final List<User> users;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.username),
leading: Text(user.id),
);
},
);
}
}
Future<T?> _addUser<T>(BuildContext context) => showModalBottomSheet<T>(
context: context,
builder: (_) {
return const AddUser();
},
);
class AddUser extends StatefulWidget {
const AddUser({
super.key,
});
@override
State<AddUser> createState() => _AddUserState();
}
class _AddUserState extends State<AddUser> {
late final TextEditingController _nameController;
late final TextEditingController _usernameController;
@override
void initState() {
super.initState();
_nameController = TextEditingController();
_usernameController = TextEditingController();
}
@override
void dispose() {
_nameController.dispose();
_usernameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8.0),
child: Column(
children: [
Text(
"Create a new user",
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 24),
TextField(
controller: _nameController,
decoration: const InputDecoration(hintText: "Name"),
),
TextField(
controller: _usernameController,
decoration: const InputDecoration(hintText: "Username"),
),
const SizedBox(height: 24),
FilledButton.icon(
onPressed: () => gazelle.client.api.users
.post(
UserPost(
name: _nameController.text.trim(),
username: _usernameController.text.trim(),
),
)
.then((user) => Navigator.of(context).pop(user)),
label: const Text("Create"),
icon: const Icon(Icons.create),
),
],
),
);
}
}
Now tap the FloatingActionButton
at the bottom of the page to open the form
insert some data and tap the create
button.
Now you should see a new user inside our app: