Hey, I'm Yehor! ๐
lvivski / start Goto Github PK
View Code? Open in Web Editor NEWSinatra inspired web development framework for Dart
License: MIT License
Sinatra inspired web development framework for Dart
License: MIT License
Hey, I'm Yehor! ๐
Start JWT
- originally developed by George Moschovitis [email protected].
- Dart2 converted by JarrodCColburn at https://github.com/JarrodCColburn.
- tested by Benjamin Jung at https://github.com/bsjung/start_jwt.
Benjamin Jung ([email protected])
The Request object doesn't provide any access to the request payload. It should provide access to HttpRequest#inputStream, so it's possible to get data from a POST.
I think the title is obvious, as is the importance :)
I recently proposed an implementation of HTTPS for the Vane dart web framework, so perhaps if I find some time, I can take a look at start as well. But you guys probably know the code better.
The Vane proposal is here: Scorpiion/vane#19
I've needed WebApp process manager like PM2 for dart.
If it does not exist a similar package, I have to make it for Start web framework.
Benjamin Jung ( [email protected] )
Cookie method of Response
is not able to set more than one cookie per response.
I think header
method is buggy.
header(String name, [value]) {
if (value == null) {
return _response.headers[name];
}
_response.headers.set(name, value);
return this;
}
should be:
header(String name, [value]) {
if (value == null) {
return _response.headers[name];
}
_response.headers.__add__(name, value);
return this;
}
There is no built in for parsing a JSON request body.
I'm new to start web-framework but, I think it is great framework for me because I like the express framework from node.js.
I've tried to use websocket server example in
https://github.com/lvivski/start/blob/master/example/app.dart.
I've tested with my node.js websocket client.
=====================================
#!/bin/env node
const WebSocket = require('ws');
const ip = 'localhost';
const port = 3000;
const url = ws://${ip}:${port}/socket
;
const connection = new WebSocket(url)
// Send message when the connection with the websocket is established
connection.onopen = () => {
let data = {'type' : 'login', 'userName': 'bsjung', 'password' : 'xxxx' };
let msg = JSON.stringify(data);
connection.send(msg);
}
// Print messages from other clients in the client terminal
connection.onmessage = (event) => {
let msg = JSON.parse(event.data);
console.log(msg);
}
// Print Websocket error in the client terminal
connection.onerror = (error) => {
console.log('Error:', error);
}
=====================================
The error is as following.
FINE: 2020-01-27 16:13:10.797449: Server started, listening on 127.0.0.1:3000
Unhandled exception:
type '_HttpRequest' is not a subtype of type 'Request' in type cast
#0 Route.handle (package:start/src/route.dart:34:34)
#1 Server.listen.handle. (package:start/src/server.dart:27:17)
#2 _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
#3 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:338:11)
#4 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:265:7)
#5 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:766:19)
#6 _StreamController._add (dart:async/stream_controller.dart:642:7)
#7 _StreamController.add (dart:async/stream_controller.dart:588:5)
#8 _HttpServer._handleRequest (dart:_http/http_impl.dart:2828:19)
#9 new _HttpConnection. (dart:_http/http_impl.dart:2586:19)
#10 _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
#11 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:338:11)
#12 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:265:7)
#13 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:766:19)
#14 _StreamController._add (dart:async/stream_controller.dart:642:7)
#15 _StreamController.add (dart:async/stream_controller.dart:588:5)
#16 _HttpParser._headersEnd (dart:_http/http_parser.dart:366:19)
#17 _HttpParser._doParse (dart:_http/http_parser.dart:703:15)
#18 _HttpParser._parse (dart:_http/http_parser.dart:320:7)
#19 _HttpParser._onData (dart:_http/http_parser.dart:812:5)
#20 _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
#21 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:338:11)
#22 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:265:7)
#23 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:766:19)
#24 _StreamController._add (dart:async/stream_controller.dart:642:7)
#25 _StreamController.add (dart:async/stream_controller.dart:588:5)
#26 _Socket._onData (dart:io-patch/socket_patch.dart:1831:41)
#27 _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
#28 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:338:11)
#29 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:265:7)
#30 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:766:19)
#31 _StreamController._add (dart:async/stream_controller.dart:642:7)
#32 _StreamController.add (dart:async/stream_controller.dart:588:5)
#33 new _RawSocket. (dart:io-patch/socket_patch.dart:1379:33)
#34 _NativeSocket.issueReadEvent.issue (dart:io-patch/socket_patch.dart:899:14)
#35 _microtaskLoop (dart:async/schedule_microtask.dart:43:21)
#36 _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)
#37 _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:118:13)
#38 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:175:5)
in Request class, input getter should be typed HttpRequest and not Stream
Would be great to be able to gzip all responses.
I just loaded all my files info in Google Drive and send them out.
And I got the error 'String contains invalid characters.';
Uncaught Error: Illegal argument(s): String contains invalid characters.
Stack Trace:
#0 _UnicodeSubsetEncoder.convert (dart:convert/ascii.dart:83)
#1 Codec.encode (dart:convert/codec.dart:22)
#2 _IOSinkImpl.write (dart:io/io_sink.dart:288)
#3 _HttpOutboundMessage.write (dart:io/http_impl.dart:484)
#4 Response.send (package:start/src/response.dart:65:20)
I cloned start, and run the example "start / example / app.dart".
I can see it uses 24M memory from activity monitor (from ios)
Then I visit http://localhost:3000, where I can see the "Start is awesome"
I refreshed the browser quickly, and found the memory it used growing fast, soon became "51M+"
Then I run "purge" from command line, it became "50M"
I'm worried if start/dart has memory leak? Or do I misunderstand something?
Is it possible to get the IP address of the client that has sent a request?
For my project, I'm doing MongoDB integration with Start web framework.
I'll use https://pub.dev/packages/mongo_dart with Start web framework.
I prefer package like mongoose. But, it takes more time for it.
Anyway, If there are any good suggestions, I'll check it.
Benjamin Jung ( [email protected] )
I needed CORS support for my project.
Thus I've made an experimental Start web framework.
All code is at https://github.com/bsjung/start_examples/blob/master/jwt/server/server.dart.
At first, I've added "cors" option at start().
void main() {
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((rec) {
print('${rec.level.name}: ${rec.time}: ${rec.message}');
});
start(port: 3000, cors: true).then((Server app) {
And, I've add addCorsHeaders with options from start().
void addCorsHeaders(HttpResponse response) {
response.headers.add('Access-Control-Allow-Origin', '*');
response.headers.add('Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE');
response.headers.add('Access-Control-Allow-Headers',
'access-control-allow-origin,content-type,x-access-token');
}
Experimental Start web framework is at https://github.com/bsjung/start.
JWT example using CORS options is at https://github.com/bsjung/start_examples/blob/master/jwt/server.
Benjamin Jung ( [email protected] )
I've tested WebSocket v0.4.0.
It works but, it is not compatible with flutter websocket format.
Most websocket client send without name, it is also flutter packages.
Thus, I've made expremental start v0.5.0 on github.
https://github.com/bsjung/start.
And I've made start web frame examples.
https://github.com/bsjung/start_examples.
Benjamin Jung ([email protected])
Does start set the right mime type for static files?
Why using noSuchMethod instead of just defining the methods? (https://github.com/lvivski/start/blob/master/lib/server.dart#L40)
(Sorry for flooding you with issues,.. I'm just going through your code and wondering about a few things)
Very handle when serving lots of static files.
It gives an example of route "/hello/:firstname.:lastname?" and claims it will match "/hello/john" and "/hello/john.doe". While it does match the latter, it is accepting all of 'john.doe' as firstname which is either incorrect or very confusing.
tried example from main project page and after evaluating this
var ws = new WebSocket("ws://localhost:3000/socket");
in Chrome console i've got following on the server side:
0 Socket.on (package:start/src/socket.dart:30:45)
1 main.. (file:///home/tomek/projects/moohub/bin/moohub.dart:33:16)
2 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:191:14)
3 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:141:16)
4 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:57:15)
5 _MapStream._handleData (dart:async/stream_pipe.dart:122:14)
6 _ForwardingStreamSubscription._handleData._handleData (dart:async/stream_pipe.dart:79:24)
7 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:191:14)
8 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:141:16)
9 _SyncStreamController._sendData (dart:async/stream_controller.dart:107:23)
10 _StreamController.add (dart:async/stream_controller.dart:48:16)
11 _WebSocketTransformerImpl.bind.. (websocket_impl.dart:294:70)
12 _ThenFuture._sendValue (dart:async/future_impl.dart:265:24)
13 _FutureImpl._setValue (dart:async/future_impl.dart:149:26)
14 _FutureImpl._setOrChainValue (dart:async/future_impl.dart:239:16)
15 _ThenFuture._sendValue (dart:async/future_impl.dart:271:21)
16 _FutureImpl._setValue (dart:async/future_impl.dart:149:26)
17 _FutureImpl._setOrChainValue (dart:async/future_impl.dart:239:16)
18 _ThenFuture._sendValue (dart:async/future_impl.dart:271:21)
19 _FutureImpl._setValue (dart:async/future_impl.dart:149:26)
20 _CatchErrorFuture._sendValue (dart:async/future_impl.dart:283:14)
21 _FutureImpl._setValue (dart:async/future_impl.dart:149:26)
22 _FutureImpl._setOrChainValue (dart:async/future_impl.dart:239:16)
23 _ThenFuture._sendValue (dart:async/future_impl.dart:271:21)
24 _FutureImpl._setValue (dart:async/future_impl.dart:149:26)
25 _AsyncCompleter._setFutureValue. (dart:async/future_impl.dart:29:23)
26 _asyncRunCallback._asyncRunCallback (dart:async/event_loop.dart:9:15)
27 Timer.Timer. (dart:async-patch/timer_patch.dart:9:15)
Unhandled exception:
type '() => dynamic' is not a subtype of type 'MsgHandler' of 'action'.
0 _throwDelayed. (dart:async/stream_impl.dart:7:5)
1 _asyncRunCallback._asyncRunCallback (dart:async/event_loop.dart:9:15)
2 _asyncRunCallback._asyncRunCallback (dart:async/event_loop.dart:13:7)
3 Timer.Timer. (dart:async-patch/timer_patch.dart:9:15)
4 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:99:28)
5 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:107:7)
6 _Timer._createTimerHandler. (timer_impl.dart:115:23)
7 _ReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:81:92)
Though being able to "route" Socket messages with the data seems useful, by using the entire contents of the data to do the routing it makes passing data associated with the message impossible.
Some refactorings to address this include:
a) Change the routing to work with JSON data, and look for a specific "msg" and "data" attributes of the parsed hash which would be used for routing and message data respectively.
b) Removing "routing" from the Socket and instead expose the raw data for the application to handle?
Thoughts? I can do a PR.
Hi,
Could you please update the pub package with the latest version? There are breaking changes which are already fixed in the repo but aren't present in pub.
I was wondering if it wouldn't be better if start used darts route library to build the routes.
Start provides no pragmatic parameter handling of post request. Therefore I propose the following method for class Request
.
/**
* Method to get post parameters from a [Request] object.
*/
Future<Map<String, String>> getPostParams({ Encoding enc: UTF8 }) {
Completer c = new Completer();
this.input.transform(const AsciiDecoder()).listen((content) {
final postParams = new Map.fromIterable(
content.split("&").map((kvs) => kvs.split("=")),
key: (kv) => Uri.decodeQueryComponent(kv[0], encoding: enc),
value: (kv) => Uri.decodeQueryComponent(kv[1], encoding: enc)
);
c.complete(postParams);
});
return c.future;
}
This would enable to do a pragmatic post parameter handling in start. Like this ...
app.post("/formular").listen((Request req) {
final name = req.getPostParams().then((params) {
final fn = params['first name'];
final ln = params['last name'];
req.response.send(renderForm("$fn $ln"));
});
});
If non valid cookies are set for example like that:
req.response.cookie("name", "for example something with a whitespace");
a call on
req.cookies
will fail like that.
Uncaught Error: HttpException: Failed to parse header value [name=nane; first name=test; last name=nane]
Unhandled exception:
HttpException: Failed to parse header value [name=nane; first name=test; last name=nane]
#0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:677)
#1 _asyncRunCallback (dart:async/schedule_microtask.dart:18)
#2 _asyncRunCallback (dart:async/schedule_microtask.dart:21)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)
Stack Trace:
#0 _HttpHeaders._parseCookies.parseCookieString.expect (http_headers.dart:470)
#1 _HttpHeaders._parseCookies.parseCookieString (http_headers.dart:480)
#2 _HttpHeaders._parseCookies.<anonymous closure> (http_headers.dart:491)
#3 List.forEach (dart:core-patch/growable_array.dart:240)
#4 _HttpHeaders._parseCookies (http_headers.dart:491)
#5 _HttpInboundMessage.cookies (http_impl.dart:74)
#6 Request.cookies (package:start/src/request.dart:22:40)
#7 main.<anonymous closure>.<anonymous closure> (file:///Users/nane/dart/httpserver/bin/start_cookie_handling.dart:13:15)
#8 _rootRunUnary (dart:async/zone.dart:695)
#9 _RootZone.runUnary (dart:async/zone.dart:834)
#10 _BaseZone.runUnaryGuarded (dart:async/zone.dart:546)
#11 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:333)
#12 _DelayedData.perform (dart:async/stream_impl.dart:585)
#13 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:701)
#14 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:661)
#15 _asyncRunCallback (dart:async/schedule_microtask.dart:18)
#16 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)
I propose to provide a Uri.encodeQueryComponent
in the following method of class Response
:
Response cookie(String name, String val, [Map options]) {
var cookie = new Cookie(
Uri.encodeQueryComponent(name),
Uri.encodeQueryComponent(value),
);
final cookieMirror = reflect(cookie);
if (options != null) {
options.forEach((option, value) {
cookieMirror.setField(new Symbol(option), value);
});
}
_response.cookies.add(cookie);
return this;
}
Also a Uri.decodeQueryComponent
should be made in the cookies
getter of HttpRequest
.
For example like this:
List<Cookie> get cookies {
return _request.cookies.map((Cookie c) {
c.name = Uri.decodeQueryComponent(c.name);
c.value = Uri.decodeQueryComponent(c.value);
return c;
});
}
Cookie method causes an exeception when called with no options.
app.get("/formular").listen((Request req) {
req.response.cookie('test', 'example');
req.response.send("something");
});
Above causes exception. The following works:
app.get("/formular").listen((Request req) {
req.response.cookie('test', 'example', {});
req.response.send("something");
});
The stringifyDate()
method of Cookie (https://github.com/lvivski/start/blob/master/lib/src/cookie.dart#L48) gets the weekday wrong by one, and throws an error if it's Sunday. DateTime.weekday
returns a value between 1 and 7, but the method assumes it's between 0 and 6.
There is no code for response.render
I mean a form in HTML:
<form method="post">
<input type="text" name="title" />
<input type="submit" />
</form>
How to get the value of posted title?
In the two socket
classes the message controller is added with the message name and data (stringified) together instead of just the message name. This needs to change to so that it only enters the message from:
_ws.onMessage.listen((e) {
var msg = new Message(e.data);
_messageController.add(msg);
});
To:
_ws.onMessage.listen((e) {
var msg = new Message.fromPacket(e.data);
_messageController.add(msg.name);
});
I think that would work, but you should get what I'm on about. I don't know how I would add a unit test to test this however.
Hi, I am starting to work with Dart.
I try to run the sample from README and get the following message:
i:\project\test>dart server.dart
Unhandled exception:
'file:///i:/project/test/server.dart': Error: line 5 pos 19: type 'View' is not loaded
start(view: new View(), public: 'example/public', port: 3000).then((app) {
^
malformed type used.
#0 main (file:///i:/project/test/server.dart:5:19)
I have found the instruction about compilation of the views:
Don't forget to compile views with bin/compiler.dart (views are precompiled in example).
But it is not clear how to do that. Can you describe the full process of compilation and installation? What should be done to fix this error.
The pub install start
also does not work in windows, it shows the following message:
Could not find a file named "pubspec.yaml" in the directory ....
So I have created the following pubspec.yaml file to make it work:
name: my_app
dependencies:
start: any
and then I run the following command:
pub install
With a normal HttpServer you can transform a request into a websocket like this.
WebSocketTransformer.upgrade(request).then((WebSocket websocket) {
onWebSocketConnected(websocket);
websocket.listen((data){
onWebSocketDataReceived(websocket,data);
},onDone:(){
onWebSocketClosed(websocket);
});
});
Notice that I can still access the websocket during the closing. This allows for handling of temp data (session-ish things) to be cleared once the socket closes. I would really like to use start for its clean semantics and want to know how to get this information properly within start's framework.
I've noticed that you first import server
which then imports all other parts of start
, like response.dart
.
This means that I can't just use the types in my app. Why don't you include all the assets with part "src/response.dart";
?
Clients can't include the Start library as it uses parts of the Dart stdlib not accessable in the web browser. That said, it would be good if there was some common code which allowed WebSocket messages to be consistently serialized and de-serialized between the client and server.
I'm going to work on building this external pub, then including it in the list of Start's dependencies but obviously wanted to hear your thoughts before I started work.
The http_server package provides static file serving, virtual host support, HTTP range, and more. What do you think about start delegating to http_server for file and directory serving?
A clean install of the example application crashes upon first GET request with an error. No response is returned from the Start HTTP server.
Full error message can be found in this gist.
Dart Editor also reports:
"HttpResponse" has no method named "write" - response.dart [Line 60]
`"HttpResponse" has no method named "write" - response.dart [Line 64]``
As such the example application is broken.
I've tested the JSON request for my project.
This is my dart client is at
https://github.com/bsjung/start_examples/blob/master/jwt/server/client.dart.
The header is set to {'Content-Type': "application/json"}.
But, the most client software appends to UTF encoding into HTTP header : [application/json; charset=utf-8].
The isMime() loose default is false.
Thus I think the loose default option should be set the true for client software.
16 bool isMime(String type, {loose: false}) =>
17 _request.headers[HttpHeaders.contentTypeHeader]
18 .where((value) => loose ? value.contains(type) : value == type)
19 .isNotEmpty;
Benjamin Jung ( [email protected] )
The following code fails to match a URL ccontaining path '/hello/file.txt'
, e.g. http://localhost/hello/file.txt
:
server.get('/hello/:filename').listen((request) {
print('match!');
});
Only when removing the period (.) from the URL does the placeholder (:filename) match the path segment; despite periods being valid characters in URL path segments.
It would be great if the start placeholders can match all valid path segment character.
Hello. I have a link to the packages folder in my web folder. I am not sure where pub get actually stores packages, but I don't think a static web serve actually serves these packages. TLDR Packages aren't getting served correctly.
The return type should be Stream for delete.
Just like the get, post method.
I think it'd be better to replace noSuchMethod with explicit method declarations of get,post, etc.. But even if there is reason to keep it, the error is super confusing. For instance:
get('/lala', (req, res){
Hello
});
Will raise "No such HTTP method", because "Hello" isn't in the list of http methods.
Hi
Iam getting an Error when calling request.cookies in 'package:start/src/request.dart'
Error:
Unhandled exception:
type 'MappedListIterable' is not a subtype of type 'List<Cookie' of 'function result'.
This is extremely cool, is there any chance it can be used with Chrome? That is to be able to run web server in chrome?
A View
is totally optional, from what I can tell. It's under-documented in the README. Could you either explain what it's used for, and why someone would care, or split the README into the concepts that don't require a View and those that do?
I'm hoping to make Start even easier to learn and use.
Thanks!
Request
class of start does not provide direct access to session data. Therefore accessing session data is unnecessary verbose due to the fact that we have to use input
property of Request
.
req.input.session['key'] = 'value';
It would be more efficient to do it this way:
req.session['key'] = 'value';
Therefore I propose to introduce the following getter to Request
class to overcome unnecessary verbosity.
HttpSession get session => _request.session;
I've already commented on WebSocket v0.4.0 at #73.
But, I've changed the onMessage() into onMessage (stream object).
app.ws('/socket').listen((socket) {
socket.onMessage.listen((data) {
print('data: $data');
socket.send(data);
});
socket.onOpen.listen((ws) {
print('new socket opened');
});
socket.onClose.listen((ws) {
print('socket has been closed');
});
});
Thus, I've made expremental start v0.5.0 on github.
https://github.com/bsjung/start.
And I've made start web frame examples.
https://github.com/bsjung/start_examples.
Benjamin Jung ([email protected])
Just FYI, request.params is empty until request.param(url) is specified first..
I am thinking about start for use in my next simple project. Is it ready for production?
Could you please provide an example how to use async operations with Start?
I tried this, but it didn't work:
app.get('/:name', (req, res) {
new File(req.param('name')).readAsString().then((content) {
res.render('view', {'content': content});
});
});
It seems, the response stream is closed before the Future's function is called.
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.