celest icon indicating copy to clipboard operation
celest copied to clipboard

Allow Celest environment in the backend

Open marcglasberg opened this issue 1 year ago • 3 comments

In a cloud function, if I check celest.currentEnvironment it throws me an error:

An unexpected error occurred: Bad state: Celest has not been initialized. Make sure to call `celest.init()` at the start of your `main` method.

However, it's very useful to know, in the backend code, if it's running locally or not. For example, suppose an admin function that should only work locally (and staging) but not in production. This function can be used to set up the database to some initial state for testing purposes:

Future<void> setDatabase(Portfolio portfolio, Iterable<AvailableStock> availableStocks) async {
   _assertIsNotProduction();
   db.setState(portfolio, availableStocks);
}

/// Some admin functions should NOT work in production.
/// Those that do should make sure it's really the admin who's calling them.
void _assertIsNotProduction() {
   if (celest.currentEnvironment == CelestEnvironment.production)
     throw Exception('This function should only be used in local and staging environments.');
}

Since the celest object is visible from the function code, I think it should have this information (and other information, like the cookies https://github.com/celest-dev/celest/issues/40 maybe). But if you try to access celest.functions from inside a function it should fail with an appropriate error (and not Celest has not been initialized. anyway).

marcglasberg avatar Feb 14 '24 23:02 marcglasberg

Good catch! Let me think about the best way to handle this.

dnys1 avatar Feb 15 '24 01:02 dnys1

Thinking about this some more, I believe there will always need to be a split between the client functionality and the server functionality. Having both available in the same interface will introduce too many footguns.

What would you think about a celestBackend global that is only available on the backend? It would be as close a possible to the frontend's celest global while having divergent functionality where appropriate, for example admin actions, etc.

dnys1 avatar Mar 04 '24 23:03 dnys1

Yes, you are right. In client.dart:

final celest = Celest();
final celestBackend = CelestBackend();

Only problem is, since it's not possible to make celest only visible in the frontend, and celestBackend only visible in the backend, people will still be able to use them in the wrong place, and then get a runtime error. So I think it's important for the plugin to take care of that, by marking it with an error when you use them in the wrong place. I'll add this to the plugin issue: https://github.com/celest-dev/celest/issues/34.

marcglasberg avatar Mar 05 '24 00:03 marcglasberg

This has been fixed in v1! Celest will now generate a celest global in your backend that provides much of the same functionality and backend-specific needs.

For example, when using Celest Data, you'll have a generated global that looks like this in your backend now:


/// The interface to your Celest backend.
///
/// Similar to the `celest` global in the frontend, this
/// provides access to the backend environment and services
/// configured for your project.
const CelestCloud celest = CelestCloud._();

/// The interface to your Celest backend.
///
/// Similar to the `Celest` class in the frontend, this class
/// provides access to the backend environment and services
/// configured for your project.
class CelestCloud {
  const CelestCloud._();

  /// The current environment of the Celest service.
  ///
  /// This is determined by the `CELEST_ENVIRONMENT` variable
  /// which is set for you by the deployment environment.
  CelestEnvironment get currentEnvironment =>
      (variables.currentEnvironment as CelestEnvironment);

  /// The variables of the Celest service.
  ///
  /// This class provides access to the values configured for the
  /// [currentEnvironment].
  CelestVariables get variables => const CelestVariables();

  /// The data services for the Celest backend.
  ///
  /// This class provides access to the databases that are configured
  /// for the [currentEnvironment].
  CelestData get data => const CelestData();
}

dnys1 avatar Oct 15 '24 04:10 dnys1