Giter VIP home page Giter VIP logo

attributor's Introduction

Praxis TravisCI Coverage Status

A fast and highly efficient paradigm to build beautiful service APIs

Praxis is built to empower development teams with extreme productivty tools to create fast, and modern APIs that will delight their customers. Some of the salient features are:

  • Truthful & Beautiful Docs: Automatically generate Open API 3.x documents from the actual functioning code, and rest assured they're always correct.

  • GraphQL Flexibility, REST Simplicity: Allow customers to specify which fields they want to receive using the GraphQL syntax, but exposing them through well known REST endpoints.

  • Fast Runtime and Blazing Fast Development: Deploy your API using one of the best Ruby performing frameworks and take advantage of an unprecedented development speed.

  • API Design-First Philosophy: Craft and visualize your API design upfont, without writing a single line of code. Forget about implementing any of the API validations, the framework fully takes care of it from your design specification.

  • Feature Rich yet Fully Customizable: Fully take advantage of the tons of best practices, proven methods, standards and features that the frameworks comes with, or pick and choose only the ones you want to enable.

  • Hardnened & Battle Tested: Rest assured you'll get the advertised results as this framework has been deployed in production environments since before 2014.

Quickstart

# Install the praxis gem
gem install praxis

# Generate and bundle a praxis application named my-app in ./my-app
praxis example my-app && cd my-app && bundle

# Run it!
rackup

Or check the getting started tutorial and reference docs at https://site.praxis-framework.io all that Praxis has to offer.

Mailing List

Join our Google Groups for discussion, support and announcements.

And follow us on twitter: @praxisapi

Contributions

Contributions to make Praxis better are welcome. Please refer to CONTRIBUTING for further details on what contributions are accepted and how to go about contributing.

Requirements

Praxis requires Ruby 2.7.0 or greater, but it is best when used with the latest 3.x series.

License

This software is released under the MIT License. Please see LICENSE for further details.

This framework was initially developed and used at RightScale, and was open sourced in 2014, after a few years of its production use.

attributor's People

Contributors

blanquer avatar careo avatar danialm avatar euge avatar gampleman avatar justingaylor avatar kwojcik avatar lisabien avatar magneland avatar thann avatar xeger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

attributor's Issues

Cannot define attribute named `method`

When I try to define an attribute named :method, I get the following error:

Attributor::DumpError: Error while dumping attribute method of type V1::MediaTypes::Hello for context $. Reason: wrong number of arguments (0 for 1)

ArgumentError: wrong number of arguments (0 for 1)

This is possibly related to #71

attributor needs human-readable documentation and examples

Attributor is severely lacking in terms of documentation. General usage needs to be documented along with special documentation for every built in attributor type. I think it would also be useful to add documentation on how to implement custom types.

Enhancements to Attribute options

  1. Support array of regular expressions to use for value validation. Either Attribute could accept a list of regular expressions here, or we could provide some way for the type to override the type to override that behavior (so at least String can take an array of regexes).
  2. Validate that :values are valid
  3. Validate that :default is valid
  4. And make the part of check_option below less weird.

Weird part:

unless self.type.valid_type?(definition) || definition.is_a?(::Regexp) || definition.is_a?(::String) || definition.is_a?(::Array)
  raise AttributorException.new("Invalid example type (got: #{definition.class.name}). It must always match the type of the attribute (except if passing Regex that is allowed for some types)")
end

Add easy way to find 'leaf' types

We have this pattern repeated in a number of places: if type.respond_to?(:attributes) || type.respond_to?(:member_attribute) and could simplify it if we had an easy way to tell if a type was a "complex" one or represented a single value.

Add descriptions for more things

There doesn't seem to be a way to set a description on a attributor model. This seem like a very useful thing to have. Hash and Collection could support it as well for some uses.

Default attribute type and options in Attributor model

Attributor::Model definition tends to look heavy. It would be nice to have a default type and default options for its attributes when you define a model.
How it is:

    class Definition < Attributor::Model
      attributes do
        attribute :action, String, required: true
        attribute :project_id, String, required: true
        attribute :resource_type, String, required: true
        attribute :service, String, required: true
        attribute :service_id, String, required: true
        attribute :status, String, required: true
        attribute :task_id, String, required: true
        attribute :vendor, String, required: true
        attribute :tracking_number, String
        attribute :output, Hash
      end
    end

How it could look like:

    class Definition < Attributor::Model
      attributes(String, required:true) do
        attribute :action
        attribute :project_id
        attribute :resource_type
        attribute :service
        attribute :service_id
        attribute :status
        attribute :task_id
        attribute :vendor
        attribute :tracking_number, required: false
        attribute :output, Hash, required: false
      end
    end
end

where "String" is a default attribute type and default value for "required" is "true".

Regexp options should render nicely

Currently, dumping a Regexp object as JSON produces a not very human friendly string:

Regexp.new(/yoyo/).to_s
"(?-mix:yoyo)"

We might need to use our own Regexp classes for these options, that can more easily display themselves as strings.
Note: We might want to use Mustermann for that too, something to explore.

Attributor::Hash should implement fully the interface of Ruby's Hash

Currently, the Attributor::Hash returned when loading an attribute of type Attributor::Hash doesn't quack like a Ruby Hash.

[2] pry(main)> config.has_key?('foobar')
NoMethodError: undefined method `has_key?' for #<Attributor::Hash:0x007fb6e008cd90>
from (pry):2:in `block (2 levels) in <top (required)>

We should fix this.

Support Hash type in Attributor

We have Struct but it requires specific attributes to be defined. I have a use case for passing a hash through to another API without validating the contents of the hash. I only want to validate 'is-a-hash'.

DSL cannot handle Boolean, only Attributor::Boolean

This is because there is no Boolean type defined in Ruby, thus syntax parsing fails with:

/Users/justingaylor/Work/attributor/spec/attributor_spec.rb:18:in `block (3 levels) in <top (required)>': uninitialized constant Boolean (NameError)
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:246:in `module_eval'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:246:in `subclass'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:232:in `describe'
    from /Users/justingaylor/Work/attributor/spec/attributor_spec.rb:6:in `block (2 levels) in <top (required)>'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:246:in `module_eval'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:246:in `subclass'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:232:in `describe'
    from /Users/justingaylor/Work/attributor/spec/attributor_spec.rb:5:in `block in <top (required)>'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:246:in `module_eval'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:246:in `subclass'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/example_group.rb:232:in `describe'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/dsl.rb:18:in `describe'
    from /Users/justingaylor/Work/attributor/spec/attributor_spec.rb:4:in `<top (required)>'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/configuration.rb:896:in `load'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/configuration.rb:896:in `block in load_spec_files'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/configuration.rb:896:in `each'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/configuration.rb:896:in `load_spec_files'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/command_line.rb:22:in `run'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/runner.rb:80:in `run'
    from /Users/justingaylor/.rightscale_bundle/attributor/ruby/1.9.1/gems/rspec-core-2.14.5/lib/rspec/core/runner.rb:17:in `block in autorun'

Provide native_type for Attributor::Boolean

Per discussion here: https://github.com/rightscale/attributor/pull/16/files#r6722390

It should be possible to make TrueClass and FalseClass both have a common ancestor and implement Attributor::Boolean.native_type, provided that the following points are observed:

  • The parent class of TrueClass and FalseClass needs to be in the Attributor namespace somewhere.
  • We cannot mix anything into the classes other than logic to report that TrueClass and FalseClass are Attributor::Boolean objects.
  • Also confirm that === works.

For Inspiration:
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/extensions/boolean.rb
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/extensions/false_class.rb
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/extensions/true_class.rb

Random string generation doesn't consider :values option

If an attribute is created like so:

attribute 'state', String, :values => ['operational', 'terminated']

Then the random generation for String give a value which is not one of the required :values.

To fix this, we need to make String.example perform an Array#sample on the array of values when values is set.

Example generation for untyped Collection and keyed Hash fails

Trying to generate examples for:

  • a simple Attributor::Collection (without the .of(...) )
  • an Attributor::Hash with keys defined in the block

fails with something like:

 TypeError: no implicit conversion of Array into String
         # ./lib/attributor/types/hash.rb:127:in `+'
         # ./lib/attributor/types/hash.rb:127:in `block in example'
         # ./lib/attributor/types/hash.rb:126:in `each'
         # ./lib/attributor/types/hash.rb:126:in `example'

Make attribute loading report errors with full attribute contexts

Right now, an error when loading an attribute can only report the problem, but cannot say what the name of the attribute it happened on.

Need to percolate the context down on loading, so that this can be properly done.

Need to be careful about performance passing and concatenating strings...perhaps we can pass arrays with the name hierarchy, and only concatenate whenever it is needed

Note: is this worth to port to validation (i.e. passing the context as arrays instead of hashes?)

Examples with Integer types are not accepted properly

When providing an example in an attribute fails, unless it it a String (or an Array, Regexp or a Proc)

For example, this definition:

attribute :version, Integer, example: 13

will end up giving an error like:

Reason: unknown example attribute type, got: 13

I believe the issue is that the example function was never updated to work on things other than strings here: https://github.com/rightscale/attributor/blob/master/lib/attributor/attribute.rb#L138

I believe the fix is to simply remove that String case, and put it at the end, to return the unmodified val for any other type that is not special (Regexp, Proc, Array)

Fail early when one defines an attribute that overlaps with any method in Attributor::Model

In the example below attribute ":attributes" overlaps with pre existing method "attributes" defined in Attributor::Model.

  class Data < Attributor::Model
    attributes do
      attribute :foo, String
      attribute :attributes, Hash
    end
  end

This compiles and runs. And you do not see any obvious issues until you try to load and validate your attributor model instance where it fails with a weird error:

Attributor::Hash can not validate object of type Hash for $.attributes 

It would be nice to fail earlier (ideally in the model definition) or at least to have a better error message.

Attributor throws syntax error when a header is defined with hypens

As a user, I should be able to define headers with hyphens in the name like "Content-Type", "X-Api-Version", etc.

But attributor throws a Syntax Error if I try to define a header with hyphens.

headers do
  header :'X-Api-Version', String, values: ['1.0'], required: true
end

SyntaxError: .../ruby/2.1.2/lib/ruby/gems/2.1.0/gems/attributor-2.1.0/lib/attributor/types/model.rb:38: syntax error, unexpected '-', expecting ';' or '\n'
        def X-API-VERSION

The attributor should be able to catch such exceptions.

Extract attribute options logic into the specific type class

Only attribute options that apply uniformly to all types (e.g. :regexp, :required, :required_if) should be validated in the Attributor::Type module. The rest of options (e.g. :min, :max, :max_length, :empty?, etc.) have validation that depends on the specific type and may not be meaningful for other types.

Attributor::String.load() loads Arrays and other complex types

For example:

$ bundle exec irb
irb(main):001:0> require 'attributor'
=> true
irb(main):002:0> Attributor::String.load([1,2,3])
=> "[1, 2, 3]"

Underneath, I see that the Attributor::String type does String(value), but in this case, it doesn't seem intuitive what should be done when a complex type like an Array or Hash are passed in.

In my particular case, a YAML file was incorrectly specifying a String value as an Array, then when trying to load it we were suddenly getting array brackets around the expected string. It would have been preferable in this case to receive an Attributor error saying that Array in not a valid String.

Collection needs to needs to support nil values

If an attribute is an optional collection and nil is given, the render code blows up later on with:

NoMethodError - undefined method collect' for nil:NilClass#012/usr/lib/ruby/gems/2.1.0/bundler/gems/attributor-14efe92c3ac7/lib/attributor/types/collection.rb:95`

Either Collection.dump or Collection.load need to handle nil values. Probably the latter.

Rethink exception handling

Attributor has a few huge pain points in its exception handling. The biggest offender probably being Attribute#load, who loves to eat errors that come from lazy attribute creation and have nothing to do with the actual loading at hand.

I can think of at least two fixes (both should be done):

  1. add a separate hierarchy of exceptions that specifically does not derive from StandardError for those exceptions that are fatal and a result of a misconfiguration.
  2. rework the myriad Type.load to not rely on exceptions like this one for reporting malformed data: ArgumentError: invalid value for Integer(): "hi"

use BasicObject as base class for Attributor::Model instead of Object

The issue is that 3rd-party DSLs such as Rake (pre-v10) will define methods on Object that can conflict with attribute names. Since Model does not remove pre-existing method definitions it will simply inherit from Object a method such as 'namespace'. When the 'namespace' attribute is invoked the code instead calls through to Rake v9.

Using BasicObject is tricky, of course, because it lacks useful methods like #to_s, #inspect, #methods, etc

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.