NAME

Kelp::Module::Symbiosis - Fertile ground for building Plack apps

SYNOPSIS

# in configuration file
modules => [qw/Symbiosis SomeSymbioticModule/],
modules_init => {
	Symbiosis => {
		mount => '/kelp', # a path to mount Kelp main instance
	},
	SomeSymbioticModule => {
		mount => '/elsewhere', # a path to mount SomeSymbioticModule
	},
},

# in kelp application - can be skipped if all mount paths are specified in config above
my $symbiosis = $kelp->symbiosis;
$symbiosis->mount('/app-path' => $kelp);
$symbiosis->mount('/other-path' => $kelp->module_method);
$symbiosis->mount('/other-path' => 'module_name'); # alternative - finds a module by name

# in psgi script
my $app = KelpApp->new();
$app->run_all; # instead of run

DESCRIPTION

This module is an attempt to standardize the way many standalone Plack applications should be ran alongside the Kelp framework. The intended use is to introduce new "organisms" into symbiotic interaction by creating Kelp modules that are then attached onto Kelp. Then, the added method run_all should be invoked in place of Kelp's run, which will construct and return an ecosystem.

Module state with Kelp 2.10

This module isn't as useful anymore with Kelp version 2.10 adding easy mounting of Plack apps. It may still be useful in some specific scenarios, like automatic URLMap usage or when some modules use it, but generally you can consider it outdated, as the problem it was solving is now easily solved using core Kelp. See "Nesting Plack apps" in Kelp::Manual for details on how Kelp deals with mounting applications under a route natively.

Why not just use Plack::Builder in a .psgi script?

One reason is not to put too much logic into .psgi script. It my opinion a framework should be capable enough not to make adding an additional application feel like a hack. This is of course subjective.

The main functional reason to use this module is the ability to access the Kelp application instance inside another Plack application. If that application is configurable, it can be configured to call Kelp methods. This way, Kelp can become a glue for multiple standalone Plack applications, the central point of a Plack mixture:

# in Symbiont's Kelp module (extends Kelp::Module::Symbiosis::Base)

sub psgi {
	my ($self) = @_;

	my $app = Some::Plack::App->new(
		on_something => sub {
			my $kelp = $self->app; # we can access Kelp!
			$kelp->something_happened;
		},
	);

	return $app->to_app;
}

# in Kelp application class

sub something_happened {
	... # handle another app's signal
}

What can be mounted?

The sole requirement for a module to be mounted into Symbiosis is its ability to run(), returning the psgi application. A module also needs to be a blessed reference, of course. Fun fact: Symbiosis module itself meets that requirements, so one symbiotic app can be mounted inside another.

It can also be just a plain psgi app, which happens to be a code reference.

Whichever it is, it should be a psgi application ready to be ran by the server, wrapped in all the needed middlewares. This is made easier with Kelp::Module::Symbiosis::Base, which allows you to add symbionts in the configuration for Kelp along with the middlewares. Because of this, this should be a preferred way of defining symbionts.

For very simple use cases, this will work though:

# in application build method
my $some_app = SomePlackApp->new->to_app;
$self->symbiosis->mount('/path', $some_app);

METHODS

These methods are available on the object in $app->symbiosis:

mount

sig: mount($self, $path, $app)

Adds a new $app to the ecosystem under $path. $app can be:

  • A blessed reference - will try to call run on it

  • A code reference - will try calling it

  • A string - will try finding a symbiotic module with that name and mounting it. See "name" in Kelp::Module::Symbiosis::Base

run

Returns a coderef ready to be run by a Plack handler. Details on that depend on the engine used, see "engine".

Note: it will not run mounted object twice. This means that it is safe to mount something in two paths at once, and it will just be an alias to the same application.

mounted

sig: mounted($self)

Returns a hashref containing a list of mounted modules, keyed by their specified mount paths.

loaded

sig: loaded($self)

new in 1.10

Returns a hashref containing a list of loaded modules, keyed by their names.

A module is loaded once it is added to Kelp configuration. This can be used to access a module that does not introduce new methods to Kelp.

METHODS INTRODUCED TO KELP

symbiosis

Returns an instance of this class.

run_all

Shortcut method, same as $kelp->symbiosis->run().

CONFIGURATION

# Symbiosis MUST be specified as the first one
modules => [qw/Symbiosis Module::Some/],
modules_init => {
	Symbiosis => {
		mount => '/kelp',
	},
	'Module::Some' => {
		mount => '/some',
		...
	},
}

Symbiosis should be the first of the symbiotic modules specified in your Kelp configuration. Failure to meet this requirement will cause your application to crash immediately.

engine

new in 2.00

Engine is the approach taken by the module to run your apps. Engines are implemented in namespace KelpX::Symbiosis::Engine. Bundled engines include:

Default is URLMap. See their documentation for caveats regarding each implementation.

mount

new in 1.10

A path to mount the Kelp instance, which defaults to '/'. Specify a string if you wish a to use different path. Specify an undef or empty string to avoid mounting at all - you will have to run something like $kelp->symbiosis->mount($mount_path, $kelp); in Kelp's build method (unless the engine is Kelp, in which case you can't mount the app anywhere - it will always be root).

reverse_proxy

new in 1.11

A boolean flag (1/0) which enables reverse proxy for all the Plack apps at once. Requires Plack::Middleware::ReverseProxy to be installed.

middleware, middleware_init

new in 1.12

Middleware specs for the entire ecosystem. Every application mounted in Symbiosis will be wrapped in these middleware. They are configured exactly the same as middlewares in Kelp. Regular Kelp middleware will be used just for the Kelp application, so if you want to wrap all symbionts at once, this is the place to do it.

CAVEATS

Routes specified in symbiosis will be matched before routes in Kelp. Once you mount something under /api for example, you will no longer be able to specify Kelp route for anything under /api.

SEE ALSO

AUTHOR

Bartosz Jarzyna, <bbrtj.pro@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2020 - 2024 by Bartosz Jarzyna

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.