Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

axel

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

axel

  • 0.0.1
  • Rubygems
  • Socket score

Version published
Maintainers
1
Created
Source

Axel

Build Status

The building blocks for building a Sport Ngin Back-end API service:

  • add some error helpers (error object)
  • standardized XML/JSON envelope (metadata/error/result objects)
  • adding suppress_response_codes to params will force a 200 and will only show errors in the error object of the response body
  • standard controller responders to ensure JSON is always prefered, XML is acceptable, and the response always has a correct body that handles all errors

Installation

Add this line to your application's Gemfile:

source 'https://D9W5miiTyaf8EzrkWdTy@gem.fury.io/me/' # BELOW THE `source rubygems`
gem 'axel'

Then execute:

$ bundle

In your app/controllers/application_controller.rb (or wherever your base class is that will use these helpers) change to:

class ApplicationController < ActionController::Base
  include Axel::ControllerHelpers
end

Usage

Controller Specific Helpers

Errors

Errors object is available (as errors) from any controller:

errors.header_status         # suppress_response_codes param will set to 200 by default
errors << "Error message!"   # add error messages
errors.display               # { status: errors.status_code, messages: errors.messages }
errors.display?              # Display errors? (was there an error added or status changed?)
errors.messages
errors.messages = []
errors.status = :not_found
errors.status_code            # => 404
errors.status = 403
errors.status_code            # => 403
errors.new_error(status, *m)  # set status, add an error or list of errors (not in an array object)

# Can also set on the fly:
rescue_error status: :not_found, message: "Error!"
rescue_error status: :unproccessable_entity, messages: ["Error!", "Error2!"]
Metadata

Metadata object that will be placed on every outgoing response body. You can add to the object like so:

metadata[:current_user] = current_user

# the body will then set this on the outgoing body:
# => { "metadata": { "current_user": "..." }, "result": "...", "...": "..." }
Responders

At the top of each controller (for APIs) should be:

respond_to_json_xml

This defines respond_to :json, :xml.

making these responders good to use for defaults:

respond_with_action :show   # Good for the end of a create to show the created object
render_action :show
respond_to_empty            # Render empty `result`, fill in `metadata`, `error` if necessary
render_empty
Resource finder

find_resource will automatically find a resource:

class PostsController < ApplicationController
  before_filter :find_resource
  def show
    respond_with
  end
end

curl http://localhost:3000/posts/1 # finds Post 1 and renders
curl http://localhost:3000/posts/1
# => {"metadata":{},"error":{"status":404,"messages":["Record not found"]},"result":null}

# can also customize the find_resource with `finder` and `value`
# were `finder` is column and `value` is the value of the column
Param helpers
query_params    # Only params on the query string
post_params     # POST params
object_params   # Either params under the object name (ie. {"user":".."} or all POST params
object_name     # singularized controller name for finding object_params
General workflow helpers

Helpers:

force_ssl!        # raises Errors::ForceSSL
drop_meta!        # we don't want the requester to get data like current_user, etc.
drop_meta?        # Did we call `drop_meta!`?
format            # The format passed from the request OR JSON
render_nil_format # This is for rendering nils in json or XML (XML is blank, JSON is "null")
safe_json_load    # If you've already manually rendered some to json this helper safely loads it to a hash for re-JSONing

Errors are rescued to make for easier API workflow and responding:

Axel::Errors::ForceSSL                # Drop meta
                                            # Status: Forbidden
                                            # Message: SSL is required

ActiveRecord::RecordNotFound                # Status: 404
                                            # Message: Record not found

Axel::Errors::NotAuthorized           # Status: 401
                                            # Message: User not authorized

ActiveModel::MassAssignmentSecurity::Error  # Status: 422
                                            # Message: Unacceptable parameter being used

Interservice Helpers

Some setup examples
Axel.config do |config|
  config.add_resource :user_service,
    :group,
    service: { url: "https://user-service.your-platform.com" }

  # Custom Path (otherwise defaults to plural of the resource_name (:user => "/users"))
  # config.add_resource :user_service,
  #   :user,
  #   service: { url: "https://user-service.your-platform.com" },
  #   attributes: [:user_name, :first_name],
  #   path: "owner"
end

class Group < Axel::ServiceResource::Base
  # Let's say your class doesn't match the configured resource, you can:
  resource_name :group

  # Setup fields (gets accessors, all available in #attributes)
  field :name
  field :owner_id
  field :owner_type
  field :uri

  route "/groups/mine", :mine
  route "/user/:user_id/groups", :by_user_id

  # Attached to every Group request, you can define instance defaults as well
  def self.default_request_options
    { headers: { "Accepts" => "stuff!", Authorization: "Bearer #{some_access_token}" } }
  end
end

group = Group.new name: "test", owner_id: 1, owner_type: "Organization", uri: "blargh"
group.save

my_groups = Group.mine
user_groups = Group.by_user_id(1)
user_groups = Group.by_user_id(user_id: 1)

a_group = Group.find(1)
class User < Axel::ServiceResource::Base
  has_many :personas
  has_one :email_address, class: Email, included: true
end

class Email < Axel::ServiceResource::Base
  belongs_to :user, find_nested: true
end

class Persona < Axel::ServiceResource::Base
  belongs_to :user
end

u = User.find(1)
u.personas            # => API call to /users/1/personas puts data in an array of Persona objects
u.email_address       # => Uses `email_address` in the User data to put into Email objects
Persona.find(1).user  # => API call to /users/#{persona.user_id} fills User object
Email.find(1).user    # => API call to /personas/1/user fills User Object
Some Chainable Query methods
Group.where(name: "test")
# => https://user-service.your-platform.com/groups?name=test

Group.all params: { name: "test" }, body: jsonified_stuffs, headers: {}, method: :post

Group.uri("https://user-service.dev/groups").where(name: "Jon").all(headers: {})
# => http://user-service.dev/groups?name=Jon

Group.uri("https://user-service.dev").at_path("/other_groups_path").where name: "test"
# => http://user-service.dev/other_groups_path?name=test

Group.where(name: "Jon").all(headers: {}).none
# => [] # Will always be empty array

Group.none.where(name: "Jon")
# => [] # can chain

Group.without_default_path.at_path("groupies")
# => https://user-service.your-platform.com/groupies

# Enumerable works!
Groups.where(name: "test").each { |g| puts e.attributes.inspect }
groups = Groups.where(name: "test").to_a

# drop cached JSON, then you can requery
groups.reload.where(owner_id: 1)
More General Usage
new_user.metadata                 # => { .. } # Metadata section of JSON output
new_user.metadata[:current_user]  # => { "id"=>1, "user_name"=>"admin", "first_name"=>"Happy", "last_name"=>"Gilmore", "uri"=>"http://user-service.dev/users/1"}
new_user.errors.status_code       # => 200
new_user.errors.messages          # => []
new_user.result                   # => { ... } # Main envelope JSON body

For more info on what the requester is and can do check out Axel::ServiceResource::Base

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

FAQs

Package last updated on 03 Jun 2015

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc