Giter Club home page Giter Club logo

http's People

Contributors

vladfaust avatar

Stargazers

 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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http's Issues

Add key aliases for params

params do
  type stripe_source : String, key: :stripeSource
end

So, a request of ?stripeSource=foo would propagate params with params[:stripe_source].

Change params DSL

Old:

params do
  param :email, String, validate: {regex: /@/, size: (5..64)}
  param :password, String, validate: {size: (8..64)}
end

New:

params do
  type email : String, validate: {regex: /@/, size: (5..64)}
  type password : String, validate: {size: (8..64)}
end

Pros:

  • Canonical type definition
  • Highlighting
  • Neat indentation (notice how params is indented with type 😏)
  • Editors do not offer param on typing within def call, this is annoying

RFC on keyword though!

Change `halt!` to `break`

Old:

halt!(409, {error: "User already exists"}) if existing_user

New:

break(409, {error: "User already exists"}) if existing_user

Pros:

  • Highlighting

Add Router#on

router = Rest::Router.new do |r|
  r.on "/foo", methods: %w(get put post) do |env|
    MyAction.call(env)
  end
end

Allow to accept empty params

params do
  type email : String | Null?
end

def call
  case params[:email]
  when Null
    user.email = nil
  when String
    user.email = params[:email]
  end
end

Make logged content a bit more abstact

class MyLogger < Rest::Logger
  def content(context)
    params = context.request.query_params.to_h
    somehow_modify_params # For example, cut some sensitive data
    context.request.path + modified_params # By default it's context.resource
  end
end

# GET /path?foo=<#> 1s

or even

logger = Rest::Logger.new do |env|
  context.request.path
end

# GET /path 1s

Adapt the project for newcomers

Crystal is growing. I spend so much effort on Prism to make web-development a joy, but seems like I'm the one who's using Prism in production. Let's change it!

  • Remind that the GitHub README is for the master branch
  • Tell that features appear along my needs and I'm open for issues and PRs
  • Prism needs a website
    • Fancy landing page
    • Docs either on GitBook or VuePress
  • Adapt for developers new to Crystal
    • Benchmarks with other languages
    • Common frameworks code comparison
    • Note about "catch bugs in development, not in production"
    • Tell about websockets built-in
  • Adapt for Crystal developers looking for a better web framework
    • Tell about Prism modularity when you decide what to include
    • Tell about Prism object-oriented approach when where are no global configuration objects which allows to have multiple servers and routers in one application
    • Tell about versatile callbacks system
    • Tell about strict params typecasting which reduces amount of code and improves security drastically
    • Tell about versatile authentication module
  • Add project template

Custom params validation

def foo_valid?(foo)
  some_code?(foo)
end

params do
  param :id, Int32, ->{ p > 0 }
  param :foo, String?, validate: foo_valid?
end

Action & Channel should be modules

Composition over inheritance!

Ideal code would be:

struct MyAction
  include Prism::Action
  include Prism::Params
  include Prism::Auth
  
  auth!

  params do
    param :foo, Int32
  end
  
  def call
    # ...
  end
end

That said, following must be implemented:

  • Prism::Action includes Callbacks and they do actually work (see crystal-lang/crystal#1104 (comment))
  • MyAction can be an abstract struct and callbacks should work in this case as well
  • Prism::Params and Prism::Auth included along with Prism::Action automatically inject those before callbacks Introduce Prism::Action::Params & Prism::Action::Auth, which is more straightforward IMO

Faster router

Before 46e9ec7 (it used Router::Cacher):

faust@mi:~/Projects/prism$ crystal bench/router.cr --release --no-debug

Begin benchmarking router...
Running static paths...

simply cached router with static path   2.72M (367.77ns) (±17.02%)  207 B/op        fastest
   non-cached router with static path   1.41M (706.98ns) (± 8.20%)  496 B/op   1.92× slower

Running dynamic paths (random from 10000 known paths)...

simply cached router with dynamic paths 954.07k (  1.05µs) (±11.87%)   848 B/op        fastest
   non-cached router with dynamic paths 701.96k (  1.42µs) (±16.06%)  1296 B/op   1.36× slower

Running absolutely random paths (caching is useless)...

simply cached router with random paths 279.56k (  3.58µs) (±20.55%)  1449 B/op   2.09× slower
   non-cached router with random paths 584.69k (  1.71µs) (±19.35%)  1365 B/op        fastest

✔️ Done benchmarking router

After 46e9ec7:

faust@mi:~/Projects/prism$ crystal bench/router.cr --release --no-debug
  with static path    3.0M (333.73ns) (± 8.66%)   194 B/op        fastest
with dynamic paths 777.92k (  1.29µs) (±12.42%)  1400 B/op   3.85× slower
 with random paths 628.63k (  1.59µs) (± 8.63%)  1317 B/op   4.77× slower

Extract params to an external shard

Prism is famous for its strict params typing allowing nesting and array params as well. I'm proud of that and it's initially has been a goal for this project - typed params.

I know that other frameworks lack in this type of functionality and I'd like to extract it into a separate shard.

@paulsmith said that it would be better to make Params a class and make all params accessible by a method (e.g. params.user.email). Also there was a thought of making it abstract so it works not only with HTTP params, but with other data inputs.

How do you see an ideal shard for such a functionality? Take your time, see the code (start from https://github.com/vladfaust/prism/blob/master/src/prism/params.cr).

/cc @drujensen

Allow kebab-case params

Currently this does not compile:

params do
  param :"my-param", String?
end

With following error:

Syntax error in expanded macro: define_params_tuple:9: expected ')' or named argument, not g

          g-recaptcha-response: String
          ^

Which is kinda expected.

Cookies example

I'm guessing there's a straightforward way of handling this but everything I end up with feels a little overcomplicated or sloppy, typically via HTTP::Cookies and the Set-Cookie header. Is there a nicer way of handling this?

Would this a good candidate for a documentation example? Or even some kind of helper module?

Error: Prism::Action is not a module, it's a struct

Running the basic example:

require "prism"

struct KnockKnock
  include Prism::Action
  include Prism::Action::Params

  params do
    param :who, String
    param :times, Int32, validate: {max: 10}
  end

  def call
    params[:times].times do
      text("Knock-knock #{who}\n")
    end
  end
end

router = Prism::Router.new do
  get "/:who", KnockKnock
end

logger = Logger.new(STDOUT)
log_handler = Prism::LogHandler.new(logger)
handlers = [log_handler, router]

server = Prism::Server.new(handlers, logger)
server.bind_tcp(8000)
server.listen

#  INFO -- :   Prism::Server is listening on http://127.0.0.1:5000...

Results in a error:

Error in src/simple_app.cr:4: Prism::Action is not a module, it's a struct

  include Prism::Action

Crystal Info

$ crystal -v
Crystal 0.26.0 [eeb53c506] (2018-08-09)

LLVM: 4.0.0
Default target: x86_64-unknown-linux-gnu

Halting with JSON

These halts should cast an object to JSON and change content type:

halt!(409, {error: "Something went wrong"})
halt!(403, PaymentError.new)

Web Sockets accessible only via ws:// scheme

Should check incoming request's scheme and organize the routing tree with /ws instead of current /get.

This will allow to place websocket actions under the same routes. 👍

Ruby-ish style callbacks

Current:

def before
  super
  some_code
end

Proposed:

before do
  some_code
end

before do
  another_code
end

Rename `from_s`

A program could potentially have many ways to initialize types from String, e.g. Int32 could be initialized like Int32.from_s("one") in some code.

I should rename from_s to something like from_string_param or maybe introduce initializers which accept String.

Complex types params

Cast String to Array or Hash, e.g:

params do
  param :ids, Array(String)
end

The issue is that different content types have different ways to pass arrays (and hashes). Moreover, there is no single standard of how-to... 🤔

Export routes with params

struct UpdateUser
  params do
    type id : Int32
    type name : String, description: "The name of the user"
  end
end

router = Atom::Handlers::Router.new do
  patch "/users/:id", UpdateUser
end
app --routes
PATCH /users/:id
   ├─ id : Int32
   └─ name : String (The name of the user)

Nested params

params do
  param :user do
    param :email, String
    param :password, String
  end
end

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.