Thursday, September 4, 2014

Example of Beegae - Part 3

Now we're finally getting to the code. This app maintains a list of names, so naturally I made a struct called "Name". Here is models/model.go:

  // model
package models

import (
    "appengine"
    "appengine/datastore"
)

type Name struct {
    FirstName, LastName string
}

const COLLECTION = "name"

func (this Name) String() string {
    return this.FirstName + " " + this.LastName
}

func (name Name) GetMatchCount(c appengine.Context) (count int, err error) {
    //    c := appengine.NewContext(rq)
    q := datastore.NewQuery(COLLECTION).Filter("FirstName =", name.FirstName).
        Filter("LastName =", name.LastName)
    var results []Name
    _, err = q.GetAll(c, &results)
    if err != nil {
        count = -1
    } else {
        count = len(results)
    }
    return
}

func (this Name) Add(c appengine.Context) error {
    key := datastore.NewIncompleteKey(c, COLLECTION, nil)
    _, err := datastore.Put(c, key, &this)
    return err
}

func GetAllNames(c appengine.Context) (names []Name, err error) {
    q := datastore.NewQuery(COLLECTION)
    _, err = q.GetAll(c, &names)
    return
}

As you can see, I'm using Datastore. The COLLECTION constant sets the data type string. The GetMatchCount function queries the database for names matching the incoming name, then calculates the number of matches and returns the total. The GetAll API function retrieves all of the documents matching the query. NewIncompleteKey generates a document key. Lastly, the String function tells Go how to convert a Name to a string. We will see how that is used soon. The Contexts determine which database gets accessed. 

Now we'll get to the controllers. Here is controllers/default.go:

package controllers
import (
    "fmt"
    "github.com/astaxie/beegae"
    "log"
    "models"
)

type MainController struct {
    beegae.Controller
}

func (this *MainController) Get() {
    this.Data["Title"] = "Beegae Example #1"
    this.TplNames = "form.tpl"
}

type VerifyController MainController

func (this *VerifyController) Post() {
    context := this.AppEngineCtx
    first := this.GetString("first")
    last := this.GetString("last")
    name := models.Name{first, last}
    count, err := name.GetMatchCount(context)
    message := fmt.Sprintf("%s %d", name, count)
    if err != nil {
        message = err.Error()
    }
    if count == 0 {
        if err := name.Add(context); err != nil {
            message = err.Error()
        }
    }
    this.Data["Title"] = "Beegae Example #1"
    this.Data["Message"] = message
    this.TplNames = "verify.tpl"
}

type ListController struct {
    beegae.Controller
}

func (this *ListController) Get() {
    context := this.AppEngineCtx
    //    var names []models.Name
    names, err := models.GetAllNames(context)
    if err != nil {
        log.Fatal(err.Error())\
    }
    this.Data["Title"] = "Beegae Example #1"
    this.Data["Names"] = names
    this.TplNames = "list.tpl"
}

GetString retrieves the form variable with the given name and casts it as a string. As you can see, the Sprintf function refers to a variable of type "Name" as a string. models.String tells Go how to implicitly cast that structure. In Beegae, constructors are actually types, which are used as receivers for the appropriate REST function. 
The views are pretty much trivial except for list.tpl. Here that is:

  
<!DOCTYPE html>

<html>
      <head>
        <title>{{.Title}}</title>
        <link rel="stylesheet" href="/static/css/style.css" type="text/css" />

    </head>
    <body>
        <h3>Updated List</h3>
        <ul>
            {{range $v := .Names}}
                <li>{{$v}}</li>
            {{end}}
        </ul>
    </body>
</html>        

The "range" keyword loops through the list of names and assigns each entry in turn to $v. As you can see, the data is treated like a string. The routing is fairly simple:

package routers
import (
    "beegaenames/controllers"
    "github.com/astaxie/beegae"
)

func init() {
    beegae.Router("/", &controllers.MainController{})
    beegae.Router("/verify", &controllers.VerifyController{})
    beegae.Router("/list", &controllers.ListController{})
}

That is routers/myrouter.go. Each Router has a URL and a variable. As you saw in earlier code, those variables are usually structs that contain a member of type beegae.Controller. The last thing we'll look at is how I deployed this app.

Friday, August 29, 2014

Example of Beegae - Part 2

The next step was to establish and configure my project. Before we get into that, I wanted a couple of Go packages to make things easier, namely github.com/astaxie/beego and github.com/beego/bee. I compiled the second package into the "bee" command.
I already had a directory in my root called "goprojects2". I created a "src" subdirectory. Then I went into the SDK command prompt and issued:

set gopath=%gopath%;c:\goprojects2

then went to the goprpjects2 directory and entered

bee new beegaenames

The "bee" command created a scaffold for my project. However, I had to convert the project from Beego to Beegae. I went into main.go (in goprojects2/src/beegaenames), and replaced "beego" with "beegae" .  I also went into controllers/default.go and routers/router.go, replacing "beego" with "beegae".
I needed to do one last thing before writing Go, namely create index.yaml on the same level as main.go. This file indexed my database. Here are the contents:

indexes:

- kind: Name
  ancestor: no
  properties:
  - name: FirstName
    direction: asc
  - name: LastName
    direction: asc

In the next installment, we'll get into the actual code.

Tuesday, August 26, 2014

Example of Beegae (Beego for App Engine) - Part 1

Sorry I've been gone for so long! I recently created a simple web form using Beegae. The setup was rather involved, but worth it. I will assume you have Git and Python 2.x already installed. I needed to install Go (http://golang.org/) and Google Cloud SDK (https://cloud.google.com/developers/ ; click "Download the SDK" for instructions). I used Datastore, the original NoSQL native to App Engine.

The next thing I had to do was install the Go SDK. To to that, I went into the Google Cloud SDK console window, and issued

gcloud components update gae-go

If you're using the Windows version, there might be a bug in goapp.bat. You will probably find it at

C:\Program Files\Google\Cloud SDK\google-cloud-sdk\platform\google_appengine

I issued the following to retrieve the Beegae Go package:

goapp get github.com/astaxie/beegae

and got this error...

'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

I fixed the problem by these steps:

  1. Open Notepad as Administrator
  2. Open goapp.bat
  3. Put the %GOROOT%\bin\%EXENAME% line, along with all the parameters, on a new line
  4. Put quotation marks (") around %GOROOT%\bin\%EXENAME%
  5. Save (make sure NOT as a .TXT file) and Exit
If you're a bit squeamish, Copy goapp.bat as goapp.bat.old first. I reissued the above "goapp" command, and this time it ran. In the next installment, I'll get into how I configured this project.



Monday, February 10, 2014

After a long "vacation"...

Hi all!

I'm sorry I left you all in the lurch. I have been busy writing code, and you can see some of it at https://github.com/ozonesurfer . As a warning, Tiedot is a work in progress, and if you try to use my current code with Tiedot 2.0, it won't work.

That being said, I thought I would put my  2 cents in on some of the current "wars of religion". Like Tiedot, the tech world is in transition. Transitions are messy things; you have to phase the old out gracefully, and allow the new to mature. People are ditching their landlines for cell phones. People now text instead of call, and e-mail/post instead of writing letters. I'm not going to say one set of technology is better than others. They're just different, each with their benefits and flaws.

As for what I've seen, one of my friends bought a Chromebook and a Windows Phone, and she's perfectly happy with both. Another friend feels incapable of using Windows. She has an old iMac, and plans to eventually get a new one.

 As for me, I bought this Vista HP laptop in 2009; now I use Windows 8.1 on the same machine. My only real problem is my graphics chips sometimes struggle with video. And yes, I once used Windows 7 too. The only real complaint I have with Windows 8.x is the lack of built-in instructions. Despite that shortcoming, I leveraged my knowledge of previous versions and my brains to figure out how to use it. I demoed this knowledge to a couple friends, and not only did they love what they saw, one experimented in front of me and we learned more features together... another later bought a Windows 8 phone.

I consider Windows 8.x as a product of the transition from computers as they were once known to tablets/smartphones. You can't please everyone, but programmers (like me) are stuck with having to try. Some people think change is bad (or at least too inconvenient), and others think change doesn't happen fast enough. I just work with what's available, and I try to keep an open mind to the new.

I think that's embodied in my current software stack: Windows, document-based NoSQL, and Go. I can hear you say "Whrere is the web server? What? No Apache?".  As for Apache or IIS, with Go I don't really need them. The Go framework comes with the "net/http" package, which has the ListenAndServe function. I can specify any web address/port I have permission to manipulate as a parameter.

I'm not saying LAMP is bad or useless. If you know what you're doing, it gets the job done. And yes, I've used JavaScript (namely jQuery) in Go websites. And with Gorilla's websockets, I can broadcast user input in a chatroom website, or even manipulate my websites using the command line. If anyone knows how to do the latter using something else, I'd love to read that code. However, the command line will have to be read, and the entered data be used by the website,while the website is running...no cheating! E-mail it to me at ross.albertson@yahoo.com.      

I haven't seen screenshots of Windows 8.1 Update, but I'm not freaking out about it. I figured out how to use 8.0 and 8.1, and with God's help I'll learn the next version. And I'm not married to Go. I plan to learn Java 8 (or try to) fairly soon. If you stop learning, you stop growing as a person. Besides, to me a technological occupation means signing up to be a professional student to some degree. One last thing... one's belief in a higher power is sacred, but no technology is... if something you created can't be changed, it's broken.