├── .gitignore
├── README.md
├── integrated
├── 01_advanced_auth
│ ├── README.md
│ ├── bin
│ │ ├── package.json
│ │ ├── start_server.sh
│ │ └── view
│ │ │ ├── home
│ │ │ └── main.html
│ │ │ └── layout.html
│ ├── server.hxml
│ ├── src
│ │ ├── Server.hx
│ │ ├── Tasks.hx
│ │ ├── api
│ │ │ └── AuthApi.hx
│ │ ├── auth
│ │ │ ├── Auth.hx
│ │ │ ├── AuthMiddleware.hx
│ │ │ └── User.hx
│ │ ├── controller
│ │ │ └── HomeController.hx
│ │ └── model
│ │ │ ├── Managers.hx
│ │ │ └── User.hx
│ └── tasks.hxml
└── 02_reactjs
│ ├── README.md
│ ├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── empty.html
│ │ ├── home
│ │ ├── about.html
│ │ └── main.html
│ │ └── layout.html
│ ├── client.hxml
│ ├── server.hxml
│ └── src
│ ├── Client.hx
│ ├── Server.hx
│ ├── controller
│ ├── HomeController.hx
│ └── ReactResult.hx
│ └── react
│ └── App.hx
└── minimal
├── 01_static_results
├── README.md
├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── home
│ │ ├── async.html
│ │ └── main.html
│ │ └── layout.html
├── server.hxml
└── src
│ ├── Server.hx
│ └── controller
│ └── HomeController.hx
├── 02_dynamic_results
├── README.md
├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── home
│ │ └── main.html
│ │ └── layout.html
├── server.hxml
└── src
│ ├── Server.hx
│ └── controller
│ └── HomeController.hx
├── 03_file_upload
├── README.md
├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── home
│ │ └── main.html
│ │ └── layout.html
├── server.hxml
└── src
│ ├── Server.hx
│ └── controller
│ └── HomeController.hx
├── 04_client_app
├── README.md
├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── home
│ │ ├── about.html
│ │ └── main.html
│ │ └── layout.html
├── client.hxml
├── server.hxml
└── src
│ ├── Client.hx
│ ├── Server.hx
│ └── controller
│ └── HomeController.hx
├── 05_api
├── README.md
├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── home
│ │ └── main.html
│ │ └── layout.html
├── server.hxml
└── src
│ ├── Server.hx
│ ├── api
│ ├── AnotherApi.hx
│ └── FileApi.hx
│ └── controller
│ └── HomeController.hx
├── 06_basic_auth
├── README.md
├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── home
│ │ └── main.html
│ │ └── layout.html
├── server.hxml
└── src
│ ├── Server.hx
│ ├── api
│ └── AuthApi.hx
│ ├── auth
│ ├── Auth.hx
│ └── User.hx
│ └── controller
│ └── HomeController.hx
├── 07_remoting
├── README.md
├── bin
│ ├── package.json
│ ├── start_server.sh
│ └── view
│ │ ├── home
│ │ ├── about.html
│ │ └── main.html
│ │ └── layout.html
├── client.hxml
├── server.hxml
└── src
│ ├── Client.hx
│ ├── Server.hx
│ ├── api
│ ├── ApiContext.hx
│ └── TestApi.hx
│ └── controller
│ └── HomeController.hx
├── 08_tasks
├── README.md
├── bin
│ ├── package.json
│ └── start_server.sh
├── src
│ ├── Tasks.hx
│ └── api
│ │ └── FileApi.hx
└── tasks.hxml
└── 09_middleware
└── .wip
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | uf-content/
3 | npm-debug.log
4 | server.js*
5 | client.js*
6 | tasks.js*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **Warning:** Ufront is not actively maintained now (as at Mar 2018). I highly recommend you to use [tink_web](https://github.com/haxetink/tink_web) instead
2 |
3 | # Ufront Guide for NodeJS target
4 |
5 | This is a collection of guides for the NodeJS target of Ufront ([website](http://ufront.net), [repo](https://github.com/ufront)).
6 |
7 | ## Overview
8 |
9 | #### What is Ufront?
10 |
11 | From Ufront repo:
12 |
13 | > Ufront is a client/server MVC web framework for Haxe. It allows you to share models, views and controllers between both server-side and client-side code. Client side, your app will run as a fast single-page-app. But everything can still work server-side - which makes for fast first page loads, great SEO, and a good fallback for old browsers.
14 |
15 | #### Why NodeJS only?
16 |
17 | Actually, Ufront does support the neko and php target (and they work very well).
18 | But according to my practical experience, the amount of libraries of nodejs (from npm) is much much more than what you can find for neko or php.
19 | That makes development much easier and faster. (p.s. for neko, you are basically limited to only use Haxe libraries). So, let's focus on NodeJS!
20 |
21 | #### Compile for neko/php (if you insist)
22 |
23 | Since Ufront does support neko and php, so the guides here should also apply to these two targets, with slight modification. The main difference is the entry point.
24 | In nodejs, we call `listen(port)` to start the server, and in neko/php we call `executeRequest()`.
25 | So, by changing this call you should be able to compile most of the examples in this guide.
26 |
27 | #### Repo structure
28 |
29 | The `minimal` folder contains a set of minimal examples.
30 | The scopes of these minimal examples are very confined, so readers can easily
31 | identify the minimum code required for a certain feature.
32 |
33 | The `integrated` folder contains a set of more-real-world examples that integrates
34 | several features. These examples are usually more complex and maybe a little bit
35 | harder to understand, make sure you have gone through the minimal examples first,
36 | to gain a brief understanding of the individual features.
37 |
38 | #### Feedback
39 |
40 | Please feel free to open issues/PR for:
41 | - Example request
42 | - Bug report / bug fixes
43 | - Any other general feedback / questions
44 |
45 | Or you can join our chatroom: https://gitter.im/ufront/ufront
46 |
47 |
48 | ## Usage
49 |
50 | The following are the steps to build and run the examples.
51 |
52 | ### Prepare
53 |
54 | ##### Haxe
55 |
56 | Install the required libraries.
57 |
58 | ```
59 | haxelib git ufront-mvc https://github.com/ufront/ufront-mvc
60 | haxelib install express
61 | haxelib install hxnodejs
62 | haxelib install pushstate
63 | ```
64 |
65 | ##### NodeJS
66 |
67 | 0. You need to install NodeJS on your machine, please refer to the official NodeJS guide ([website](https://nodejs.org)).
68 | 0. Install the "nodemon" package, `npm install -g nodemon`.
69 |
70 | ### Build
71 |
72 | Navigate to each example folder, then build the hxml files there, for example:
73 |
74 | ```
75 | cd minimal/01_static_results
76 | haxe server.hxml
77 | ```
78 |
79 | If there is a client, compile it as well:
80 | ```
81 | haxe client.hxml
82 | ```
83 |
84 | ### Run
85 |
86 | By default: Ufront requires the following node packages:
87 | - compression
88 | - body-parser
89 | - cookie-parser
90 | - express
91 | - multer
92 |
93 | The dependencies have been specified in the `package.json` file in each examples, so simply navigate to the `bin` folder, install the node dependencies by `npm install`.
94 |
95 | ```
96 | cd bin
97 | npm install
98 | ```
99 |
100 | Then start the server:
101 |
102 | ```
103 | npm start
104 | ```
105 |
106 | ### View
107 |
108 | Open your browser and navigate to `localhost:2987`
109 |
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/README.md:
--------------------------------------------------------------------------------
1 | # Integrated example: Advanced Authentication
2 |
3 | In this example, we will set up a server that will handle login, check credentials with database and persist login status across requests.
4 |
5 | ## Overview
6 |
7 | #### Database
8 |
9 | We will use MongoDB as our database backend in this example.
10 | Haxe's SPOD is a good library but it is not (yet?) supported on nodejs.
11 | For simplicity we will use the mongoose library as our database driver.
12 |
13 | #### Persistent Login Status
14 |
15 | We will use Json Web Tokens to persist login status.
16 |
17 |
18 | ## Prepare
19 |
20 | #### Install MongoDB
21 |
22 | Please refer to MongoDB official guide.
23 | To test if MongoDB is installed successfully, run the following in terminal:
24 | ```bash
25 | mongo
26 | ```
27 |
28 | If you can enter the mongo shell then you are done.
29 |
30 |
31 | #### More Haxe Dependencies
32 |
33 | In addition to the libraries listed in the main README, we need js-kit and jsonwebtoken:
34 | ```bash
35 | haxelib git js-kit https://github.com/clemos/haxe-js-kit
36 | haxelib install hxnodejs-jsonwebtoken
37 | ```
38 |
39 |
40 | ## Build
41 |
42 | Build server.hxml and tasks.hxml
43 |
44 | ```bash
45 | haxe server.hxml && haxe tasks.hxml
46 | ```
47 |
48 | ## Run
49 |
50 | ```bash
51 | # cd to bin/ folder
52 | cd bin
53 | # install node dependencies
54 | npm install
55 | # create an user in database
56 | node tasks.js --create-user
57 | # start the web server
58 | npm start
59 | ```
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "01_advanced_auth",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0",
11 | "mongoose": "^4.3.3",
12 | "jsonwebtoken": "^5.5.4"
13 | },
14 | "scripts": {
15 | "start": "./start_server.sh"
16 | }
17 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 | ::if isLoggedIn::
2 |
3 | You are logged in. Now try refreshing the page, it keeps you logged in.
4 |
5 |
8 | ::else::
9 |
10 | You are NOT logged in.
11 |
12 | Log in here: (username: ufront, password: ufrontpw)
13 |
18 | ::end::
19 |
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 | ::viewContent::
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # jsonwebtoken
11 | -lib hxnodejs-jsonwebtoken
12 |
13 | # js-kit (for the mongoose externs)
14 | -lib js-kit
15 |
16 | # we are compiling for the server
17 | -D server
18 |
19 | # usual hxml things...
20 | -cp src
21 | -main Server
22 | -js bin/server.js
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import auth.Auth;
4 | import auth.AuthMiddleware;
5 | import controller.HomeController;
6 | import model.Managers;
7 |
8 | using ufront.MVC;
9 |
10 | class Server
11 | {
12 | static function main()
13 | {
14 | var ufrontApp = new UfrontApplication({
15 | indexController: HomeController,
16 | defaultLayout: "layout.html",
17 | authImplementation: Auth, // specify our auth implementation
18 | requestMiddleware: [new AuthMiddleware()], // our auth middleware will check, when a request arrives, for a login access token
19 | });
20 |
21 | // init database
22 | Managers.init(ufrontApp.injector);
23 |
24 | // listen for incoming connection at this port number
25 | ufrontApp.listen(2987);
26 | }
27 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/Tasks.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import api.*;
4 | import ufront.tasks.UFTaskSet;
5 | import model.User;
6 | import model.Managers;
7 |
8 | using ufront.MVC;
9 | using tink.CoreApi;
10 |
11 | class Tasks extends UFTaskSet
12 | {
13 | static function main()
14 | {
15 | var tasks = new Tasks();
16 |
17 | // Inject our content directory in case we need to write to it.
18 | tasks.injector.map(String, "contentDirectory").toValue("../uf-content/");
19 |
20 | // init database
21 | Managers.init(tasks.injector);
22 |
23 | // Inject all our APIs.
24 | for (api in CompileTime.getAllClasses(UFApi)) tasks.injector.mapRuntimeTypeOf(api).toSingleton(api);
25 |
26 | // Use CLI logging, which prints both to a log file and to the CLI output.
27 | tasks.useCLILogging("logs/tasks.log");
28 |
29 | // Execute the task runner
30 | var args = Sys.args();
31 | tasks.execute(args);
32 |
33 | }
34 |
35 | @inject @:skip
36 | public var userManager:UserManager;
37 |
38 | /**
39 | Create a user in database
40 |
41 | Usage: node tasks.js --create-user
42 | **/
43 | public function createUser()
44 | {
45 | userManager.create({username: 'ufront', password: 'ufrontpw'}, function(err, user) {
46 | if(err != null) trace(err);
47 | Sys.exit(0);
48 | });
49 | }
50 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/api/AuthApi.hx:
--------------------------------------------------------------------------------
1 | package api;
2 |
3 | import auth.Auth;
4 | import model.User;
5 | import js.npm.JsonWebToken;
6 |
7 | using ufront.MVC;
8 | using tink.CoreApi;
9 |
10 | class AuthApi extends UFApi
11 | {
12 | static inline var SECRET = @:privateAccess auth.AuthMiddleware.SECRET;
13 |
14 | // inject our database manager
15 | @inject
16 | public var userManager:UserManager;
17 |
18 | // inject the http context so that we can write a cookie later
19 | @inject
20 | public var context:HttpContext;
21 |
22 | public function login(username:String, password:String):Surprise
23 | {
24 | // database call is async, we use a future to handle it
25 | var trigger = Future.trigger();
26 |
27 | // find the user in database
28 | userManager.findOne({username: username}, function(err, user) trigger.trigger(err == null ? Success(user) : Failure(Error.withData('Mongo Error', err))));
29 |
30 | // check the credentials when the user data is fetched from database
31 | return trigger.asFuture() >>
32 | function(user:User)
33 | {
34 | // invalid username
35 | if(user == null) return new Error("User not found").asBadSurprise();
36 |
37 | // incorrect password
38 | if(password != user.password) return new Error("Incorrect password").asBadSurprise();
39 |
40 | // cast the auth interface into our implementation
41 | var authImplementation = Std.instance(auth, Auth);
42 |
43 | // initialize our auth handler
44 | authImplementation.init(username);
45 |
46 | // let the browser store the json web token as cookie
47 | // so that in the next request we can pick it up in the middleware,
48 | // in order to persist the login status
49 | var token = JsonWebToken.sign({username: username}, SECRET, {expiresIn: '30m'});
50 | context.response.setCookie(new HttpCookie("access_token", token, Date.fromTime(Date.now().getTime() + 30 * 60 * 1000), null, "/"));
51 | return SurpriseTools.success();
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/auth/Auth.hx:
--------------------------------------------------------------------------------
1 | package auth;
2 |
3 | using ufront.MVC;
4 |
5 | class Auth implements UFAuthHandler
6 | {
7 | // required by the interface
8 | public var currentUser(get, never):UFAuthUser;
9 |
10 | // actually stores the user;
11 | var _currentUser:User;
12 |
13 | // initialize our auth handler with an user id,
14 | // this user id should be the result of some authentication (e.g. username/password)
15 | public function init(payload:Dynamic)
16 | {
17 | _currentUser = new User(payload.userId);
18 | }
19 |
20 | // required by the interface
21 | public function hasPermission (permission:EnumValue):Bool
22 | {
23 | return isLoggedIn() && _currentUser.can(permission);
24 | }
25 |
26 | // required by the interface
27 | public function hasPermissions (permissions:Iterable):Bool
28 | {
29 | return isLoggedIn() && _currentUser.can(permissions);
30 | }
31 |
32 | // required by the interface
33 | public function isLoggedIn():Bool
34 | {
35 | return _currentUser != null;
36 | }
37 |
38 | // required by the interface
39 | public function isLoggedInAs(user:UFAuthUser):Bool
40 | {
41 | return isLoggedIn() && _currentUser.userID == user.userID;
42 | }
43 |
44 | // required by the interface
45 | public function requireLogin ():Void
46 | {
47 | if(!isLoggedIn()) throw HttpError.authError(ANotLoggedIn);
48 | }
49 |
50 | // required by the interface
51 | public function requireLoginAs (user:UFAuthUser):Void
52 | {
53 | if(!isLoggedInAs(user)) throw HttpError.authError(ANotLoggedInAs(user));
54 | }
55 |
56 | // required by the interface
57 | public function requirePermission (permission:EnumValue):Void
58 | {
59 | if(!hasPermission(permission)) throw HttpError.authError(ANoPermission(permission));
60 | }
61 |
62 | // required by the interface
63 | public function requirePermissions (permissions:Iterable):Void
64 | {
65 | for(permission in permissions) if(!hasPermission(permission)) throw HttpError.authError(ANoPermission(permission));
66 | }
67 |
68 | // required by the interface
69 | public function toString ():String
70 | {
71 | return "Auth";
72 | }
73 |
74 | function get_currentUser() return _currentUser;
75 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/auth/AuthMiddleware.hx:
--------------------------------------------------------------------------------
1 | package auth;
2 |
3 | import haxe.Json;
4 | import js.npm.JsonWebToken;
5 | import auth.Auth;
6 |
7 | using ufront.MVC;
8 | using tink.CoreApi;
9 |
10 | class AuthMiddleware implements UFRequestMiddleware
11 | {
12 | #if server // make sure our secret is not leaked to client
13 | static inline var SECRET = 'our-jwt-secret';
14 | #end
15 |
16 | public function new() {}
17 |
18 | /**
19 | This function will be run when a request arrives, before it is handled by controllers.
20 | We look for a access token in the request and use it to identify the user.
21 | If an user is identified we initiate our auth handler, so that later when a controller
22 | handles this request, it can use `context.auth` to find out the auth-related information.
23 | **/
24 | public function requestIn( ctx:HttpContext ):Surprise
25 | {
26 | // try to fetch the access token from cookies or post/get params
27 | var token = ctx.request.params['access_token'];
28 |
29 | if (token != null)
30 | {
31 | // try to decode the token
32 | var payload =
33 | try
34 | JsonWebToken.verify(token, SECRET)
35 | catch(e:js.Error)
36 | // there are some problem with the token, let's skip the following process
37 | return SurpriseTools.success();
38 |
39 | // refresh the token to make it not to expire in the next 30 minutes
40 | // this is done through
41 | // - setting the expiry of the token (encoded in jwt), and;
42 | // - setting the expiry of the cookie
43 | var refreshedToken = JsonWebToken.sign(payload, SECRET, {expiresIn: '30m'});
44 | ctx.response.setCookie(new HttpCookie("access_token", refreshedToken, Date.fromTime(Date.now().getTime() + 30 * 60 * 1000), null, "/"));
45 |
46 | // init our auth handler
47 | var auth:Auth = cast ctx.auth;
48 | auth.init(payload.username);
49 | }
50 |
51 | return SurpriseTools.success();
52 | }
53 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/auth/User.hx:
--------------------------------------------------------------------------------
1 | package auth;
2 |
3 | using ufront.MVC;
4 |
5 | class User implements UFAuthUser
6 | {
7 | // required by the interface
8 | public var userID(get, never):String;
9 |
10 | // actually stores the user id
11 | var userId:String;
12 |
13 | public function new(userId:String)
14 | {
15 | this.userId = userId;
16 | }
17 |
18 | // required by the interface
19 | public function can(?permission:EnumValue, ?permissions:Iterable):Bool
20 | {
21 | // for minimal demonstration purpose, here simply returns true to allow all permissions.
22 | // in reality, you should implement your own logic (e.g. query database, etc)
23 | // to determine if an user is "can" do the specified permissions
24 | return true;
25 | }
26 |
27 | function get_userID() return userId;
28 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | import api.AuthApi;
4 |
5 | using ufront.MVC;
6 |
7 | class HomeController extends Controller
8 | {
9 | @inject
10 | public var authApi:AuthApi;
11 |
12 | @:route(GET, "/")
13 | public function main()
14 | {
15 | var isLoggedIn = context.auth.isLoggedIn();
16 |
17 | return new ViewResult({
18 | title: "Ufront NodeJS Guide",
19 | isLoggedIn: isLoggedIn,
20 | });
21 | }
22 |
23 | @:route(POST, "/login")
24 | public function login(args:{username:String, password:String})
25 | {
26 | // try to login and redirect back to home page if success
27 | return authApi.login(args.username, args.password) >>
28 | function(_) return new RedirectResult('/');
29 | }
30 |
31 | @:route(POST, "/logout")
32 | public function logout()
33 | {
34 | // clear the access_token cookie in user's browser
35 | context.response.setCookie(new HttpCookie("access_token", '', Date.now(), null, "/"));
36 |
37 | // redirect back to home page
38 | return new RedirectResult('/');
39 | }
40 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/model/Managers.hx:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | import js.npm.mongoose.Mongoose;
4 | import model.User;
5 |
6 | class Managers
7 | {
8 | public static function init(injector:minject.Injector)
9 | {
10 | // connect to mongodb
11 | var mongoose = new Mongoose();
12 | mongoose.connect("mongodb://localhost/01_advanced_auth");
13 |
14 | // init our database manager
15 | var userManager = UserManager.build(mongoose, "User");
16 |
17 | // inject our user manager
18 | injector.map(UserManager).toValue(userManager);
19 | }
20 | }
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/src/model/User.hx:
--------------------------------------------------------------------------------
1 | package model;
2 |
3 | // schema for our User model in database
4 | typedef UserData =
5 | {
6 | username:String,
7 | password:String,
8 | }
9 |
10 | // collection manager
11 | class UserManager extends js.npm.mongoose.macro.Manager {}
12 |
13 | @:schemaOptions({
14 | autoIndex: true
15 | })
16 | class User extends js.npm.mongoose.macro.Model {}
--------------------------------------------------------------------------------
/integrated/01_advanced_auth/tasks.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # the uftasks library
5 | -lib ufront-uftasks
6 |
7 | # we need hxnodejs because we are targeting nodejs
8 | -lib hxnodejs
9 |
10 | # ufront uses expressjs behind the hood
11 | -lib express
12 |
13 | # js-kit (for the mongoose externs)
14 | -lib js-kit
15 |
16 | # we are compiling for the server
17 | -D server
18 |
19 | # usual hxml things...
20 | -cp src
21 | -main Tasks
22 | -js bin/tasks.js
--------------------------------------------------------------------------------
/integrated/02_reactjs/README.md:
--------------------------------------------------------------------------------
1 | # Integrated example: Using React with Ufront
2 |
3 | In this example, we will set up a client application that will use React (http://reactjs.org/).
4 |
5 | ## Prepare
6 |
7 | #### More Haxe Dependencies
8 |
9 | In addition to the libraries listed in the main README, we need the react library:
10 | ```bash
11 | haxelib git react https://github.com/massiveinteractive/haxe-react
12 | ```
--------------------------------------------------------------------------------
/integrated/02_reactjs/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "02_reactjs",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/integrated/02_reactjs/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/integrated/02_reactjs/bin/view/empty.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinresol/ufront-nodejs-guide/a4b92bfd7d8257388ab698fa90af4643dbb8ef7b/integrated/02_reactjs/bin/view/empty.html
--------------------------------------------------------------------------------
/integrated/02_reactjs/bin/view/home/about.html:
--------------------------------------------------------------------------------
1 |
2 | About Page...
3 |
--------------------------------------------------------------------------------
/integrated/02_reactjs/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 |
2 | ::message::
3 |
--------------------------------------------------------------------------------
/integrated/02_reactjs/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ::viewContent::
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/integrated/02_reactjs/client.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # use the pushstate lib, which handles the browser history for us
5 | -lib pushstate
6 |
7 | # the haxe-react library
8 | -lib react
9 |
10 | # we are compiling for the client
11 | -D client
12 |
13 | # we are not going to use js require
14 | -D react_global
15 |
16 | # usual hxml things...
17 | -cp src
18 | -main Client
19 | -js bin/client.js
--------------------------------------------------------------------------------
/integrated/02_reactjs/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/integrated/02_reactjs/src/Client.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | import minject.Injector;
5 | import react.App;
6 | using ufront.MVC;
7 |
8 | class Client
9 | {
10 | public static var reactApp:App;
11 | public static var ufrontApp:ClientJsApplication;
12 | public static var injector:Injector;
13 |
14 | static function main()
15 | {
16 | ufrontApp = new ClientJsApplication({
17 | indexController: HomeController,
18 | defaultLayout: "layout.html",
19 | });
20 |
21 | // Listen to any history changes using PushState, and process each request.
22 | ufrontApp.listen();
23 |
24 | // trigger the initial render
25 | ufrontApp.executeRequest();
26 | }
27 | }
--------------------------------------------------------------------------------
/integrated/02_reactjs/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Server
7 | {
8 | static function main()
9 | {
10 | var ufrontApp = new UfrontApplication({
11 | indexController: HomeController, // all incoming requests will be handled by this controller
12 | defaultLayout: "layout.html", // use this file as the default layout for a ViewResult
13 | });
14 |
15 | // listen for incoming connection at this port number
16 | ufrontApp.listen(2987);
17 | }
18 | }
--------------------------------------------------------------------------------
/integrated/02_reactjs/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | #if client
4 | import api.react.ReactMacro.jsx;
5 | #end
6 |
7 | using ufront.MVC;
8 |
9 | class HomeController extends Controller
10 | {
11 | @post
12 | public function postInject()
13 | {
14 | ViewResult.globalValues['title'] = "Ufront with React";
15 | }
16 |
17 | /**
18 | Serves a main page.
19 | On server-side it renders nothing but only send an almost-empty layout html plus the client js app to browser.
20 | Then on client-side it will render the react components.
21 | **/
22 | @:route(GET, "/")
23 | public function main()
24 | {
25 | return new ReactResult(jsx('
26 |
30 | '));
31 | }
32 |
33 | /**
34 | Serves another page
35 | **/
36 | @:route(GET, "/about")
37 | public function about()
38 | {
39 | return new ReactResult(jsx('
40 |
44 | '));
45 | }
46 |
47 |
48 | #if server
49 | // we are not going to do anything with jsx on server-side
50 | public static inline function jsx(_) return null;
51 | #end
52 | }
53 |
--------------------------------------------------------------------------------
/integrated/02_reactjs/src/controller/ReactResult.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | using ufront.MVC;
4 | using tink.CoreApi;
5 |
6 | #if client
7 |
8 | import api.react.ReactMacro.jsx;
9 | import api.react.ReactDOM;
10 | import react.App;
11 |
12 | /**
13 | We need a way to trigger a re-render in our react app.
14 | Here we use a PartialViewResult with ClientAction to do that.
15 | **/
16 | abstract ReactResult(AddClientActionResult) to AddClientActionResult
17 | {
18 | public function new(content:Dynamic)
19 | this = new PartialViewResult({}, "../empty.html").addClientAction(RenderPageAction, {content: content});
20 | }
21 |
22 | class RenderPageAction extends UFClientAction
23 | {
24 | override public function execute(httpContext:HttpContext, ?data:RenderPageActionData)
25 | {
26 | // store the current injector for use in react components
27 | Client.injector = httpContext.injector;
28 |
29 | // create and mount the react app if not yet done so
30 | if(Client.reactApp == null) Client.reactApp = cast ReactDOM.render(jsx(''), js.Browser.document.getElementById("app"));
31 |
32 | // set the contents
33 | Client.reactApp.setState({content: data.content});
34 | }
35 | }
36 |
37 | typedef RenderPageActionData =
38 | {
39 | content:Dynamic,
40 | }
41 |
42 | #else
43 |
44 | // on server-side it is just a plain view result
45 | abstract ReactResult(PartialViewResult) to PartialViewResult
46 | {
47 | public inline function new(_)
48 | this = new PartialViewResult({}, "../empty.html");
49 | }
50 |
51 | #end
--------------------------------------------------------------------------------
/integrated/02_reactjs/src/react/App.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import api.react.ReactMacro.jsx;
4 | import api.react.ReactComponent;
5 | import js.html.*;
6 |
7 | using ufront.MVC;
8 | using tink.CoreApi;
9 |
10 | class App extends ReactComponentOfState<{?content:ReactComponent}>
11 | {
12 | @inject
13 | public var ctx:HttpContext;
14 |
15 | public function new(props)
16 | {
17 | super(props);
18 |
19 | Client.injector.injectInto(this); // get our injections
20 |
21 | // initialize a state
22 | state = {}
23 | }
24 |
25 | override function render()
26 | {
27 | // just a proof-of-concept that you can really get the injected variables
28 | // basically you can inject anything here, e.g. remoting API, etc
29 | trace(ctx.auth.isLoggedIn());
30 |
31 | return jsx('
32 |
33 | {state.content}
34 |
35 | Note that when you click on the link above, the page is re-rendered by js (react),
36 | so that it is a single-page-app (SPA). But when you enter the URL directly
37 | (e.g. http://localhost:2987/about), you will still get the same result, because the
38 | the page is prepared on client-side (by ufrontApp.executeRequest() in Client.hx)
39 |
40 |
41 | ');
42 | }
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/minimal/01_static_results/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: Static Results
2 |
3 | In this example, we will set up a minimal server that will serve static results (e.g. static page, static json, static file, etc).
--------------------------------------------------------------------------------
/minimal/01_static_results/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "01_static_results",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/01_static_results/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/01_static_results/bin/view/home/async.html:
--------------------------------------------------------------------------------
1 |
2 | ::message::
3 |
4 | (async.html)
--------------------------------------------------------------------------------
/minimal/01_static_results/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 |
2 | ::message::
3 |
--------------------------------------------------------------------------------
/minimal/01_static_results/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 |
11 | View Result
12 | Json Result
13 | Redirect Result
14 | File Result
15 | Async View Result
16 |
17 | ::viewContent::
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/minimal/01_static_results/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/minimal/01_static_results/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Server
7 | {
8 | static function main()
9 | {
10 | var ufrontApp = new UfrontApplication({
11 | indexController: HomeController, // all incoming requests will be handled by this controller
12 | defaultLayout: "layout.html", // use this file as the default layout for a ViewResult
13 | });
14 |
15 | // listen for incoming connection at this port number
16 | ufrontApp.listen(2987);
17 | }
18 | }
--------------------------------------------------------------------------------
/minimal/01_static_results/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | import haxe.Timer;
4 |
5 | using ufront.MVC;
6 | using tink.CoreApi;
7 |
8 | class HomeController extends Controller
9 | {
10 | /**
11 | Serves a ViewResult, which reads a template file (usualy html)
12 | and fill in the variable values provided
13 | **/
14 | @:route(GET, "/")
15 | public function main()
16 | {
17 | return new ViewResult({
18 | title: "Ufront NodeJS Guide",
19 | message:"Welcome to Ufront!"
20 | });
21 | }
22 |
23 | /**
24 | Serves a JsonResult, the Content-Type response header will be set to "application/json"
25 | **/
26 | @:route(GET, "/json")
27 | public function json()
28 | {
29 | return new JsonResult({
30 | title: "Ufront NodeJS Guide",
31 | message:"Welcome to Ufront!"
32 | });
33 | }
34 |
35 | /**
36 | Serves a RedirectResult, which redirect the client to another path
37 | **/
38 | @:route(GET, "/redirect")
39 | public function redirect()
40 | {
41 | return new RedirectResult("/");
42 | }
43 |
44 | /**
45 | Serves a FilePathResult, which read a file at the path specified and return it.
46 | One can optionally specify the mime type and download file name.
47 | **/
48 | @:route(GET, "/file")
49 | public function file()
50 | {
51 | return new FilePathResult("package.json");
52 | }
53 |
54 | /**
55 | Advanced:
56 | The above examples return results in a sync manner. However, in many cases,
57 | (especially on nodejs) server cannot return immediately due to heavy tasks,
58 | network latency, etc. So, in order to return an async result, we can return a
59 | Future or Surprise of a result. To learn more about Future/Surprise, please
60 | read the doc of the tink_core library.
61 | **/
62 | @:route(GET, "/async")
63 | public function async()
64 | {
65 | // simulate an async call
66 | var trigger = Future.trigger();
67 | Timer.delay(trigger.trigger.bind("Welcome to Ufront! (Async)"), 2500); // delay 2.5 seconds
68 |
69 | // return the async result
70 | return trigger.asFuture() >>
71 | function(message:String) return new ViewResult({
72 | title: "Ufront NodeJS Guide",
73 | message: message,
74 | });
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: Dynamic Results
2 |
3 | In this example, we will set up a minimal server that will handle GET/POST parameters
4 |
5 | ### Prerequisites
6 |
7 | - [Static Results](../01_static_results)
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "02_dynamic_results",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 | GET
2 |
7 |
8 | POST
9 |
14 |
15 | PATH
16 | Go
17 |
18 | MIXED
19 |
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 | ::viewContent::
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Server
7 | {
8 | static function main()
9 | {
10 | var ufrontApp = new UfrontApplication({
11 | indexController: HomeController, // all incoming requests will be handled by this controller
12 | defaultLayout: "layout.html", // use this file as the default layout for a ViewResult
13 | });
14 |
15 | // listen for incoming connection at this port number
16 | ufrontApp.listen(2987);
17 | }
18 | }
--------------------------------------------------------------------------------
/minimal/02_dynamic_results/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | using ufront.MVC;
4 |
5 | class HomeController extends Controller
6 | {
7 | /**
8 | Main page
9 | **/
10 | @:route(GET, "/")
11 | public function main()
12 | {
13 | return new ViewResult({
14 | title: "Ufront NodeJS Guide",
15 | });
16 | }
17 |
18 | /**
19 | GET parameters
20 | **/
21 | @:route(GET, "/get")
22 | public function get(args:{param1:String, param2:Int})
23 | {
24 | return new JsonResult({
25 | param1: args.param1,
26 | param2: args.param2,
27 | });
28 | }
29 |
30 | /**
31 | POST paramters
32 | **/
33 | @:route(POST, "/post")
34 | public function post(args:{param1:String, param2:Int})
35 | {
36 | return new JsonResult({
37 | param1: args.param1,
38 | param2: args.param2,
39 | });
40 | }
41 |
42 | /**
43 | You can also put the parameters as part of the url
44 | **/
45 | @:route(GET, "/path/$param1/$param2")
46 | public function path(param1:String, param2:Int)
47 | {
48 | return new JsonResult({
49 | param1: param1,
50 | param2: param2,
51 | });
52 | }
53 |
54 | /**
55 | You can mix path paramters and query parameters
56 | **/
57 | @:route(GET, "/mixed/$param1")
58 | public function mixed(param1:String, args:{param2:Int})
59 | {
60 | return new JsonResult({
61 | param1: param1,
62 | param2: args.param2,
63 | });
64 | }
65 |
66 | }
--------------------------------------------------------------------------------
/minimal/03_file_upload/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: File upload
2 |
3 | In this example, we will set up a minimal server that will handle uploaded files.
4 |
5 | ### Prerequisites
6 |
7 | - [Middleware](../09_middleware)
--------------------------------------------------------------------------------
/minimal/03_file_upload/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "03_file_upload",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/03_file_upload/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/03_file_upload/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/minimal/03_file_upload/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 | ::viewContent::
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/minimal/03_file_upload/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/minimal/03_file_upload/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Server
7 | {
8 | static function main()
9 | {
10 | // prepare the temp file upload middleware, which will save the uploaded
11 | // to a temp location, and delete it when the request ends
12 | var uploadMiddleware = new TmpFileUploadMiddleware();
13 |
14 | var ufrontApp = new UfrontApplication({
15 | indexController: HomeController, // all incoming requests will be handled by this controller
16 | defaultLayout: "layout.html", // use this file as the default layout for a ViewResult
17 | requestMiddleware: [uploadMiddleware], // handle the uploaded file when a request comes
18 | responseMiddleware: [uploadMiddleware], // make it a response middleware so that it will delete the temp file
19 | });
20 |
21 | // listen for incoming connection at this port number
22 | ufrontApp.listen(2987);
23 | }
24 | }
--------------------------------------------------------------------------------
/minimal/03_file_upload/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | using ufront.MVC;
4 |
5 | class HomeController extends Controller
6 | {
7 | /**
8 | Serves the upload form
9 | **/
10 | @:route(GET, "/")
11 | public function main()
12 | {
13 | return new ViewResult({
14 | title: "Ufront NodeJS Guide",
15 | });
16 | }
17 |
18 | /**
19 | Handles the uploaded file.
20 | **/
21 | @:route(POST, "/upload")
22 | public function upload()
23 | {
24 | var file = context.request.files['upload']; // use the form input name to retrieve the file
25 | if(file != null)
26 | {
27 | // save a copy of the file to disk, otherwise the temp uploaded file
28 | // will be deleted at the end of the request
29 | file.writeToFile(context.contentDirectory + file.originalFileName);
30 | }
31 |
32 | // return a result
33 | return new JsonResult({
34 | success: file != null,
35 | });
36 | }
37 | }
--------------------------------------------------------------------------------
/minimal/04_client_app/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: Client Application
2 |
3 | In this example, we will set up a minimal client application.
--------------------------------------------------------------------------------
/minimal/04_client_app/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "04_client_app",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/04_client_app/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/04_client_app/bin/view/home/about.html:
--------------------------------------------------------------------------------
1 |
2 | About Page...
3 |
--------------------------------------------------------------------------------
/minimal/04_client_app/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 |
2 | ::message::
3 |
--------------------------------------------------------------------------------
/minimal/04_client_app/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 |
11 | Try to click the following links and check your server log, there should be no request sent to server.
12 | Because the request is handled at client side, because of the "pushstate" class.
13 |
14 |
15 | Home
16 | About
17 |
18 |
19 | The following links will be handled by the server when the link has no "pushstate" class
20 |
21 | Home
22 | About
23 |
24 |
25 | Page contents start here:
26 | ::viewContent::
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/minimal/04_client_app/client.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # use the pushstate lib, which handles the browser history for us
5 | -lib pushstate
6 |
7 | # we are compiling for the client
8 | -D client
9 |
10 | # usual hxml things...
11 | -cp src
12 | -main Client
13 | -js bin/client.js
--------------------------------------------------------------------------------
/minimal/04_client_app/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/minimal/04_client_app/src/Client.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Client
7 | {
8 | static function main()
9 | {
10 | var ufrontApp = new ClientJsApplication({
11 | indexController: HomeController,
12 | defaultLayout: "layout.html",
13 | });
14 |
15 | // Listen to any history changes using PushState, and process each request.
16 | ufrontApp.listen();
17 | }
18 | }
--------------------------------------------------------------------------------
/minimal/04_client_app/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Server
7 | {
8 | static function main()
9 | {
10 | var ufrontApp = new UfrontApplication({
11 | indexController: HomeController, // all incoming requests will be handled by this controller
12 | defaultLayout: "layout.html", // use this file as the default layout for a ViewResult
13 | });
14 |
15 | // listen for incoming connection at this port number
16 | ufrontApp.listen(2987);
17 | }
18 | }
--------------------------------------------------------------------------------
/minimal/04_client_app/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | using ufront.MVC;
4 |
5 | class HomeController extends Controller
6 | {
7 | /**
8 | Serves a main page
9 | **/
10 | @:route(GET, "/")
11 | public function main()
12 | {
13 | return new ViewResult({
14 | title: "Ufront NodeJS Guide - Home",
15 | message:"Welcome to Ufront!"
16 | });
17 | }
18 |
19 | /**
20 | Serves another page
21 | **/
22 | @:route(GET, "/about")
23 | public function about()
24 | {
25 | return new ViewResult({
26 | title: "Ufront NodeJS Guide - About",
27 | });
28 | }
29 | }
--------------------------------------------------------------------------------
/minimal/05_api/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: API
2 |
3 | In this example, we will set up a minimal server that will use an API
4 |
5 | In Ufront, we have controllers and API. Controllers mainly handles routes and parse parameters from a request,
6 | while API usually handle "core" logics, like interacting with database, and authentications.
7 |
8 | You can also put your "core" or authentications logic inside a controller, but that is HIGHLY DISCOURAGED.
9 | because controller code will be compiled into client app and you risk leaking
10 | critical information to users, also authentications done in client side is also not trustable.
11 | On the other hand, APIs are NOT compiled into client app, any API calls from client app is
12 | actually a remoting call, i.e. the API code are always run in the server instead of the client.
13 | This way your logics and secrets are protected, and we can make sure authentications are not maliciously manipulated.
--------------------------------------------------------------------------------
/minimal/05_api/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "05_api",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/05_api/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/05_api/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 |
2 | ::message::
3 |
--------------------------------------------------------------------------------
/minimal/05_api/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 | ::viewContent::
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/minimal/05_api/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/minimal/05_api/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Server
7 | {
8 | static function main()
9 | {
10 | var ufrontApp = new UfrontApplication({
11 | indexController: HomeController, // all incoming requests will be handled by this controller
12 | defaultLayout: "layout.html", // use this file as the default layout for a ViewResult
13 | });
14 |
15 | // listen for incoming connection at this port number
16 | ufrontApp.listen(2987);
17 | }
18 | }
--------------------------------------------------------------------------------
/minimal/05_api/src/api/AnotherApi.hx:
--------------------------------------------------------------------------------
1 | package api;
2 |
3 | using ufront.MVC;
4 | using tink.CoreApi;
5 |
6 | /** Just to demonstrate that we can reference another API **/
7 | class AnotherApi extends UFApi
8 | {
9 | // inject the api we need
10 | @inject
11 | public var fileApi:FileApi;
12 |
13 | public function doSomething():Surprise
14 | {
15 | return fileApi.getFile('package.json');
16 | }
17 | }
--------------------------------------------------------------------------------
/minimal/05_api/src/api/FileApi.hx:
--------------------------------------------------------------------------------
1 | package api;
2 |
3 | import sys.io.File;
4 | import haxe.Timer;
5 |
6 | using ufront.MVC;
7 | using tink.CoreApi;
8 |
9 | class FileApi extends UFApi
10 | {
11 | public function getFile(path:String):Surprise
12 | {
13 | var content = File.getContent(path);
14 |
15 | // the file is read immediately, but we want to simulate an async call,
16 | // so we delay to return the result for 1sec (1000ms)
17 | // read docs of tink_core library to learn how Future/Surprise works
18 | var trigger = Future.trigger();
19 | Timer.delay(function() trigger.trigger(Success(content)), 1000);
20 | return trigger;
21 | }
22 | }
--------------------------------------------------------------------------------
/minimal/05_api/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | import api.*;
4 |
5 | using ufront.MVC;
6 |
7 | class HomeController extends Controller
8 | {
9 | // inject our api (please read docs of the minject library)
10 | @inject
11 | public var fileApi:FileApi;
12 |
13 | @inject
14 | public var anotherApi:AnotherApi;
15 |
16 | /**
17 | Call the API and return the value
18 | **/
19 | @:route(GET, "/")
20 | public function main()
21 | {
22 | return fileApi.getFile('package.json') >>
23 | function(content:String) return new ViewResult({
24 | title: "Ufront NodeJS Guide",
25 | message: content,
26 | });
27 | }
28 |
29 | /**
30 | For demonstration of API referring to another
31 | **/
32 | @:route(GET, "/test")
33 | @template('main.html') // specify the template file, otherwise ufront by default will try to find 'test.html'
34 | public function test()
35 | {
36 | return anotherApi.doSomething() >>
37 | function(content:String) return new ViewResult({
38 | title: "Ufront NodeJS Guide",
39 | message: content,
40 | });
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/minimal/06_basic_auth/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: Basic Authentication
2 |
3 | In this example, we will set up a minimal server that will have basic authentication.
4 |
5 | Note that "sessions" are not implemented in this minimal example, therefore the log-in status
6 | is only applicable to the current request. In other words, the log-in status will not persist across pages.
7 |
8 | ### Prerequisites
9 |
10 | - [Client App](../04_client_app)
11 |
12 | ## Overview
13 |
14 | The minimal code required for authentication mainly involves:
15 | - 2 interfaces: `UFAuthUser` & `UFAuthHandler` (see the `auth` package)
16 | - and the code to initialize them (see `AuthApi`)
--------------------------------------------------------------------------------
/minimal/06_basic_auth/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "06_basic_auth",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/06_basic_auth/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/06_basic_auth/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 |
2 | Is Logged In? ::isLoggedIn::
3 |
4 |
5 |
6 | Log in here: (username: ufront, password: ufrontpw)
7 |
--------------------------------------------------------------------------------
/minimal/06_basic_auth/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 | ::viewContent::
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/minimal/06_basic_auth/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/minimal/06_basic_auth/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import auth.Auth;
4 | import controller.HomeController;
5 | using ufront.MVC;
6 |
7 | class Server
8 | {
9 | static function main()
10 | {
11 | var ufrontApp = new UfrontApplication({
12 | indexController: HomeController,
13 | defaultLayout: "layout.html",
14 | authImplementation: Auth, // specify our auth implementation
15 | });
16 |
17 | // listen for incoming connection at this port number
18 | ufrontApp.listen(2987);
19 | }
20 | }
--------------------------------------------------------------------------------
/minimal/06_basic_auth/src/api/AuthApi.hx:
--------------------------------------------------------------------------------
1 | package api;
2 |
3 | import auth.Auth;
4 |
5 | using ufront.MVC;
6 | using tink.CoreApi;
7 |
8 | class AuthApi extends UFApi
9 | {
10 | public function login(username:String, password:String):Surprise
11 | {
12 | // check the username and password,
13 | // (note: in reality you should probably check against the database instead of hardcoding like this)
14 | if(username == 'ufront' && password == 'ufrontpw')
15 | {
16 | // cast the auth interface into our implementation
17 | var authImplementation = Std.instance(auth, Auth);
18 |
19 | // initialize our auth handler
20 | authImplementation.init(username);
21 | }
22 |
23 | // our simple authentication logic example here is a sync operation.
24 | // in reality, you may want to query the database or do other async operations,
25 | // in that case you can return a "real" future instead of a "sync future"
26 | // as what I am doing here.
27 | return Future.sync(Success(Noise));
28 | }
29 | }
--------------------------------------------------------------------------------
/minimal/06_basic_auth/src/auth/Auth.hx:
--------------------------------------------------------------------------------
1 | package auth;
2 |
3 | using ufront.MVC;
4 |
5 | class Auth implements UFAuthHandler
6 | {
7 | // required by the interface
8 | public var currentUser(get, never):UFAuthUser;
9 |
10 | // actually stores the user;
11 | var _currentUser:User;
12 |
13 | public function new()
14 | {
15 | }
16 |
17 | // initialize our auth handler with an user id,
18 | // this user id should be the result of some authentication (e.g. username/password)
19 | public function init(userId:String)
20 | {
21 | _currentUser = new User(userId);
22 | }
23 |
24 | // required by the interface
25 | public function hasPermission (permission:EnumValue):Bool
26 | {
27 | return isLoggedIn() && _currentUser.can(permission);
28 | }
29 |
30 | // required by the interface
31 | public function hasPermissions (permissions:Iterable):Bool
32 | {
33 | return isLoggedIn() && _currentUser.can(permissions);
34 | }
35 |
36 | // required by the interface
37 | public function isLoggedIn():Bool
38 | {
39 | return _currentUser != null;
40 | }
41 |
42 | // required by the interface
43 | public function isLoggedInAs(user:UFAuthUser):Bool
44 | {
45 | return isLoggedIn() && _currentUser.userID == user.userID;
46 | }
47 |
48 | // required by the interface
49 | public function requireLogin ():Void
50 | {
51 | if(!isLoggedIn()) throw HttpError.authError(ANotLoggedIn);
52 | }
53 |
54 | // required by the interface
55 | public function requireLoginAs (user:UFAuthUser):Void
56 | {
57 | if(!isLoggedInAs(user)) throw HttpError.authError(ANotLoggedInAs(user));
58 | }
59 |
60 | // required by the interface
61 | public function requirePermission (permission:EnumValue):Void
62 | {
63 | if(!hasPermission(permission)) throw HttpError.authError(ANoPermission(permission));
64 | }
65 |
66 | // required by the interface
67 | public function requirePermissions (permissions:Iterable):Void
68 | {
69 | for(permission in permissions) if(!hasPermission(permission)) throw HttpError.authError(ANoPermission(permission));
70 | }
71 |
72 | // required by the interface
73 | public function toString ():String
74 | {
75 | return "Auth";
76 | }
77 |
78 | function get_currentUser() return _currentUser;
79 | }
80 |
--------------------------------------------------------------------------------
/minimal/06_basic_auth/src/auth/User.hx:
--------------------------------------------------------------------------------
1 | package auth;
2 |
3 | using ufront.MVC;
4 |
5 | class User implements UFAuthUser
6 | {
7 | // required by the interface
8 | public var userID(get, never):String;
9 |
10 | // actually stores the user id
11 | var userId:String;
12 |
13 | public function new(userId:String)
14 | {
15 | this.userId = userId;
16 | }
17 |
18 | // required by the interface
19 | public function can(?permission:EnumValue, ?permissions:Iterable):Bool
20 | {
21 | // for minimal demonstration purpose, here simply returns true to allow all permissions.
22 | // in reality, you should implement your own logic (e.g. query database, etc)
23 | // to determine if an user is "can" do the specified permissions
24 | return true;
25 | }
26 |
27 | function get_userID() return userId;
28 | }
--------------------------------------------------------------------------------
/minimal/06_basic_auth/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | import api.*;
4 |
5 | using ufront.MVC;
6 |
7 | class HomeController extends Controller
8 | {
9 | @inject
10 | public var authApi:AuthApi;
11 |
12 | @:route(GET, "/")
13 | public function main(?args:{username:String, password:String})
14 | {
15 | // try to login with the provided credentials
16 | // there is no problem if they are not provided,
17 | // the api will simply skip the process.
18 | return authApi.login(args.username, args.password) >>
19 | function(_)
20 | {
21 | // we can access the auth handler from `context.auth`
22 | var isLoggedIn = context.auth.isLoggedIn();
23 |
24 | return new ViewResult({
25 | title: "Ufront NodeJS Guide",
26 | isLoggedIn: isLoggedIn,
27 | });
28 | }
29 |
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/minimal/07_remoting/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: Remoting
2 |
3 | In this example, we will set up a minimal client application that use remoting.
4 |
5 | Remoting is the type-safe way for a client to communicate with the server.
6 | Some quick comparison of Haxe remoting vs AJAX:
7 |
8 | 0. Haxe remoting is fully typed vs ajax is just plain text or json
9 | 0. We can basically send ANY haxe types over the wire with haxe remoting, including enum, class instances, etc.
10 | 0. Since it is fully typed, it gives you autocomplete in IDE
11 | 0. It helps you share the same piece of code between server and client
12 | 0. It is cross-platform: same code, compile to different targets
13 |
14 | ### Prerequisites
15 |
16 | - [API](../05_api)
17 |
--------------------------------------------------------------------------------
/minimal/07_remoting/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "07_remoting",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/07_remoting/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/07_remoting/bin/view/home/about.html:
--------------------------------------------------------------------------------
1 |
2 | About Page...
3 |
--------------------------------------------------------------------------------
/minimal/07_remoting/bin/view/home/main.html:
--------------------------------------------------------------------------------
1 |
2 | ::message::
3 |
4 |
5 | Rendered by: ::renderedBy::
6 |
7 |
8 |
9 | Try to input something and click submit, the "GET" request will not be sent to server,
10 |
because it is handled by pushstate. Instead, the client will handle the request and,
11 |
for the API call it will use remoting so that the API call is actually run on the server.
12 |
You can check the server output to verify that.
13 |
14 |
--------------------------------------------------------------------------------
/minimal/07_remoting/bin/view/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ::title::
7 |
8 |
9 |
10 |
11 | ::viewContent::
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/minimal/07_remoting/client.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # use the pushstate lib, which handles the browser history for us
5 | -lib pushstate
6 |
7 | # we are compiling for the client
8 | -D client
9 |
10 | # usual hxml things...
11 | -cp src
12 | -main Client
13 | -js bin/client.js
--------------------------------------------------------------------------------
/minimal/07_remoting/server.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # we need hxnodejs because we are targeting nodejs
5 | -lib hxnodejs
6 |
7 | # ufront uses expressjs behind the hood
8 | -lib express
9 |
10 | # we are compiling for the server
11 | -D server
12 |
13 | # usual hxml things...
14 | -cp src
15 | -main Server
16 | -js bin/server.js
--------------------------------------------------------------------------------
/minimal/07_remoting/src/Client.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import controller.HomeController;
4 | using ufront.MVC;
5 |
6 | class Client
7 | {
8 | static function main()
9 | {
10 | var ufrontApp = new ClientJsApplication({
11 | indexController: HomeController,
12 | defaultLayout: "layout.html",
13 | });
14 |
15 | // Listen to any history changes using PushState, and process each request.
16 | ufrontApp.listen();
17 | }
18 | }
--------------------------------------------------------------------------------
/minimal/07_remoting/src/Server.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import api.ApiContext;
4 | import controller.HomeController;
5 | using ufront.MVC;
6 |
7 | class Server
8 | {
9 | static function main()
10 | {
11 | var ufrontApp = new UfrontApplication({
12 | indexController: HomeController,
13 | remotingApi: ApiContext, // specify our remoting API context (interface)
14 | defaultLayout: "layout.html",
15 | });
16 |
17 | // listen for incoming connection at this port number
18 | ufrontApp.listen(2987);
19 | }
20 | }
--------------------------------------------------------------------------------
/minimal/07_remoting/src/api/ApiContext.hx:
--------------------------------------------------------------------------------
1 | package api;
2 |
3 | import api.TestApi;
4 | using ufront.MVC;
5 |
6 | class ApiContext extends UFApiContext
7 | {
8 | public var testApi:TestApi;
9 | }
--------------------------------------------------------------------------------
/minimal/07_remoting/src/api/TestApi.hx:
--------------------------------------------------------------------------------
1 | package api;
2 |
3 | using ufront.MVC;
4 | using tink.CoreApi;
5 |
6 | class TestApi extends UFApi
7 | {
8 | public function test(param:String):Surprise
9 | {
10 | // make sure this piece of code is compiled in the server only
11 | // to demonstrate that the code is actually run in the server,
12 | // even when the API is called form client
13 | #if server
14 | param = '$param (server)';
15 | #end
16 |
17 | // just shorthand to `Future.sync(Success(param))`
18 | return param.asGoodSurprise();
19 | }
20 | }
21 |
22 |
23 | // UFAsyncApi will do the magic, converting all the api calls to remoting calls for the client
24 | class AsyncTestApi extends UFAsyncApi {}
--------------------------------------------------------------------------------
/minimal/07_remoting/src/controller/HomeController.hx:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | import api.TestApi;
4 |
5 | using ufront.MVC;
6 |
7 | class HomeController extends Controller
8 | {
9 | @inject
10 | public var testApi:AsyncTestApi;
11 |
12 | @:route(GET, "/")
13 | public function main(?args:{param:String})
14 | {
15 | return testApi.test(args.param) >>
16 | function(result:String) return new ViewResult({
17 | title: "Ufront NodeJS Guide - Home",
18 | message: 'Result: $result', // print the result of the API call
19 | renderedBy: #if server 'Server' #else 'Client' #end, // let us know if this page is rendered by client or server
20 | });
21 | }
22 | }
--------------------------------------------------------------------------------
/minimal/08_tasks/README.md:
--------------------------------------------------------------------------------
1 | # Minimal example: Ufront Tasks
2 |
3 | In this example, we will set up a minimal task script.
4 |
5 | Ufront task scripts are program that run in the command line, acting like a hybrid of
6 | server and client. In fact, we do not actually need a server here because all the API functions
7 | are compiled into the task script, making it like a server that doesn't listen to incoming
8 | http request, but instead invoked through command line.
9 |
10 | Since the task script resides in the server, you can write admin programs in this
11 | way. For example, you can write a task that will clear obsolete/expired data from the database,
12 | or a task that will call an API to send out emails.
13 |
14 | UFTaskSet is based on the [mcli](https://github.com/waneck/mcli) library, for more usage details please refer to mcli docs.
15 |
16 | ## How to build / run
17 |
18 | #### Build:
19 |
20 | ```bash
21 | haxe tasks.hxml
22 | ```
23 |
24 |
25 | #### Run:
26 |
27 | ```bash
28 | cd bin
29 | node tasks.js --test
30 | node tasks.js --read-path start_server.sh
31 | ```
--------------------------------------------------------------------------------
/minimal/08_tasks/bin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "08_tasks",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "compression": "^1.6.1",
7 | "body-parser": "^1.15.0",
8 | "cookie-parser": "^1.4.1",
9 | "express": "^4.13.4",
10 | "multer": "^1.1.0"
11 | },
12 | "scripts": {
13 | "start": "./start_server.sh"
14 | }
15 | }
--------------------------------------------------------------------------------
/minimal/08_tasks/bin/start_server.sh:
--------------------------------------------------------------------------------
1 | nodemon server.js
--------------------------------------------------------------------------------
/minimal/08_tasks/src/Tasks.hx:
--------------------------------------------------------------------------------
1 | package;
2 |
3 | import api.*;
4 | import ufront.tasks.UFTaskSet;
5 |
6 | using ufront.MVC;
7 | using tink.CoreApi;
8 |
9 | class Tasks extends UFTaskSet
10 | {
11 | static function main()
12 | {
13 | var tasks = new Tasks();
14 |
15 | // Inject our content directory in case we need to write to it.
16 | tasks.injector.map(String, "contentDirectory").toValue("../uf-content/");
17 |
18 | // Inject the auth system if you need auth in your APIs.
19 | // tasks.injector.map(UFAuthHandler).toClass(YesBossAuthAHandler);
20 |
21 | // Inject all our APIs.
22 | for (api in CompileTime.getAllClasses(UFApi)) tasks.injector.mapRuntimeTypeOf(api).toSingleton(api);
23 |
24 | // Use CLI logging, which prints both to a log file and to the CLI output.
25 | tasks.useCLILogging("logs/tasks.log");
26 |
27 | // Execute the task runner
28 | var args = Sys.args();
29 | tasks.execute(args);
30 |
31 | }
32 |
33 | // inject our API
34 | @inject @:skip
35 | public var fileApi:FileApi;
36 |
37 | /**
38 | A demonstration to show that you can call an API from a task script.
39 |
40 | Usage: node tasks.js --test
41 | **/
42 | public function test()
43 | {
44 | // You can call any API from a task script
45 | fileApi.getFile('package.json').handle(
46 | function(content)
47 | {
48 | trace(content.sure());
49 | Sys.exit(0);
50 | }
51 | );
52 | }
53 |
54 | /**
55 | A demonstration to show that you can pass parameters to task script.
56 | (Refer to mcli docs for more details.)
57 |
58 | Usage: node tasks.js --read-path package.json
59 | **/
60 | public function readPath(path:String)
61 | {
62 | // You can call any API from a task script
63 | fileApi.getFile(path).handle(
64 | function(content)
65 | {
66 | trace(content.sure());
67 | Sys.exit(0);
68 | }
69 | );
70 | }
71 | }
--------------------------------------------------------------------------------
/minimal/08_tasks/src/api/FileApi.hx:
--------------------------------------------------------------------------------
1 | package api;
2 |
3 | import sys.io.File;
4 | import haxe.Timer;
5 |
6 | using ufront.MVC;
7 | using tink.CoreApi;
8 |
9 | class FileApi extends UFApi
10 | {
11 | public function getFile(path:String):Surprise
12 | {
13 | var content = File.getContent(path);
14 |
15 | // the file is read immediately, but we want to simulate an async call,
16 | // so we delay to return the result for 1sec (1000ms)
17 | // read docs of tink_core library to learn how Future/Surprise works
18 | var trigger = Future.trigger();
19 | Timer.delay(function() trigger.trigger(Success(content)), 1000);
20 | return trigger;
21 | }
22 | }
--------------------------------------------------------------------------------
/minimal/08_tasks/tasks.hxml:
--------------------------------------------------------------------------------
1 | # use the ufront-mvc lib
2 | -lib ufront-mvc
3 |
4 | # the uftasks library
5 | -lib ufront-uftasks
6 |
7 | # we need hxnodejs because we are targeting nodejs
8 | -lib hxnodejs
9 |
10 | # ufront uses expressjs behind the hood
11 | -lib express
12 |
13 | # we are compiling for the server
14 | -D server
15 |
16 | # usual hxml things...
17 | -cp src
18 | -main Tasks
19 | -js bin/tasks.js
--------------------------------------------------------------------------------
/minimal/09_middleware/.wip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinresol/ufront-nodejs-guide/a4b92bfd7d8257388ab698fa90af4643dbb8ef7b/minimal/09_middleware/.wip
--------------------------------------------------------------------------------