Throwing exceptions
Celest also knows how to handle exceptions thrown in your Celest Functions. When an exception is thrown, Celest will do three things:
- Catch the thrown exception serialize it using the same process outlined above
- Map the exception to an appropriate HTTP response and status code
- Deserialize the exception type in your Flutter app and rethrow the same Dart type with the original message
Suppose you have some validation logic on your server which checks that a user's name is properly formatted. If the name is empty, you want to throw an exception. You can define a Dart type in your Celest backend to represent this error.
class BadNameException implements Exception {
const BadNameException(this.message);
final String message;
}
When you encounter an empty name, you can throw this exception in your Celest Function.
import 'package:celest_backend/exceptions/bad_name_exception.dart';
@cloud
Future<String> sayHello(String name) async {
// Perform custom validation
if (name.isEmpty) {
throw const BadNameException('Name cannot be empty');
}
return 'Hello, $name';
}
In your Flutter app, the same BadNameException
type will be thrown by the generated client so
you can catch it and handle it as you would any other exception. Any message
you passed in the
on the server will be available in the message
field of the exception on the client. Magically!
import 'package:celest_backend/client.dart';
@cloud
Future<String> getGreeting(String name) async {
try {
return await celest.functions.greeting.sayHello(name);
// Catch the exception type defined in your backend
} on BadNameException catch (e) {
print(e.message); // prints "Name cannot be empty"
rethrow;
}
}
HTTP mapping
When an exception is thrown in your Celest Function, Celest will map the exception to an appropriate HTTP response code.
For example, all Exception
types will be mapped to a 400 Bad Request
status and all Error
types will be mapped
to a 500 Internal Server Error
status by default.
Celest also provides a number of built-in exception types for common HTTP status codes. For example, you can throw a NotFoundException
to return a 404 Not Found
status code. And you can even include a custom message with it.
import 'package:celest/celest.dart';
@cloud
Future<String> sayHello(String name) async {
if (name.isEmpty) {
throw const NotFoundException('Name cannot be empty');
}
return 'Hello, $name';
}
If an exception type you've defined needs to be mapped to a different status code, you can use the @httpError
annotation to
specify the status code Celest should use for it. For example, maybe we want our BadNameException
to return a 404 Not Found
status
instead of the default 400
.
import 'package:celest/celest.dart';
import 'package:celest/http.dart';
class BadNameException implements Exception {
const BadNameException(this.message);
final String message;
}
@cloud
@httpError(404, BadNameException)
Future<String> sayHello(String name) async {
if (name.isEmpty) {
throw const BadNameException('Name cannot be empty');
}
return 'Hello, $name';
}
Next steps
You have now learned how to handle exceptions in your Celest Functions. Keep reading to learn about configuring your environment and ensuring your backend is secure.