“Pets Clinic” app using Go, Ember.js with Ember data, JSON API standard and MySQL.

Ember.js icons

Introduction

Despite the fact there are a lot of Javascript frameworks out there, today we will try to use Ember JS and Ember Data. As it is stated on their official website, “Ember.js is a framework for creating ambitious web applications”.

What we are going to build and how?

We are going to implement a simple application, named “Pets clinic”. It will keep records about pets and their visits to the veterinarian and their owner details. Basically, we will work with 2 models. One of them will be Pet model and the other one will be Visit model. In order to achieve better understanding of what we are doing, I will split this article into 3 parts. We will do them one by one.

Note: The code is available to download at github, please follow this link – https://github.com/atomate/pets-clinic-demo

Implementation flow

      Installing Go, workspace and database setup, revealing needed Go dependencies and tools we’re going to use.
      Implementing Go structs and API handler.
      Implementing Ember JS client.

First of all, make sure you have Go installed on your local machine. If you don’t, please follow this guide to install it. The next step is setting up the workspace. Let’s admit that you have a folder called ‘Projects’ in your home directory. If not, please create it. `cd` into this folder and create a new folder, called ‘clinic-api’. Then, following conventions from this article, create this folders: src, pkg and bin. If you read that article, you already know why we need them. Now the workspace is ready. We can move on to creating the database and the database tables. Create a MySQL database named `pets_clinic`. This database will have 2 tables: ‘pet’ and ‘visit’. The create syntax for `pet` table is below:

CREATE TABLE `pet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`owner_name` varchar(255) NOT NULL DEFAULT '',
`owner_phone` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

And the syntax for `visit` table below:

CREATE TABLE `visit` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pet_id` int(11) NOT NULL,
`result` varchar(255) NOT NULL DEFAULT '',
`time` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk` (`pet_id`),
CONSTRAINT `fk` FOREIGN KEY (`pet_id`) REFERENCES `pet` (`id`) ON DELETE
CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

As you might noticed, there is a relationship between tables. We will reflect this in the code later.Now we have our database ready.

Let’s see what libraries and tools we are going to use in order to build the app.

  • JSONAPI standard conventions. More about JSONAPI here.
  • jsonapi library for the Go language. Basically, what this library does is serializing/deserializing json payloads that comply with JSONAPI standard.
  • Beego ORM. Beego ORM is a powerful ORM framework in Go. It’s inspired by Django ORM and SQLAlchemy.
  • mux package. Package gorilla/mux implements a request router and dispatcher.
  • Twitter Bootstrap UI framework.
  • ember-data. A data persistence library for Ember JS.
  • ember-cli. A command line tool for Ember JS;

Good. Now we know what tools we will use next.

Before we proceed to writing code, let’s think about API endpoints we want to implement. I’ve made a table with the endpoints I think are relevant for the application.

Method URL Description Data
POST /api/v1/pets Creates a new Pet Pet object
GET /api/v1/pets/{id} Retrieves a pet Nothing
GET /api/v1/pets Retrieves all Pets Nothing*
DELETE /api/v1/pets/{id} Deletes a Pet Nothing
PATCH /api/v1/pets/{id} Updates a Pet Pet object
POST /api/v1/visits Create a visit Visit object
DELETE /api/v1/visits/{id} Deletes a Visit Nothing

That’s it. By doing this, we have a better understanding of what we need to implement and what our application will be able to do. I think we’re done with first step from our flow. Let’s grab a coffee and move on.

Coding time. Move into the ‘src’ folder from the root of the app and create new folder, called ‘api’. Here we will store all application related files, excluding the app.go file. So, ’touch app.go && mkdir api && cd api’ should do the job. While you’re in the ‘api’ folder, create a new file called ‘models.go’, open it and add this code:

package api
// Pet "model"
type Pet struct {
    Id int `jsonapi:"primary,pets"`
    Name string `jsonapi:"attr,name"`
    OwnerName string `jsonapi:"attr,owner-name"`
    Visits []*Visit `jsonapi:"relation, visit" orm:"reverse(many)" `
    OwnerPhone string `jsonapi:"attr,owner-phone"`
}
// Visit "model"
type Visit struct {
    Id int `jsonapi:"primary,visits"`
    Pet *Pet `jsonapi:"relation,pet" orm:"column(pet_id);rel(fk)"`
    Time int `jsonapi:"attr,visit-date"`
    Result string `jsonapi:"attr,result"`
}

In order to actually be able use this types, we need a database handler, that will create, read, update and delete database records from them. Create a new file called ‘db_handler.go’ and add the following code:

package api
//
import (
    "fmt"
    "github.com/astaxie/beego/orm"
    _ "github.com/go-sql-driver/mysql"
)

func init() {
    orm.RegisterDriver("mysql", orm.DR_MySQL)
    orm.RegisterDataBase("default", "mysql", "root:pass@/pets-clinic?charset=utf8")
    orm.RegisterModel(new(Pet), new(Visit))
}

func CreatePet(pet *Pet) {
    id, err := orm.NewOrm().Insert(pet)
    if err == nil {
        fmt.Println(id)
    }
}

func ReadPet(pet *Pet) *Pet{
    o := orm.NewOrm();
    o.Read(pet);
    o.LoadRelated(pet, "Visits")
    return pet;
}

func UpdatePet(pet *Pet) {
    if num, err := orm.NewOrm().Update(pet); err == nil {
        fmt.Println(num)
    }
}
//
func DeletePet(pet *Pet) {
    if num, err := orm.NewOrm().Delete(pet); err == nil {
        fmt.Println(num)
    }
}
//
func ReadPetsList() []interface{} {
    var pets []Pet
    all, err := orm.NewOrm().QueryTable("pet").All(&pets)
    fmt.Printf("Returned Rows Num: %s, %s", all, err)
    result := make([]interface{}, len(pets))
    for i, s := range pets {
        r := s;
        result[i] = &r
    }
    return result;
}

These are the functions that work with Pet type. Reading their names, it’s clear what each functions does. Now let’s implement the same things for the Visit type.

func CreateVisit(visit *Visit) {
	id, err := orm.NewOrm().Insert(visit)
	if err == nil {
		fmt.Println(id)
	}
}

func ReadVisit(visit *Visit) *Visit{
	o := orm.NewOrm();
	o.Read(visit);
	o.LoadRelated(visit, "Pet")
	return pet;
}

func DeleteVisit(visit *Visit) {
	if num, err := orm.NewOrm().Delete(visit); err == nil {
		fmt.Println(num)
	}
}

So this is the code we need for the ‘database handler’. It’s now ready to be used and we will use it in order to implement the last part of the API. The next thing we need is a handler for the HTTP request our API will receive. Please create a new file named ‘api_handler.go’ into the ‘api’ directory and open it.
This is the code for the file:

package api

import (
	"fmt"
       "strconv"
	"github.com/shwoodard/jsonapi"
       "github.com/gorilla/mux"
	"net/http"
)

func AllPets(w http.ResponseWriter, r *http.Request) {
	jsonapiRuntime := jsonapi.NewRuntime().Instrument("/")
	w.WriteHeader(200)
	w.Header().Set("Content-Type", "application/vnd.api+json")
	pets := ReadPetsList()
	if err := jsonapiRuntime.MarshalManyPayload(w, pets); err != nil {
		http.Error(w, err.Error(), 500)
	}
}

func OnePet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, err := strconv.Atoi(vars["id"])
	if err != nil {
		fmt.Println("Invalid pet id")
		return
	}
	pet := ReadPet(&Pet{Id: id})
	w.WriteHeader(200)
	w.Header().Set("Content-Type", "application/vnd.api+json")
	if err := jsonapiRuntime.MarshalOnePayload(w, pet); err != nil {
		http.Error(w, err.Error(), 500)
	}
}

func NewPet(w http.ResponseWriter, r *http.Request) {
	jsonapiRuntime := jsonapi.NewRuntime().Instrument("/")
	pet := new(Pet)
	if err := jsonapiRuntime.UnmarshalPayload(r.Body, pet); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	CreatePet(pet)
	if err := jsonapiRuntime.MarshalOnePayload(w, pet); err != nil {
		http.Error(w, err.Error(), 500)
	}
	w.WriteHeader(201)
	w.Header().Set("Content-Type", "application/vnd.api+json")
}


func ModifyPet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, err := strconv.Atoi(vars["id"])
	if err != nil {
		fmt.Println("Invalid pet id")
		return
	}
	pet := ReadPet(&Pet{Id: id})
       if err := jsonapiRuntime.UnmarshalPayload(r.Body, pet); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	UpdatePet(pet)
	if err := jsonapiRuntime.MarshalOnePayload(w, pet); err != nil {
		http.Error(w, err.Error(), 500)
	}
	w.WriteHeader(201)
	w.Header().Set("Content-Type", "application/vnd.api+json")
}

func RemovePet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, err := strconv.Atoi(vars["id"])
	if err != nil {
		fmt.Println("Invalid pet id")
		return
	}
	pet := ReadPet(&Pet{Id: id})
	DeletePet(pet)
	w.WriteHeader(201)
	w.Header().Set("Content-Type", "application/vnd.api+json")
}

func NewVisit(w http.ResponseWriter, r *http.Request) {
	jsonapiRuntime := jsonapi.NewRuntime().Instrument("/")
	visit := new(Visit)
	if err := jsonapiRuntime.UnmarshalPayload(r.Body, visit); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	CreateVisit(visit)
	w.WriteHeader(201)
	w.Header().Set("Content-Type", "application/vnd.api+json")
}

func RemoveVisit(w http.ResponseWriter, r *http.Request) {
	jsonapiRuntime := jsonapi.NewRuntime().Instrument("/")
	visit := new(Visit)
	if err := jsonapiRuntime.UnmarshalPayload(r.Body, pet); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	DeleteVisit(visit)
	w.WriteHeader(201)
	w.Header().Set("Content-Type", "application/vnd.api+json")
}

Now, the only thing we need to do in order to get done the API part, is implementing the main application file. Remember that ‘app.go’ file we created at the beginning ? Now we will use it. Please go to ‘src’ folder and open the ‘app.go’ file, then add this code :

package main

import (
	"api"
       "net/http"
       "github.com/gorilla/mux"
)

func main() {
	rtr := mux.NewRouter()
	rtr.HandleFunc("/api/v1/pets", api.AllPets).Methods("GET")
	rtr.HandleFunc("/api/v1/pets/{id}", api.OnePet).Methods("GET")
	rtr.HandleFunc("/api/v1/pets", api.NewPet).Methods("POST")
	rtr.HandleFunc("/api/v1/pets/{id}", api.ModifyPet).Methods("PATCH")
	rtr.HandleFunc("/api/v1/pets/{id}", api.RemovePet).Methods("DELETE")
	rtr.HandleFunc("/api/v1/visits", api.NewVisit).Methods("POST")
	rtr.HandleFunc("/api/v1/visits", api.RemoveVisit).Methods("DELETE")
	http.Handle("/", rtr)
	http.ListenAndServe(":8080", nil)
}

Finish! We’ve implemented all the code needed for the API. Now let’s build, install and run it. Go to the ‘src’ folder and run ‘go get api’ command. As you might already know, this will download and install all the dependencies we have imported earlier right after we declared the package name. After this command, we need to run ‘go install api’ and then ‘go run app.go’. This will start our application.

Now it’s time for Ember JS!

Ok, got another cup of coffee ? If yes, we’re ready to start the next part, that will be creating the client for the API. As we already now, we will do it using Ember JS and Ember Data. There are a lot of things that can be told about Ember, despite the fact that the framework is not so old. It started in 2011, but it is already used by companies like Square, Yahoo, Groupon etc. Here, at Atomate, we’ve used Ember JS only once, but for me, as a team member, it was a really cool experience. So let’s see it in action.

As we have said before, we will use ember-cli tool. The first line on their official site says: “Ember CLI is the Ember.js command line utility that provides a fast Broccoli-powered asset pipeline, a strong conventional project structure, and a powerful addon system for extension.” We need this tool for creating and managing our app components. Please install it following this guide.

Now let’s move into the ‘Projects’ folder and run the ‘ember new clinic-client’ command. It will create a new folder with all the files required for a ember application. First time it might take some time, as it downloads all the dependencies. Please be patient.

Before we start coding again, let’s define another workflow, this time for implementing the API client. This will help us, as we said before, understand better what and most important, why we’re doing things we are going to do. So, our workflow for the API client development:

  • Implementing models (Pet and Visit)
  • Implementing routes
  • Implementing adapter
  • Integrate templates
  • Implementing controllers

We will start with the Pet model. Enter the newly created ‘clinic-client’ folder and run ‘ember generate model pet’ command. It will generate all the file needed for the Pet model. It will also generate tests file. The pet.js file will be located at ‘app/models’ and will already have some boiler template code in there as shown below:

import DS from 'ember-data';

export default DS.Model.extend({
  
});

As you can see, we are already using ember-data library. Now we must add fields for the Pet model. We should reflect the ‘model’ we’ve created in Go. After adding those fields, the code will look like this:

import DS from 'ember-data';

export default DS.Model.extend({
    name:       DS.attr('string'),
    ownerName:  DS.attr('string'),
    ownerPhone: DS.attr('string'),
    visits:     DS.hasMany('visit')
});

The next one is Visit model. Again, we should run the ‘ember generate model visit’ command. This will create the visit.js file in the same folder as pet.js file. Open it and add the following lines of code:

import DS from 'ember-data';

export default DS.Model.extend({
    pet:    DS.belongsTo('pet'),
   visitDate: DS.attr('number', {
        defaultValue() { return Math.floor(Date.now() / 1000);}
    }),
    result: DS.attr('string')
});

Now, we’re done with the first part of the workflow. We have our models ready to be used. The next thing on our list is implementing the routes. Like we did with endpoints, I think it’s a good idea to illustrate the routes we will need via a simple table. The table is below:

Method URL
/pets Lists all pets
/pets/pet/{id} Info about a particular pet
/pets/add Add Pet form
/pets/edit/{id} Edit a Pet

>

We should start with the first route. ’ember generate route pets/index’ will help us and will generate all the files needed. Run this command and see the output. It says that ember-cli created the route and the templates file. Also, it updated the router.js file from the ‘app’ directory and added some basic tests for the newly created route. Go to ‘app/routes/pets’ folder and open the index file. As we can see, it’s just a simple template ember-cli creates by default :

import Ember from 'ember';

export default Ember.Route.extend({
});

Not too much code, right ? The thing is, here the magic begins. In order to be able to parse all the pets records from the database we just need to add one function, with one line body. So go ahead and add the ‘model’ function into this route. Our final code will be :

import Ember from 'ember';
export default Ember.Route.extend({
    model: function(){
        return this.store.findAll('pet');
    }
});

That’s all. Let’s quickly create the other routes we need and the next one is ‘pet/add’, that can be created using ‘ember generate route pets/add’. Then ‘ember generate route pets/edit’ and ‘ember generate route pets/pet’ for the remaining two routes. The last three routes also need a model function, so let’s define them one by one. Open ‘app/routes/pets/add.js’ file and add the following method:

model: function(){
        return this.store.createRecord('pet');
}

Here, when we want to create the ‘model’ function for the ‘pet’ and ‘edit’ routes, another magic happen. We don’t need to define them. Ember JS is smart enough to know what model to return if we pass to the route the object ID. But where do we specify this ID and how ? We do this in the ‘app/router.js’ file. Open it and you should see this:

import Ember from 'ember';
import config from './config/environment';

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.route('pets', function() {
    this.route('add');
    this.route('edit');
    this.route('pet');
  });
});

export default Router;

We should modify this code a bit and add additional parameters for the ‘edit’ and ‘pet’ route. Please modify the highlighted code in order to look like below:

Router.map(function() {
  this.route('pets', function() {
    this.route('add');
    this.route('edit', { path: 'edit/:pet_id' });
    this.route('pet', { path: 'edit/:pet_id' });
  });
});

Ok, that’s all with the routes. Now it’s time to implement our adapter. Third step from our last flow. Run ‘ember generate adapter application’ command and it will create a new file called ‘application.js’ into the ‘app/adapters’ folder. Please open it and replace existing code with the one below:

import DS from 'ember-data';

export default DS.JSONAPIAdapter.extend({
    namespace: 'api/v1'
});

Good, we’re done with the adapter and now it’s time to actually render and see something in the browser window. Next, we will implement some HTML code in order to render things properly. But before we start, let’s just start our Ember application by running ’ember serve –proxy http://localhost:8080′. We are using the proxy parameter because the API that the app will make HTTP requests to is running on port 8080 and Ember will proxy all requests there. The output for this command is :

Proxying to http://localhost:8080
Livereload server on http://localhost:49152
Serving on http://localhost:4200/

This means that the API calls will be made to http://localhost:8080 and the Ember app is running on port 4200. Open the http://localhost:4200 page in your favorite browser. It should show “Ember to Ember” text. If you see it, that’s great, we are on the same page. Moving to http://localhost:4200 page will result in seeing a blank white page. This means it’s time to write integrate the templates. We will start by including Twitter Bootstrap library in the index.html file from the ‘app’ folder. Next, open the ‘app/templates/application.hbs’ file and replace existing code with the code below:

<body>
  <div class="container">
    <div class="row">
      <div class="col-md-12 header" style="margin-top: 10px;">
          <img src="https://cdn4.iconfinder.com/data/icons/small-n-flat/24/cat-alt-64.png">
      </div>
    </div>
    <hr>
    <div class="row">
      {{outlet}}
    </div>
  </div>
</body>

Then, let’s move on to the ‘app/templates/pets/index.hbs’ and add the following code:

<div class="col-md-12">
    <ul>
        <li>
            {{#link-to 'pets.add'}}Add new pet{{/link-to}}
        </li>
    </ul>
    <div class="table-responsive">
      <table class="table">
          <thead>
              <tr>
                  <td>  ID </td>
                  <td>  Pet name </td>
                  <td>  Owner name/phone </td>
                  <td>  Actions  </td>
              </tr>
          </thead>
          <tbody>
              {{#each model as |pet|}}
                <tr>
                    <td> {{pet.id}} </td>
                    <td> {{#link-to 'pets.pet' pet}} {{pet.name}}  {{/link-to}}</td>
                    <td> {{pet.ownerName}} / {{pet.ownerPhone}} </td>
                    <td> {{#link-to 'pets.edit' pet}}Edit{{/link-to}} </td>
                </tr>
              {{/each}}
          </tbody>
      </table>
    </div>
</div>

After saving this file and going to http://localhost:4200 we should get the following result:

Ember.js screenshot 1

We can see the app logo we put in the ‘application.hbs’ file, then we can see the table we just added into the ‘app/templates/pets/index.hbs’ template. But why there are no records in the table ? That’s because we don’t actually have any records in our database. So the next step will be adding the templates code for the ‘app/templates/pets/add.hbs’ file. Open it and add this code:

<div class="col-md-12">
  <h4 class='form-label'><b>Add new pet</b></h4>
  <form role="form" id="addPetForm">
    <div class="form-group">
      <label for="name">Name:</label>
      {{input class="form-control" id="name" value=model.name}}
    </div>
    <div class="form-group">
      <label for="owner_name">Owner name:</label>
       {{input class="form-control" id="ownerName" value=model.ownerName}}
    </div>
    <div class="form-group">
      <label for="owner_phone">Owner phone:</label>
       {{input class="form-control" id="ownerPhone" value=model.ownerPhone}}
    </div>
    <button type="submit" class="btn btn-default" {{action 'savePet'}}>Submit</button>
  </form>
</div>

Save the file and go to http://localhost:4200 . We should get this form rendered:

Ember.js screenshot 2

Edit form will look the same, we just need to replace “Add new pet” with “Edit pet” and change the action for the ‘Submit’ button to ‘editPet’. Please make the changes and add the code to ‘app/templates/edit.hbs’ file. And finally, the code for the ‘app/templates/pets/pet.hbs’ file is:

<div class="col-md-12">
        <div class="info">
                <h4>You are browsing <b>{{model.name}}'s file</b></h4>
                <ul>
                    <li>Name: <b>{{model.name}}</b></li>
                    <li>Owner name: <b>{{model.ownerName}}</b></li>
                    <li>Owner phone: <b>{{model.ownerPhone}}</b></li>
                </ul>
                <h4><b>{{model.name}}</b> visits history</h4>
                <ul>
                    {{#each model.visits as |visit|}}
                      <li>Visited on {{visit.visitDate}}. Result: <b>{{visit.result}}</b></li>
                    {{/each}}
                </ul>
        </div>
</div>

That’s all what needs to be done with templates. Of course, templates can be much more improved, but this article isn’t about this. It’s time to implement controllers, because the actions we’ve defined for the buttons and links will be placed there.

In order to add a pet, we will need to fill the form from the ‘pets/add’ templates and click the ‘Submit’ button. Now, nothing will happen if we click it, so we need to add a method in our controller ‘app/controllers/pets/add.js’.

Before we could add code, we need to create it. Run ‘ember generate controller pets/add’, then open it and add the following code:

import Ember from 'ember';

export default Ember.Controller.extend({
    actions: {
        savePet: function(){
            this.get('model').save().then(pet => this.transitionToRoute('pets.pet', pet));
        }
    }
});

Now, once we fill the ‘Add new pet’ form and click submit button, the application will save the object locally, in the local storage, then will send a POST request to the API and after it gets a success response, it will redirect us to the pet’s page. Also, the newly created record will show up in the table when going back to pets list. After we are done with this, it’s time to add the form for creating a visit. We will do it on the page what allows us to view one particular pet information.

<div class="col-md-4">
   <h4>Add a new visit</h4>
   <form>
      <div class="form-group">
         <label for="name">Result:</label>
         {{textarea class="form-control" id="name" value=model.visit.result}}
      </div>
      <button type="submit" class="btn btn-default" 
      {{action 'addVisit'}}> Add
      </button>
   </form>
</div>

This form will add a visit, but before we test it, let’s define the ‘addVisit’ method we’ve specified as an action for the ‘Add’ button. Create a new controller for the ‘pets/pet’ router with ‘ember generate controller pets/pet’ command and open the fresh file this command just created. Add the following code:

import Ember from 'ember';

export default Ember.Controller.extend({
    visit: function(){
            return this.store.createRecord('visit');
    }.property(),
    actions: {
        addVisit: function(){
this.get('visit')
.set('pet',this.store.peekRecord('pet', this.get('model').get('id')))
.save();

        }
    }
});

After clicking the ‘Add’ button, the visit record will automatically be added to the visits list. Let’s see this in action.

The next thing we need to implement is delete pet functionality and we will do it by adding a button with an ‘deletePet’ action to it. This is the HTML code we need to add right after the ‘ul’ tag where we’re showing the Pet information.

<button type="submit" class="btn btn-danger" {{action 'deletePet'}}>Delete</button>

And the action method code is as follows:

deletePet: function(){
        this.store.findRecord('pet', this.get('model').get('id')).then(
            pet => pet.destroyRecord();
        );
        this.transitionToRoute('pets.index');
}

This will remove the record from the local storage, then it will send a DELETE request to the API and finally it will redirect the user to the pets list page. And now, the final thing we need to do is to implement a way to edit pet information. For this, we need to add a method to the ‘pets/edit’ controller we will create. Run the ’ember generate ember controller pets/edit’ command, then open the new file from the ‘app/controllers/pets’ and add the following code:

import Ember from 'ember';

export default Ember.Controller.extend({
    actions: {
        editPet: function(){
            this.get('model').save().then(pet => alert(pet.get("name") + " info updated."));
        }
    }
});

That’s it. This is the only code we need in order to update a pet model.

Below is an demonstration of how it works. First, we create a pet, then we add a visit for it, then we edit pet’s owner name.

That’s all for this time. Of course there are a lot of improvements and refactoring that can be done, so please feel free to improve this code.

Commenting and criticising (but not too much please, as my boss probably will read it too :)) is welcome.

Note: The code is available to download at github, please follow this link – https://github.com/atomate/pets-clinic-demo

Conclusion

In our days, it’s very hard to imagine a web-app without using Javascript. There are a lot of frameworks and tools for implementing quick and robust web application with Javascript and Ember JS is one of them. One of the main good part of Ember is convention over configuration. This means that instead of writing a lot of boilerplate code, Ember can automatically infer much of the configuration itself, such as automatically determining the name of the route and the controller when defining a router resource. Ember even raises the bar by automatically creating the controller for your resource if you don’t define one yourself. Also, it includes both an excellent router and an optional data layer, called ember data, that we have used in our project. However, there is a part I don’t like about Ember. Ember’s API suffered too much changes before it stabilized. Because of this, there are a lot of resources and articles on the internet, that are outdated and just don’t work. This is becoming a very big problem for the new developers, once they decided to start with Ember JS. Most of them, give up, but I really advise you to not to do so.

What about Go ? Go is a relatively new language that is in constant development but it already has a considerable amount of industry support and is used in real systems at Google, Dropbox and others. As it is stated of their documentation page, “Go is expressive, concise, clean, and efficient. Its concurrency mechanisms make it easy to write programs that get the most out of multicore and networked machines, while its novel type system enables flexible and modular program construction. Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection. It’s a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language.” But enough reading, here is a really interesting and cool talk from GopherCon by Robert Griesemer from Google, that perfectly illustrates the evolution of Go programming language:

Leave a comment

3 Comments

  1. hi, great tutorial, trying it out. When compiling, I found that in some cases, I had to change “jsonapiRuntime” to just “jsonapi” and then it compiled. I found this by looking at docs for google/jsonapi, but it’s still not clear to me why in some cases, jsonapiRuntime is still the correct thing to do. Can you help me understand this?

    1. figured it out, you omitted this line in a couple of functions:

      jsonapiRuntime := jsonapi.NewRuntime().Instrument(“/”)