Tuesday, November 18, 2014

From node to website

This post is for people who want to learn to create a website with node.js

During the process some steps are there to let you understand what the code does, this doesn't mean you should use the code as a part of a real website.

Setting up the project

After installing node on your computer, you open the command prompt or terminal and create a directory which will contain your files.

When you are in the directory you run npm init. This command will ask you some questions and generate a package.json file.

Starting to create the site

On the front page of the site you see how to create a webserver which shows Hello world when you go to the url in your browser

I named the file app.js so to run the website with npm start you need to change "start": "node index" to "start": "node app" in the package.json file.

The first webpage

The code above displays plain text but most of you know browsers display html nicer than plain text. So lets change the code to make this possible.

The changes I made:

  1. I moved the output of the site to its own function. This keeps the webserver code clean.
  2. I put the html code in a separate file. This allows you to change the html without changing the code.
  3. I used the fs module to read the file with the html in.
  4. Thanks to the callback parameters of the readFile method I can show a page not found error if the file isn't found.
  5. And to end it I display the html code that was read from the file.

If the website is running you need to stop it with the key combination ctrl+c, and start it again. Now you see that hello world is bigger and bolder.

More pages

A website has more than one page. It is possible to create multiple pages in the browser using frameworks, but we are going to keep using node to do this.

The changes I made

  1. I added page2.html
  2. I added a link to page2 in index.html and a link to home in page2.html
  3. I added a new parameter to the render function to make it possible to read different files.
  4. I checked if the browser send a GET request. At the moment we don't care about POST, PUT, DELETE or PATCH requests
  5. Then I checked which url the browser wants

After restarting the webserver again you will see the link to the second page. And clicking on it will display the second page.

Cleanup the webserver code

Because checking the routes is a responsibility of the app it's best to move the code out the webserver code.

  1. Created a Router object with the public methods get, nopage and handle. And one private method find.
  2. Added an instance of the Router object with the name router.
  3. Added the pages with get method, and the 404 page with the nopage method.
  4. Used router.handle instead of a anonymus function to let the app decide which content should be visible.

  5. Changed the render function to set the status code of the page if there is an error. This is important for SEO and other automated page visits.
  6. Added the 404.html file to display a nice page.

Making it real

We can build websites with this code but it isn't very powerful, for instance you have to add all the routes instead of using variables for groups of similar routes.

The most used framework is express

run npm install express --save, mac os users will need to add sudo in front of the command. This will add the express package to the project in the node_modules directory.

Express takes care of the routing for us, and allows us to add a template engine. At the moment we use static html files but when the data comes from somewhere else the html code is going to contain variables and logic.

As you can see express also has a get method to set GET request routes. To display a html 404 error you need to define it with the use method below all other routes.

Express needs to know the root template engine files directory, what method the template engine uses to render the template and declare the default template engine. You can use multiple template engines but this is not a good idea if you want performance and consistency.

Express also has a listen method so you don't need to create the webserver yourself.

Conclusion

I hope this gives you a clue how we went from a webserver that only displayed hello world to a website with multiple pages and html output.

Wednesday, October 29, 2014

Meteor and the findOne no result problem

Now that meteor has a version 1.0 release I wanted to give it another try.
As a test I was creating a simple blog.

The problem I encountered was when i tried to display a post detail. The code looked simple enough.

Router.route('/:_id', function(){
   this.render('detail', {
       data: function(){ 
           var templateData = { post: Posts.findOne({_id: this.params._id}) };
           return templateData;
       }    
   });
});

this.params._id looks almost like req.params._id from the express framework.
And I was sure the document with the _id existed because it came from the database.

During my search I found a few different ways to pass the _id to the findOne function.

The first one I tried comes from the official documentation:

Posts.findOne(this.params.id)

It looks like the mongo library that comes with meteor adds a little abstraction to the mongodb method. Great, but it didn't work.

Next there the id key without the underscore. That didn't work either.

Then i got the idea the hexstring wasn't enough. I needed the ObjectId instance like it's needed in the mongodb shell.
Of course the mongo ObjectId isn't available in Meteor.

After a bit of searching i found that the meteor Mongo library has a ObjectID method.

Router.route('/:_id', function(){
   this.render('detail', {
       data: function(){ 
           var postId = new Mongo.ObjectID(this.params._id); 
           var templateData = { post: Posts.findOne({_id:postId}) };
           return templateData;
       }    
   });
});

And the document data was visible.

Update

It looks like the meteor mongo shell produces _ids that are ObjectId objects, but inserting documents with the meteor Mongo library produces _ids that are 'plain' hexstrings.

So to insert documents you best use the meteor Mongo library because that's the way you interact with mongo the most.

Saturday, January 04, 2014

Belgian rail and usability

After the bus company, De lijn, introduced the sms-ticket I never use other way to buy tickets for a bus ride. Now the Belgian rail introduced a sms-ticket and I wanted to see if it is going to be the way to buy train tickets from now on.

I suspected it to be a little more difficult because of the price range between short and long rides but the experience was much harder than expected.

First attempt

There are two ways to buy a ticket, an iphone app and the mobile website. Why is there only an iphone app? As a developer I know there are tools to create apps for the different smartphone operating systems form a single code base. And Belgian rail has an official app for android, so why not update that app for sms-tickets?

Some bright minds probably already started thinking, why do they call it an sms-ticket if you need an internet connection. The ticket is send to your phone in an sms.

So I go to the mobile site and before you can buy a ticket you need to have an account.  If you want to buy a ticket on the regular website you need to provide you name and address, so I guess creating an account is their solution to make the buying easier because it is a one time deal.
I'm filling in the form. After I click on the what I think is the last step to complete the account I get an error message.

For a spur of the moment buyer this is enough reason never to buy an sms-ticket.

The long way

Because I'm crazy or addicted to technology or both I really want to know how to buy an sms-ticket. So I go to the Belgian rail website on my computer and create an account.

The first thing that strikes me as a webdeveloper is that the form to create an account is in a popup. What other things do you want to do other than creating an account at that time?
For your date of birth they use the JQuery UI datepicker with default settings which makes it impossible to select your date faster than you can type. There is a demo on the JQuery UI site which makes it a better datepicker.

After I completed the form I get a message to confirm the account. I guess you also need to do this on the mobile site so if you are on a smartphone you need to switch between apps, which is another threshold before buying a ticket.

Back to the mobile site now. I log in and go through the ticket data selection. When I come to the payment part there are only creditcard options. This is strange because on the regular website you have more options.
After selecting a creditcard option there is a checkbox to remember Belgian rail as seller to make the payments easier. It seems that the service Belgian rail uses to handle the payments only provides this option for creditcards?

 Conclusion

After creating an account and having a creditcard and remebering Belgian rail as a seller, the only one that makes it hard to buy an sms-ticket is the bank you are with. Some banks make you to verify the online creditcard purchase so you need to have your digipass with you and also your creditcard.

SMS is a quick platform for on the road and buying and sms-ticket isn't, there are too much actions needed  and less options than on the regular website. 

Aftermath analysis (how I would create the sms-ticket) 

After looking at all the data they need and all the ticket options they have it looks like the sms ticket is a six step process.

  1. Personal data and data about the ride 
  2. ride options provided by Belgian rail
  3. ride option selection sms
  4. payment info by Belgian rail
  5. payment sms
  6. sms-ticket by Belgian rail
So it takes three sms messages without the need of an internet connection.

Personal data and data about the ride

They use parts of the account information, date of birth gets mentioned in their faq, to secure the sms ticket.
Why not make the personal information that they need required lines in the sms.

The ride data they need is begin and end station, go date and return date is optional.

An example sms could be:
  1. START
  2. first name
  3. last name
  4. date of birth
  5. begin station
  6. end station
  7. go date
The first line is to make the sms service aware this is a new ticket. 

Ride options provided by Belgian rail

SMS is a peer to peer platform so there are no sessions and because it is a multistep process a token should be send to add to the following sms messages. The token should be as short as possible to make it easy to remember but big enough to allow all the travelers to create a ticket for a two day period. The two day period is in case the traveler starts making a ticket close to midnight.

The options should have numbers to identify them.

An example sms:
  1. abc123
  2. 1 adult : 2.5 €
  3. 2 child : 2 €

Ride option selection sms

The ticket buyer now needs to  verify which options he needs.

Example sms:
  1. OPTIONS abc123
  2. 1 1

Payment info by Belgian rail

Provide a code that the buyer can send to reduce his telecom account by the amount of the ticket and send the sms ticket to the buyer.
This is what the bus company does with the two options they provide.

Conclusion

It can be a bumpy ride especially the first sms because it needs a lot of information that has to verified. But it is a pure sms solution which makes the public who can use the sms ticket bigger.