0.0
There's a lot of open issues
Provides a RESTful API for database tables for your rails apps.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

~> 2.2, >= 2.2.1
>= 6.0.0
 Project Readme

CrazyTrain Logo

I'm going off the rails on a crazy train.

CrazyTrain

This gem is still unstable.

Provides a RESTful API for database tables into your rails apps.

Installation

Add this line to your application's Gemfile:

gem "crazy_train"

And then execute:

$ bundle install

Execute the below to generate a configuration file.

$ rails generate crazy_train:install
# config/initializers/crazy_train.rb:
CrazyTrain.setup do |config|
  config.secret = 'xxxxxxxxxxxxxxxx'
  config.unauthorized_role = 'anonymous'
  config.authorized_role = 'authenticated'
end

Then add a line to routes.rb to mount the API.

# routes.rb:
Rails.application.routes.draw do
  mount CrazyTrain::Engine, at: '/api'
end

Usage

crazy_train uses RLS for access control.

If accessed without authentication, it is accessed with anonymous ROLE. If accessed with authentication, it is accessed with authenticated ROLE.

Set the authorization and RLS POLICY so that posts can SELECT even when unauthorized.

(Assume that you have a posts table in an existing rails project.)

GRANT SELECT ON posts TO anonymous;
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
CREATE POLICY posts_policy ON posts TO anonymous USING (TRUE);

Then you can use the REST API as follows.

$ curl http://localhost:3000/api/posts
[
  {
    "id": 1,
    "content": "crazy"
  },
  {
    "id": 2,
    "content": "train"
  }
]

You can use the API in the same way if you also set up permissions and POLICY settings for other tables and other ROLEs.

Access to the DB in rails is done by default ROLE, so it is not affected.

For complex items, create a Web API manually as usual, and use this for items that require a simple CRUD.

Authentication

crazy_train provides a mechanism for authentication in JWT.

You can generate a token using the crazy_train:generate_token task. (secret uses the value of CrazyTrain.config.secret)

$ rails crazy_train:generate_token
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

The token allows you to access the API in an authenticated state.

$ curl curl http://localhost:3000/api/posts/1234 \
  -H "Authorization: Bearer aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
{
  "id": 1234,
  "content": "crazy"
}

JWT-Based User Impersonation

What if I want to create another ROLE (e.g. admin ROLE) for authentication?

In crazy_train, if there is a role item in the JWT payload, it will be used as the ROLE name.

To create a token to authenticate with admin ROLE, do the following

$ rails crazy_train:generate_token PAYLOAD='{"role": "admin"}'
bbbbbbbbbbbbbbbbbbbbbbbbbbb

When the API is accessed using this token, the DB is accessed as an admin ROLE.

$ curl curl http://localhost:3000/api/posts/1234 \
  -H "Authorization: Bearer bbbbbbbbbbbbbbbbbbbbbbbbbbb"
{
  "id": 1234,
  "content": "crazy"
}

Individual user identification

What if I need to identify individual users to create a POLICY, such as "I can only view the posts I have posted"?

In crazy_train, the JWT payload can be retrieved via a user-defined configuration parameter in postgresql.

If you want to use the following as a PAYLOAD,

{ "user_id": 1234 }

In the DB, you can use current_setting to get it from request.jwt.claims.

SELECT current_setting('request.jwt.claims', true)::json->>'user_id';
# => 1234

The POLICY "Only your `posts`` can be viewed" can be written as follows.

CREATE POLICY posts_policy ON posts
  USING (user_id = current_setting('request.jwt.claims', true)::json->>'user_id');

API

Allows CRUD to be performed on tables that exist in the DB.

HTTP Verb URL Description
GET /api/posts List
GET /api/posts/1234 Read
POST /api/posts Create
PUT /api/posts/1234 Update
Delete /api/posts/1234 Delete
$ curl localhost:3000/api/posts
[{"id":1,"body":"text 1"},{"id":2,"body":"text 2"},{"id":3,"body":"text 3"}]
$ curl localhost:3000/api/posts/1
{"id":1,"body":"text 1"}

Ordering

Sorting can be performed using the order parameter. Column names and sort order are separated by . , and multiple rules are separated by ,.

$ curl http://localhost:3000/api/posts?order=content.asc,id.desc
[
  {
    "id": 2,
    "content": "train"
  },
  {
    "id": 1,
    "content": "crazy"
  }
]

Contributing

Contribution directions go here.

License

The gem is available as open source under the terms of the MIT License.