onyxframework / http Goto Github PK
View Code? Open in Web Editor NEWAn opinionated framework for scalable web 🌎
Home Page: https://onyxframework.com/http
License: MIT License
An opinionated framework for scalable web 🌎
Home Page: https://onyxframework.com/http
License: MIT License
params do
type stripe_source : String, key: :stripeSource
end
So, a request of ?stripeSource=foo
would propagate params
with params[:stripe_source]
.
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
param
on typing within def call
, this is annoyingRFC on keyword though!
Old:
halt!(409, {error: "User already exists"}) if existing_user
New:
break(409, {error: "User already exists"}) if existing_user
json(201, {article: article})
text(200, "ok")
Because they're so good.
🤔
For some strange reason application/json; charset=utf-8
turns into application/json
in Action
response despite of
Need to investigate.
router = Rest::Router.new do |r|
r.on "/foo", methods: %w(get put post) do |env|
MyAction.call(env)
end
end
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
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
param :name, validate: {size: {gte: 3}}
It's a nice alternative to {size: (3..Float32::INFINITY)}
.
Because some apps may find it redundant.
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!
params do
param :foo, String, proc: ->(foo : String) { foo.upcase }
end
def foo_valid?(foo)
some_code?(foo)
end
params do
param :id, Int32, ->{ p > 0 }
param :foo, String?, validate: foo_valid?
end
Because it may look like an error.
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 wellPrism::Params
and Prism::Auth
included along with Prism::Action
automatically inject those before
callbacksPrism::Action::Params
& Prism::Action::Auth
, which is more straightforward IMOIt's more commonly used and much clearer IMO. I'm also thinking of less_than: 42
and greater_than_or_equal: 5
, but their lengths are terrifying
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
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
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.
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?
shards install
Fetching https://github.com/atomframework/web.git
Error shard name (prism) doesn't match dependency name (atom-web)
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...
Error in src/simple_app.cr:4: Prism::Action is not a module, it's a struct
include Prism::Action
$ crystal -v
Crystal 0.26.0 [eeb53c506] (2018-08-09)
LLVM: 4.0.0
Default target: x86_64-unknown-linux-gnu
crystal-lang/crystal#5286 is fixed
For apis it would make sense to be able to handle the param erros manually so one can respond with json that can be parsed on the client side.
Currently Rest::Logger
logs a ws
request only when it's closed.
These halts should cast an object to JSON and change content type:
halt!(409, {error: "Something went wrong"})
halt!(403, PaymentError.new)
server = Prism::Server.new(handlers, name: "My API")
# INFO > My API is listening on https://localhost:5000
Are there any benchmarks for Prism?
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. 👍
Current:
def before
super
some_code
end
Proposed:
before do
some_code
end
before do
another_code
end
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
.
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... 🤔
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)
params do
param :user do
param :email, String
param :password, String
end
end
Change to
if context.request.headers.includes_word?("Upgrade", "Websocket")
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.