17 Oct

10 minutes to a custom GraphQL Backend

First the backstory: I have been using GraphQl for react apps for a bit now, and I found myself yearning for an easy to build backend. There are several GraphQL as a service providers popping up, but I don’t like the idea of trusting my data to new comers since I am not sure how long they’ll be around and wether I’ll be able to get my data out should they go out of business.

On to business. Let’s build a GraphQL backend in Python. We’ll need authentication, and some sort of ORM. I plan to host this on AWS Lambda so I also want to support DynamoDB.

Read More

16 Jan

JMVC + JQM improved dispatch

In my previous example, I used an eval to load a page controller from the jQuery.fn  name space. Here is a much better version of that code which has the added benefit of allowing access to the instance of my controller:

If ( typeof MyApp.Pages[pageName] === 'function') {
    // don't really need the element passed here per this example's controller, will check if needed.
    pageInstance  = new MyApp.Pages[pageName]($('body'));
    pageInstance.view.done( function ( htmlOutput ) {
        $('body').append(htmlOutput);
        $('#' + pageName).page();
        $.mobile.changePage( $('#' + pageName) );
    }

On the controller side, the init method becomes much simpler than I had originally written:

/**
 * @class MyApp.Pages.Frontpage
 */
$.Controller('MyApp.Pages.Frontpage',
    /** @Static */
    {
        defaults : {
            itemsPerPage : 20,
            currentPage : 1
        },
        pluginName: 'frontpage'
    },
    /** @Prototype */
    {
        /**
         * Downloads and renders a full page of blog posts
         */
        init : function() {
            this.view = $.View("my_app/pages/views/frontpage.ejs", {
                items: MyApp.Models.BlogPost.findAll({
                    start : (this.options.currentPage-1)
                            * this.options.itemsPerPage,
                    count : this.options.itemsPerPage
                })
            });
        }
    }
); // End of controller

My full bootstrap method now looks like this:

function() {
    // intercept changePage events to inject our controllers as needed (dispatch)
    $(document).bind( "pagebeforechange", function( e, data ) {
        // we only handle url changes
        if ( typeof data.toPage === "string" ) {
            // We are being asked to load a page by URL
            var u = $.mobile.path.parseUrl( data.toPage ),
                re = /^\#([a-zA-Z]+)$/; // TODO $.route

            if (u.hash.search(re) !== -1 && $(u.hash).length == 0) {
                var pageName = re.exec(u.hash);
                pageName = pageName[1];
                if(pageName === 'splah') {
                    return false;
                }
                // ucwords - ignore as it will be replaced by using $.route
                controllerName = pageName.replace(/^([a-z])|\s+([a-z])/g, function (str) {
                    return str.toUpperCase();
                });
                if (typeof MyApp.Pages[controllerName] === 'function') {
                    var $instance = new MyApp.Pages[controllerName]($('body'));
                    $instance.view.done(function (htmlOutput){
                        // add the rendered output to the body (could also be done in the controllers instead)
                        $('body').append(htmlOutput);
                        $('#' + pageName).page(); // jQuery Mobile magic decoration
                        // passing an object skips the dispatch and just shows the page
                        $.mobile.changePage($('#' + pageName));
                    });
                    e.preventDefault();
                }
            }
        }
    });
    $('#splash').fadeIn(500);
    setTimeout(function () {
        $.mobile.changePage('#frontpage');
    }, 500);
});

I’ll flesh out the full updated integration when I get home, but i am now close to my ideal setup and my full app is working as expected from start to finish. Among my recent changes are the use of partials, routes, pagination, API service auth (with caveats) and of course testing and documentation.

Stay tuned!

10 Jan

PhoneGap + JavascriptMVC production build

Once you build your app and produce production.js and production.css (hopefully through an ant script like mine), you may notice that your app does not run once deployed with PhoneGap. This is because it seems the recommended way of bootstrapping your app in JMVC uses the script’s URI to specify the app name: “../steal/steal.production.js?myappname” which PhoneGap does not appear to support.

The simple workaround is to resort to this notation instead:

<script src="../steal/steal.production.js"></script>
<script>
    steal('myappname/production.js').then('myappname/myappname.js');
</script>

Now, your deployed assets will not contain myappname.js since you already built it into production.js. Once you load production.js you have essentially loaded all the javascript you told steal.build to package for you. Unfortunately, you need to remember that the build refers to your files from the perspective of the folder directly above your app, which means you need to load ‘myappname/myappname.js’ instead of ‘./myappname.js’.

These are minor issues and once you figure out the gotchas, it should be smooth sailing from there. I have divided my html into 2 files, one for development, and one for production. My Ant script now picks the right html to include as PhoneGap’s index.html depending on what I am building.

10 Jan

Javascript MVC + PhoneGap + jQm Build with Ant

In an effort to streamline the build of mobile applications, I made an ant build file to automate some of the tasks you would normally have to do to package your JMVC webapp and deploy it into an android project.

Here is the interesting parts of my build.xml file:

    <target name="build" description="Builds the app for production"  depends="">
        <exec executable="./js" dir="${src}/.." vmlauncher="no">
           <arg line="${src}/scripts/build.js" />
        </exec>
        <copy todir="${build}/steal">
            <fileset dir="${src}/../steal"/>
        </copy>
        <copy todir="${build}/${appName}/images">
            <fileset dir="${src}/images"/>
        </copy>
        <copy file="${src}/${appName}.html" tofile="${build}/${appName}/index.html"/>
        <replace file="${build}/${appName}/index.html" token="steal/steal.js" value="steal/steal.production.js" />
        <move file="${src}/production.css" tofile="${build}/${appName}/production.css"/>
        <move file="${src}/production.js" tofile="${build}/${appName}/production.js"/>
    </target>

I also have the clean phonegap android projects inside a folder called platforms/Android under my JMVC app folder. This project was updated to generate an ant build.xml file using this command from within the project folder:

android update project -p .

Finally I have a task that makes a copy of that Android project into my build folder copies the JMVC build into its assets/www folder and starts building the mobile app:

    <target name="android" description="Invokes a build on the android platform" depends="build">
        <copy todir="${build}/Android">
            <fileset dir="${src}/platforms/Android"/>
        </copy>
        <copy todir="${build}/Android/assets/www/steal">
            <fileset dir="${build}/steal"/>
        </copy>
        <copy todir="${build}/Android/assets/www/${appName}">
            <fileset dir="${build}/${appName}"/>
        </copy>
        <ant antfile="${build}/Android/build.xml" dir="${build}/Android" target="debug">
        </ant>
    </target>

This is not rocket science, but I thought it may be helpful to someone just starting out with a similar project.