https://github.com/rawleyfowler/slick
Slick: A Perl web toolkit built on technologies you already know
https://github.com/rawleyfowler/slick
hacktoberfest microservice-framework perl perl5 plack plack-app restful-webservices
Last synced: about 1 year ago
JSON representation
Slick: A Perl web toolkit built on technologies you already know
- Host: GitHub
- URL: https://github.com/rawleyfowler/slick
- Owner: rawleyfowler
- License: mit
- Created: 2023-07-28T17:19:52.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2024-10-16T17:35:19.000Z (over 1 year ago)
- Last Synced: 2025-03-23T21:35:55.510Z (about 1 year ago)
- Topics: hacktoberfest, microservice-framework, perl, perl5, plack, plack-app, restful-webservices
- Language: Perl
- Homepage:
- Size: 153 KB
- Stars: 9
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES
- License: LICENSE
Awesome Lists containing this project
README
# [Slick](https://metacpan.org/pod/Slick)
Slick is an Object-Oriented Perl web-framework for building performant, and easy to refactor web applications.
Slick is built on top of [DBI](https://metacpan.org/pod/DBI), [Plack](https://metacpan.org/pod/Plack),
and [Moo](https://metacpan.org/pod/Moo) and fits somewhere in-between the realms of Dancer and Mojo.
Slick has everything you need to build a Database driven REST API, including built in support
for Database connections, Migrations, and Caching via Redis or Memcached. Since Slick is a Plack application,
you can also take advantage of swappable backends and Plack middlewares extremely simply.
Currently, Slick supports `MySQL`, `Redis`, `Memcached` and `Postgres` but there are plans to implement `Oracle` and `MS SQL Server`.
## Philosophy
Slick is aiming to become a "Batteries Included" framework for building REST API's and Micro-Services in
Perl. This will include tooling for all sorts of Micro-Service concerns like Databases, Caching, Queues,
User-Agents, and much more.
### Goals
- [x] Database management (auto-enabled)
- [x] Migrations (auto-enabled)
- [ ] CLI
- [x] Caching via Redis (optional)
- [x] Caching via Memcached (optional)
- [x] Sub-routine based caching for routes (optional)
- [ ] RabbitMQ built-ins (optional)
- [ ] AWS S3 support (optional)
- [ ] User-Agents, including Client API exports
- [ ] AWS SQS support (optional)
*Note*: All of these features excluding database stuff will be enabled optionally at run-time.
## Examples
### Single File App
```perl
use Slick;
my $s = Slick->new;
# Both MySQL and Postgres are supported databases
# Slick will create the correct DB object based on the connection URI
# [{mysql,postgres,postgresql}://][user[:[password]]@]host[:port][/schema]
$s->database(my_db => 'postgresql://user:password@127.0.0.1:5432/schema');
$s->database(corporate_db => 'mysql://corporate:secure_password@127.0.0.1:3306/schema');
$s->my_db->migration(
'create_user_table', # id
'CREATE TABLE user ( id SERIAL PRIMARY KEY AUTOINCREMENT, name TEXT, age INT );', #up
'DROP TABLE user;' # down
);
$s->my_db->migrate_up; # Migrates all pending migrations
$s->get('/users/{id}' => sub {
my $app = shift;
my $context = shift;
# Queries follow SQL::Abstract's notations
my $user = $app->my_db->select_one('user', { id => $context->param('id') });
# Render the user hashref as JSON.
$context->json($user);
});
$s->post('/users' => sub {
my $app = shift;
my $context = shift;
my $new_user = $context->content; # Will be decoded from JSON, YAML, or URL encoded (See JSON::Tiny, YAML::Tiny, and URL::Encode)
$app->my_db->insert('user', $new_user);
$context->json($new_user);
});
$s->run; # Run the application.
```
See the examples directory for this example.
### Multi-file Router App
```perl
### INSIDE lib/MyApp/ItemRouter.pm
package MyApp::ItemRouter;
use Moo;
extends 'Slick::Router';
my $router = __PACKAGE__->new(base => '/items');
$router->get('/{id}' => sub {
my ($app, $context) = @_;
my $item = $app->items_db->select_one({ id => $context->param('id') });
$context->json($item);
});
$router->post('' => sub {
my ($app, $context) = @_;
my $new_item = $context->content;
# Do some sort of validation
if (not $app->item_validator->validate($new_item)) {
$context->status(400)->json({ error => 'Bad Request' });
}
else {
$app->items_db->insert('items', $new_item);
$context->json($new_item);
}
});
sub router {
return $router;
}
1;
package main;
use 5.036;
use lib 'lib';
use Slick;
use MyApp::ItemRouter;
my $slick = Slick->new;
$slick->database(items_db => 'sqlite://items.db');
$slick->register(MyApp::ItemRouter->router);
$slick->run;
```
See the examples directory for this example.
### Running with `plackup`
If you wish to use `plackup` you can change the final call to `run` to a call to `app`
```perl
$s->app;
```
Then simply run with plackup (substitue `my_app.psgi` with whatever your app is called):
```bash
plackup -a my_app.psgi
```
### Changing PSGI backend
Will run on the default [`HTTP::Server::PSGI`](https://metacpan.org/pod/HTTP::Server::PSGI).
```perl
$s->run;
```
or
In this example, running Slick with a [`Gazelle`](https://metacpan.org/pod/Gazelle) backend on port `8888` and address `0.0.0.0`.
```perl
$s->run(server => 'Plack::Handler::Gazelle', port => 8888, addr => '0.0.0.0');
```
### Using Plack Middlewares
You can register more Plack middlewares with your application very easily!
```perl
my $s = Slick->new;
$s->middleware('Deflater')
->middleware('Session', store => 'file')
->middleware('Debug', panels => [ qw(DBITrace Memory) ]);
$s->run; # or $s->app depending on if you want to use plackup.
```
## Managing Your Database(s)
Slick allows you to easily connect databases to your applications.
### Creating a database
```perl
my $s = Slick->new;
$s->database(my_postgres => 'postgresql://username:password@127.0.0.1:5432/db_name');
```
### Migrations
Migrations are built using the `migration` method on `Slick::Database`. You provide 1, an ID for the migration,
2, the runnable/happy side of the migrations, and 3, the down or reverse of the migration.
```perl
$s->database('my_postgres')
->migration('create_users_table',
'CREATE TABLE users ( id INT PRIMARY KEY, name TEXT, age INT );',
'DROP TABLE user;')
->migration('create_pets_table',
'CREATE TABLE pets ( id INT PRIMARY KEY, name TEXT, owner INT FOREIGN KEY REFERENCES users (id) );',
'DROP TABLE pets;');
```
### Queries
Queries in Slick are built with [`SQL::Abstract`](https://metacpan.org/pod/SQL::Abstract), and most of the heavy lifting
is done for you already!
```perl
my $users = $s->my_postgres
->select('users', [ 'id', 'name' ]); # SELECT id, name FROM users;
my $user = $s->my_postgres
->select_one('users', [ 'id', 'name', 'age' ], { id => 1 }); # SELECT id, name, age FROM users WHERE id = 1;
$s->my_postgres
->insert('users', { name => 'Bob', age => 23 }); # INSERT INTO users (name, age) VALUES ('Bob', 23);
$s->my_postgres
->update('users', { name => 'John' }, { id => 2 }); # UPDATE users SET name = 'John' WHERE id = 2;
```
If you can't do what you want with `SQL::Abstract` helpers, you can certainly do it with DBI!
```perl
$s->database('my_postgres')->dbi->execute('DROP TABLE users;');
```
## Caching
Slick supports caching using [`Memcached`](https://memcached.org) or [`Redis`](https://redis.io).
```perl
use 5.036;
use Slick;
use Slick::Annotation qw(cacheable);
my $s = Slick->new;
# See Redis and Cache::Memcached on CPAN for arguments
# Create a Redis instance
$s->cache(
my_redis => type => 'redis', # Slick Arguments
server => '127.0.0.1:6379' # Cache::Memcached arguments
);
# Create a Memcached instance
$s->cache(
my_memcached => type => 'memcached', # Slick Arguments
servers => ['127.0.0.1'] => debug => 1 # Cache::Memcached arguments
);
$s->my_redis->set( something => 'awesome' );
$s->get(
'/foo' => sub {
my ( $app, $context ) = @_;
my $value = $app->cache('my_redis')->get('something'); # Use your cache
return $context->text($value);
}
);
# Use your cache to cache a route
$s->get(
'/foobar' => cacheable(
'my_redis',
sub {
my ( $app, $context ) = @_;
return $context->json( { foo => 'bar' } );
}
)
);
$s->run;
```
## Deployment
Please follow a standard `Plack` application deployment. Reverse-proxying your application behind
[`NGiNX`](https://nginx.org) or [`Caddy`](https://caddyserver.com) and using [`Docker`](https://www.docker.com) can
drastically improve your deployment.
An example `Dockerfile` can be found in the examples directory.
## Contributing
Slick is open to any and all contributions.
**Code Standards**:
* Always format with the provided `.perltidyrc`
* Always use `Perl::Critic` set to severity `3`
* Unpack subroutine arguments using array-destructuring when there are 2 or more elements
## License
Slick is provided under the Artistic 2.0 license.