📜 ⬆️ ⬇️

Development of client-server infrastructure in javascript (part 1 - client)

image

What is this article about. I want to share the experience of developing a mobile application on phonegap. The result was a whole software package with a RESTfull server, clients, and even hosted on PaaS. Therefore, I will describe separately the client application architecture (html5 single page app wrapped in phonegap), server application (nodejs with swagger-node-express + node-orm2), and how to put all this on openshift PaaS.

Development of client-server infrastructure in javascript (part 2 - server and location)

For impatient:
Project page
Source
')
I think the site will immediately fall from habraeffekta. This is a trial account with only two slots for the node. But more about that at the end.

I want to clarify right away - the project is not finished, but it is already working stably, plus you can show the main parts and architectural solutions.

Let's start with the most important thing - the client. I used (ex) twitter bootstrap, I understand that the template is not very good yet - but the main thing is js logic. The application itself is built on require.js, although I myself do not mind minimizing the entire project. The fact is that on the phone the files will be loaded quickly, and for the site, in fact, a separate application is planned in the future. As a javascript framework, I chose marionette.
Two main modules are now implemented: Auth and Conferences.
Disable autostart:

this.startWithParent = false; 

And manually run them after initializing the main module.

 require( [ 'css!bootstrap_css', 'bootstrap', 'app/modules/conferences', 'app/modules/auth', ], function () { app.start(); } ); 

 MyConference.addInitializer(function(options){ mainLayout = new MainLayout; MyConference.mainView.show(mainLayout); var headerView = new HeaderView; headerView.MyConference = MyConference; mainLayout.header.show(headerView); MyConference.Conferences.start(); MyConference.Auth.start(); }); 

Auth - registration / authorization. I want to pay attention to social authorization. I always implement the authorization myself and do not use third-party aggregators, I don’t know it’s good or bad. Implemented by Google, LinkedIn, Facebook, Twitter, you can just take my code if you need to implement something similar. The essence of social authorization is that I use the js on the client to get the Api key, and then transfer it to the server for verification. For example facebook:

 var afterInit = function(){ var sendAccessToken = function(response){ $.post( cfg.baseUrl + 'auth.json/facebook', {FacebookKEY: response.authResponse.accessToken}, function(data, message, xhr){ process_social_resporce(model, data, xhr); }, "text" ); } FB.getLoginStatus(function(response) { if(response.status == "not_authorized" || response.status == "unknown"){ FB.login(function(response, a) { if (response.authResponse) { sendAccessToken(response); } else { console.log(response, a) } }, {scope:'email'}); }else{ sendAccessToken(response); } }); } window.fbAsyncInit = function() { FB.init({ appId : cfg.facebookAppId, // App ID status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true // parse XFBML }); afterInit(); }; // Load the SDK asynchronously (function(d){ var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0]; if (d.getElementById(id)) {return afterInit();} js = d.createElement('script'); js.id = id; js.async = true; js.src = "//connect.facebook.net/en_US/all.js"; ref.parentNode.insertBefore(js, ref); }(document)); 

For posts / likes, I don’t need this key, just find out what the user is. So, if you need to use offline access, then this method may not work because you need to receive a separate key, which js clients do not issue.
Separate story with twitter. It does not have browser-based client authorization, so I implemented the server one. A window opens, there the user is authorized and then the parent window reads the response from the child. This may not work in all browsers, so you will most likely have to change it a bit. But in the android layout it works fine.

 var childWin = window.open(cfg.baseUrl + 'auth.json/twitter/'+Storage.get('API_KEY'), 'Twitter Auth', "height=640,width=480"); childWin.onunload = function(){ var check = function(){ if(childWin.document){ var body = childWin.document.getElementsByTagName("body")[0]; if(!model.isNew() || body.textContent.length > 0){ process_social_resporce(model, body.textContent); childWin.close(); }else{ setTimeout(check, 100); } }else{ setTimeout(check, 100); } } setTimeout(check, 100); } 

We now turn to the main module - Conferences. Here, in fact, everything is very simple. I describe the controller with the routes.

 var ConferencesController = Marionette.Controller.extend(new function(){ return { main: function(){ MyConference.mainView.currentView.header.currentView.setHeader('Conferences'); var conferencesCollection = new ConferencesCollection; var spinnerView = new SpinnerView(); spinnerView.render(); conferencesCollection.fetch({ error: function(){ console.log('error'); }, success: function(collection){ var mainView = new MainView; mainView.collection = conferencesCollection; MyConference.mainView.currentView.content.show(mainView); spinnerView.remove(); } }) }, conference: function(id){ var conferenceModel = new ConferenceModel; conferenceModel.set('id', id); conferenceModel.fetch({ error: function(){ var conferenceNotFoundView = new ConferenceNotFoundView; MyConference.mainView.currentView.content.show(conferenceNotFoundView); }, success: function(conference){ var conferenceFullView = new ConferenceFullView; conferenceFullView.model = conference; MyConference.mainView.currentView.content.show(conferenceFullView); } }); }, streams: function(conference_id){ ShowStreams( conference_id, function(){ ShowStream(streams.at(0).get('id')); } ); }, stream: function(id){ ShowStream(id); } } }); var MainRouter = Backbone.Marionette.AppRouter.extend({ appRoutes: { "conference/:id": "conference", "conferences": "main", "": "main", "streams/:conference_id": "streams", "stream/:id": "stream" }, controller: new ConferencesController }); 

As you can see, the usual Beckbon model / collection is created, the data is received and transferred to the view. The conference list is a regular collectionview. I’ll give a closer look at the View for a detailed conference description. Support for OpenStreetMap and GoogleMaps is implemented manually. You can, of course, use Leaflet, but I'm not sure that Google likes direct access to their pictures. Also there is a picture / pdf displayed or a link to the file, if any. And at the top right link to the list of reports.
If the user is logged in, he sees three buttons, “go” to the conference, to favorites, and refuse. I did not inherit the detailed description from the ItemView, but from the Layout, so I simply determined the block where to render these three buttons.

 regions: { decision: "#decision" }, 

And depending on the status of the user, I show one or another view.

 if(MyConference.Auth.getUser().isNew()){ var view = new GuestDecisionView; }else{ var desisionModel = new DecisionModel(view.model.get('decision')); var view = new LoggedInDecisionView({model: desisionModel}); view.parent = this; } this.decision.show(view); 

It remains only to collect and run the project on the phone. If you need to do the platform, do the "cordova platform add android"

 cordova platform add android 

Then

 cordova build android 

To build or

 cordova run android 

To look at your phone.

The ultimate goal is to place apps on Google play, the Apple App Store and the Windows Store. But my main activity is web, not mobile, development, so I am not yet registered as a developer in any of these stores.

I hope someone will be useful this article. I tried not to inflate it much, but to pay attention to all the main points. I will be glad to criticism, wishes, pull requests to the repository . Due to the fact that there was a lot of material, I broke it into two articles - the client and the server. In the next article I will describe the creation of a restfull server on nodejs with orm autodocument and memcached. And how I deploy all of this on PaaS from RedHat - openshift .

Source: https://habr.com/ru/post/200192/


All Articles