Monday, July 11, 2016

Using TypeScript feels like you are in the Matrix, you can bend things(types) at will

Using TypeScripts feels like you are in the Matrix, you can bend things(types) at will.


Improved the code from this..


export function pageBuilder(req: express.Request, res: express.Response, next: Function)
{

    let dRequest = denodeify(request);

    let cookie = request.cookie(req.headers["cookie"]);

    let headers = {cookie};

    let parts = {
        header : dRequest({url: "http://localhost:168/ui/header.html", headers}),
        toolbox: dRequest({url: "http://localhost:168/ui/toolbox.html", headers}),
        footer : dRequest({url: "http://localhost:168/ui/footer.html", headers})
    };


    Q.all(<any>parts).then(result =>
    {
     
        let html = buildPage(result.header.body, result.toolbox.body, result.footer.body);

        res.send(html);
    });

}

..to this:


export function pageBuilder(req: express.Request, res: express.Response, next: Function)
{

    let dRequest = denodeify(request);

    let cookie = request.cookie(req.headers["cookie"]);

    let headers = {cookie};

    let parts = {
        header : dRequest({url: "http://localhost:168/ui/header.html", headers}),
        toolbox: dRequest({url: "http://localhost:168/ui/toolbox.html", headers}),
        footer : dRequest({url: "http://localhost:168/ui/footer.html", headers})
    };


    Q.all(<any>parts).then(result =>
    {
        let partsResult: {
            header: express.Request,
            toolbox: express.Request,
            footer: express.Request
        } = <any>result;


        let html = buildPage(partsResult.header.body, partsResult.toolbox.body, partsResult.footer.body);

        res.send(html);
    });

}

The current signature of Q's TypeScript definition does not allow dictionary, but you can do adhoc'y types even in the code's body, don't necessarily need to put the type in the global context.


Happy Coding!

Thursday, July 7, 2016

Using array instead of creating a junction table with foreign keys

Joining is slow on junction table:

explain analyze
select coupons.coupon_id 
from coupons join coupons_products using (coupon_id) 
where coupons.user_id is null and product_id = 1000 group by coupon_id;

Planning time: 0.931 ms
Execution time: 676.687 ms

Try to query against another query:

explain analyze
select coupons.coupon_id 
from coupons 
where coupons.user_id is null 
    and coupons.coupon_id in (select cp.coupon_id from coupons_products cp where cp.product_id = 100);

Planning time: 0.769 ms
Execution time: 0.075 ms

The above has same performance with array approach:

explain analyze
select coupons.coupon_id 
from coupons 
where coupons.user_id is null and product_ids @> array[1000];

Planning time: 0.211 ms
Execution time: 0.075 ms


Array query and junction table query(no-join) has same performance, 0.075 ms. The advantage of array query is its planning takes less time. 0.211 ms vs 0.769 ms.


This is an observation made on denormalizing junction table to array


Happy Coding!

NodeJS choosing between req.params and req.query, and when to use them both.

req.params.memberId

actual url:
    http://example.com/member/thisGoesToParam

nodejs's routing: 
    http://example.com/member/:memberId

req.params.memberId == "thisGoesToParam"


req.query.memberId
actual url:
    http://example.com/member?memberId=thisGoesToQuery

nodejs's routing: 
    http://example.com/member

req.query.memberId == "thisGoesToQuery"



req.params is most often used since it can directly/explicitly identify a resource right in the URL itself, and it's SEO-friendly. Search engines prefer URLs that has no question marks in them, clean URLs, req.params can facilitate clean URL.


req.query is mostly used on searching or paging. Anything that are extra to the identifier, goes to req.query. An example, getting the list of person (uses paging since there are too many persons in a country) from a country should better use req.query instead of req.param.


actual url:
    http://example.com/country/PH/person?page=1

routing: 
    http://example.com/country/:countryCode/person

req.params.countryCode == "PH"
req.params.page == 1

that might return:

{
 country: "Philippines"
 persons: ["Schwarzenegger", "Zach"]
}


Anything that goes to req.params are called resource identifier, meaning even how many times the url with embedded resource is called/submitted to, result is always the same. REST has a terminology for that, idempotent. Idempotent meaning, when something is called/submitted to a url with a primary key, the result of calling/submitting to a URL should be always the same even how many times it is called/submitted to.

Parameters that goes to req.params returns idempotent result. While parameters that goes to req.query returns non-idempotent result, as req.query's result today would not be same as req.query's result tomorrow, later or any point in time


Let's say later there are new persons added to a country, the country identifier (req.params.countryCode) will always return idempotent result, same country even how many times it is called. While with req.query.page, it returns non-idempotent result, a value passed to req.query even it's the same might not be the same(say page number 1 is called/refreshed on the browser many times) depending on when the url is called/submitted.

http://example.com/country/PH/person?page=1

So even we use the same Country and same Page, although the country's parameter always return the same result(Philippines), the page's parameter might return different results depending on when the url is called/submitted.

{
 country: "Philippines"
 persons: ["Adams", "Applegate", "Ashley"]
}


It's much better to use req.params, not only it is SEO-friendly for search engines, in code it's also easy to spot the required parameters(mostly primary key) as they are explicitly part of the url itself.


routing: 
    http://example.com/country/:countryCode/person

actual url: 
    http://example.com/country/PH/person


To access countryCode from req.params. Simply read it from: req.params.countryCode


If a country REST API (that fetches the country name and its people) uses req.query instead of req.params, the REST's URL would have a routing design like this:

http://example.com/country/person 


The URL is not so intuitive, some non-native English speaker might think if "person" is a country code.

Note that question marks can't be included on node.js's routing, so the consumer of the REST's URL would have to guess what is the name of the country parameter for the country, is it countryCode? is it countryId? req.query parameters have to be always documented, while req.params is so intuitive it doesn't even need documentation.


Happy Coding!

Tuesday, July 5, 2016

JavaScript's C# SelectMany

C# has a convenient method for flattening collections' collection, that method is SelectMany:

var result = 
    from account in areas.SelectMany(area => area.Accounts)
    where account.Selected
    select account.AccountId;



In JavaScript:

interface IAccountDto
{
    accountId: number;
    accountName: string;

    selected?: boolean; // not in actual DTO, just used in UI
}

interface IAreaDto
{
    areaName: string;
    accounts: IAccountDto[];
}



class Something {

   
    areas: IAreaDto[] = [
            {
                areaName: "Philippines",
                accounts: [
                    {
                        accountId  : 168,
                        accountName: "Account 168",
                        selected: true
                    },
                    {
                        accountId  : 169,
                        accountName: "Account 169",
                        selected: true
                    },
                ]
            },
            {
                areaName: "China",
                accounts: [
                    {
                        accountId  : 170,
                        accountName: "Account 170"
                    },
                    {
                        accountId  : 171,
                        accountName: "Account 171",
                        selected: true
                    },
                ]
            },


        ];   
   
   
   getResult(): number[] {

       let result = 
            this.areas.map(ar => ar.accounts)
            .reduce((a,b) => a.concat(b), [])
            .filter(ac => ac.selected)
            .map(ac => ac.accountId)
            
       return result;
   }
}



let s = new Something();

let x = JSON.stringify(s.getResult());

document.body.innerHTML = x;

Happy Coding!

Tuesday, June 28, 2016

Design for the default

If the library doesn't work out of the box, there must be a problem with the library.

node-soap generates xmlns prefix (tns), but it doesn't apply it to SOAP's method:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:tns="http://v5.soap.platform.helloworld.com/">
    <soap:Body>
         <authenticate>
             <apiKey>meh</apiKey>
             <username>ryan</username>
             <password>dahl</password>
        </authenticate>
    </soap:Body>
</soap:Envelope>

This is the right XML, as tested in Google Chrome's Boomerang extension, there is tns prefix in SOAP's method (authenticate):
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:tns="http://v5.soap.platform.helloworld.com/">
    <soap:Body>
         <tns:authenticate>
             <apiKey>meh</apiKey>
             <username>ryan</username>
             <password>dahl</password>
        </tns:authenticate>
    </soap:Body>
</soap:Envelope>



To fix the node-soap's broken default, add this option on createClient method:

var options = {
    ignoredNamespaces: {
        namespaces: [],
        override: true
    }
}


soap.createClient ( url, options, function ( err, client ) {


Using that, node-soap will apply the tns prefix to the SOAP's method name.


.NET's generated SOAP works out of the box, notice that there is no prefix in SOAP call:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
        <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none" />
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <authenticate xmlns="http://v5.soap.platform.helloworld.com/">
            <apiKey xmlns="">meh</apiKey>
            <username xmlns="">ryan</username>
            <password xmlns="">dahl</password>
        </authenticate>
    </s:Body>
</s:Envelope>


Happy Coding!

Sunday, June 26, 2016

Make further proxy requests authenticated

app.get('/hoo/ray', (req,res,next) => {


    let url = "https://www.helloworld.com/ui/fragments/header.html";

    let cookie = request.cookie(req.headers["cookie"]);

    let headers = {cookie};

    request({url, headers}, (error, response, body) => {

        url = "https://www.helloworld.com/ui/fragments/toolbox.html";

        request({url, headers}, (toolboxError, toolboxResponse, toolboxBody) => {

            let html = body + toolboxBody;

            res.writeHead(200, {
                'Content-Type'  : 'text/html',
                'Content-Length': html.length,
                'Expires'       : new Date().toUTCString()
            });


            res.end(html);

        });

    });

});


Next step, convert those callback hell to promises.

Sunday, May 1, 2016

pm2 must not be ran with sudo

If you got an EACCES error when you run pm2 without sudo..

me@ubuntu:~/myapp$ pm2 start ./bin/www
events.js:160
      throw er; // Unhandled 'error' event
      ^

Error: connect EACCES /home/me/.pm2/rpc.sock
    at Object.exports._errnoException (util.js:896:11)
    at exports._exceptionWithHostPort (util.js:919:20)
    at PipeConnectWrap.afterConnect [as oncomplete] (net.js:1073:14)


..chances are you might try to run pm2 with sudo and it will work.

However, it will cause an undefined value on process.env.PWD, and then it will cause SPA page that are refreshed or re-loaded from bookmark not to load.

var base = process.env.PWD;

res.sendFile('index.html', {root: path.join(base, '/public')});


To fix the error, make the following your own file /home/yourUsernameHere/.pm2/rpc.sock

sudo chown yourUsernameHere ~/.pm2/rpc.sock


Doing the above you can now run your pm2 without the sudo.

After running:

$ pm2 start ./bin/www

Run this:

$ pm2 save
$ pm2 startup

Then follow the instruction of that pm2 startup command.


Happy Coding!