Saturday, May 18, 2024
HomeGolangPattern Net Software Utilizing Beego and Mgo

Pattern Net Software Utilizing Beego and Mgo


Introduction
I’m very excited concerning the Beego net framework. I wished to share with you the way I exploit the framework to construct actual world websites and net providers. Here’s a image of the pattern web site the submit goes to showcase:

The pattern net utility:

  1. Implements a standard grid view of information calling into MongoDB
  2. Supplies a modal dialog field to view particulars utilizing a partial view to generate the HTML
  3. Implements an online service that returns a JSON doc
  4. Takes configuration parameters from the atmosphere utilizing envconfig
  5. Implements assessments by way of goconvey
  6. Leverages my logging package deal

The code for the pattern might be discovered within the GoingGo repository up on Github:
https://github.com/goinggo/beego-mgo

You may carry the code down and run it. It makes use of a public MongoDB database I created at MongoLab. You have to git and bazaar put in in your system earlier than working go get.

go get github.com/goinggo/beego-mgo

To shortly run or check the online utility, use the scripts situated within the zscripts folder.

Net Software Code Construction
Let’s check out the venture construction and the totally different folders that exist:

controllers Entry level for every Net name. Controllers course of the requests.
localize Supplies localization help for various languages and cultures
fashions Fashions are information buildings utilized by the enterprise and repair layers
routes Mappings between URL’s and the controller code that handles these calls.
providers Providers present primitive capabilities for the totally different providers that exist. These may very well be database or net calls that carry out a particular operate.
static Useful resource information equivalent to scripts, stylesheets and pictures
check Assessments that may be run by means of the go check software.
utilities Code that helps the online utility. Boilerplate and abstraction layers for accessing the database and dealing with panics.
views Code associated to rendering views
zscripts Assist scripts to assist make it simpler to construct, run and check the online utility

Controllers, Fashions and Providers
These layers make up the majority of the code that implement the online utility. The thought behind the framework is to cover and summary as a lot boilerplate code as attainable. That is achieved by implementing a base controller package deal and a base providers package deal.

Base Controller Package deal
The bottom controller package deal makes use of composition to summary default controller conduct required by all controllers:

sort (
    BaseController struct {
        beego.Controller
        providers.Service
    }
)

func (this *BaseController) Put together() {
    this.UserId = this.GetString(“userId”)
    if this.UserId == “” {
        this.UserId = this.GetString(“:userId”)
    }

    err := this.Service.Put together()
    if err != nil {
        this.ServeError(err)
        return
    }
}

func (this *BaseController) End() {
    defer func() {
        if this.MongoSession != nil {
            mongo.CloseSession(this.UserId, this.MongoSession)
            this.MongoSession = nil
        }
    }()
}

A brand new sort known as BaseController is asserted with the Beego Controller sort and the bottom Service sort embedded straight. This composes the fields and strategies of those sorts straight into the BaseController sort and makes them straight accessible by means of an object of the BaseController sort.

Beego Controller framework will execute the Put together and End capabilities on any Controller object that implements these interfaces. The Put together operate is executed previous to the Controller operate being known as. These capabilities will belong to each Controller sort by default, permitting this boilerplate code to be applied as soon as.

Providers Package deal
The Service package deal maintains state and implements boilerplate code required by all providers:

sort (
    // Providers comprises widespread properties
    Service struct {
        MongoSession *mgo.Session
        UserId string
    }
)

func (this *Service) Put together() (err error) {
    this.MongoSession, err = mongo.CopyMonotonicSession(this.UserId)
    if err != nil {
        return err
    }

    return err
}

func (this *Service) End() (err error) {
    defer helper.CatchPanic(&err, this.UserId, “Service.End”)

    if this.MongoSession != nil {
        mongo.CloseSession(this.UserId, this.MongoSession)
        this.MongoSession = nil
    }

    return err
}

func (this *Service) DBAction(databaseName string, collectionName string, mongoCall mongo.MongoCall) (err error) {
    return mongo.Execute(this.UserId, this.MongoSession, databaseName, collectionName, mongoCall)
}

Within the Service sort, the Mongo session and the id of the person is maintained. This model of Put together handles making a MongoDB session to be used. End closes the session which releases the underlying connection again into the pool.  The operate DBAction supplies an abstraction layer for working MongoDB instructions and queries.

Buoy Service
This Buoy Service package deal implements the calls to MongoDB. Let’s take a look at the FindStation operate that known as by the controller strategies:

func FindStation(service *providers.Service, stationId string) (buoyStation *buoyModels.BuoyStation, err error) {
    defer helper.CatchPanic(&err, service.UserId, “FindStation”)

    queryMap := bson.M{“station_id”: stationId}

    buoyStation = &buoyModels.BuoyStation{}
    err = service.DBAction(Config.Database, “buoy_stations”,
        func(assortment *mgo.Assortment) error {
            return assortment.Discover(queryMap).One(buoyStation)
        })

    if err != nil {
        if strings.Accommodates(err.Error(), “not discovered”) == false {
            return buoyStation, err
        }

        err = nil
    }

    return buoyStation, err
}

The FindStation operate prepares the question after which utilizing the DBAction operate to execute the question in opposition to MongoDB.

Implementing Net Calls
With the bottom sorts, boilerplate code and repair performance in place, we are able to now implement the online calls.

Buoy Controller
The BuoyController sort consists solely from the BaseController. By composing the BuoyController on this approach, it instantly satisfies the Put together and End interfaces and comprises all of the fields of a Beego Controller.

The controller capabilities are sure to routes. The routes specify the urls to the totally different net calls that the appliance helps. In our pattern utility we’ve three routes:

beego.Router(“/”, &controllers.BuoyController{}, “get:Index”)
beego.Router(“/buoy/retrievestation”, &controllers.BuoyController{}, “submit:RetrieveStation”)
beego.Router(“/buoy/station/:stationId”, &controllers.BuoyController{}, “get,submit:RetrieveStationJson”)

The route specifies a url path, an occasion of the controller used to deal with the decision and the identify of the tactic from the controller to make use of. A prefix of which verb is accepted might be specified as nicely.

The Index controller methodology is used to ship the preliminary html to the browser. It will embrace the javascript, fashion sheets and the rest wanted to get the online utility going:

func (this *BuoyController) Index() {
    area := “Gulf Of Mexico”

    buoyStations, err := buoyService.FindRegion(&this.Service, area)
    if err != nil {
        this.ServeError(err)
        return
    }

    this.Knowledge[“Stations”] = buoyStations
    this.Structure = “shared/basic-layout.html”
    this.TplNames = “buoy/content material.html”
    this.LayoutSections = map[string]string{}
    this.LayoutSections[“PageHead”] = “buoy/page-head.html”
    this.LayoutSections[“Header”] = “shared/header.html”
    this.LayoutSections[“Modal”] = “shared/modal.html”
}

A name is made into the service layer to retrieve the record of areas. Then the slice of stations are handed into the view system. Since that is organising the preliminary view of the appliance, layouts and the template are specified. When the controller methodology returns, the beego framework will generate the html for the response and ship it to the browser.

Screen Shot

To generate that grid of stations, we’d like to have the ability to iterate over the slice of stations. Go templates help iterating over a slice. Right here we use the .Stations variable which was handed into the view system:

{{vary $index, $val := .Stations}}
<tr>      
  <td><a category=”element” information=”{{$val.StationId}}” href=”#”>{{$val.StationId}}</a></td>
  <td>{{$val.Identify}}</td>
  <td>{{$val.LocDesc}}</td>
  <td>{{$val.Situation.DisplayWindSpeed}}</td>
  <td>{{$val.Situation.WindDirection}}</td>
  <td>{{$val.Situation.DisplayWindGust}}</td>
</tr>
{{finish}}

Every station id is a hyperlink that brings up a modal dialog field with the main points for every station. The RetrieveStation controller methodology generates the html for the modal dialog:

func (this *BuoyController) RetrieveStation() {
    params := struct {
        StationId string kind:&quot;stationId&quot; legitimate:&quot;Required; MinSize(4)&quot; error:&quot;invalid_station_id&quot;
    }{}

    if this.ParseAndValidate(&params) == false {
        return
    }

    buoyStation, err := buoyService.FindStation(&this.Service, params.StationId)
    if err != nil {
        this.ServeError(err)
        return
    }

    this.Knowledge[“Station”] = buoyStation
    this.Structure = “”
    this.TplNames = “buoy/pv_station.html”
    view, _ := this.RenderString()

    this.AjaxResponse(0, “SUCCESS”, view)
}

RetrieveStation will get the main points for the desired station after which makes use of the view system to generate the html for the dialog field. The partial view is handed again to the requesting ajax name and positioned into the browser doc:

operate ShowDetail(end result) {
    strive {
        var postData = {};
        postData[“stationId”] = $(end result).attr(‘information’);

        var service = new ServiceResult();
        service.getJSONData(“/buoy/retrievestation”,
            postData,
            ShowDetail_Callback,
            Standard_ValidationCallback,
            Standard_ErrorCallback
        );
    }

    catch (e) {
        alert(e);
    }
}

operate ShowDetail_Callback() {
    strive {
        $(‘#system-modal-title’).html(“Buoy Particulars”);
        $(‘#system-modal-content’).html(this.ResultObject);
        $(“#systemModal”).modal(‘present’);
    }

    catch (e) {
        alert(e);
    }
}

As soon as the decision to modal.(‘present’) is carried out, the next modal diaglog seems.

Screen Shot

The RetrieveStationJson operate implements an online service name that returns a JSON doc:

func (this *BuoyController) RetrieveStationJson() {
    params := struct {
        StationId string kind:&quot;:stationId&quot; legitimate:&quot;Required; MinSize(4)&quot; error:&quot;invalid_station_id&quot;
    }{}

    if this.ParseAndValidate(&params) == false {
        return
    }

    buoyStation, err := buoyService.FindStation(&this.Service, params.StationId)
    if err != nil {
        this.ServeError(err)
        return
    }

    this.Knowledge[“json”] = &buoyStation
    this.ServeJson()
}

You may see the way it calls into the service layer and makes use of the JSON help to return the response.

Testing The Endpoint
As a way to make certain the appliance is at all times working, it must have assessments:

func TestStation(t *testing.T) {
    r, _ := http.NewRequest(“GET”, “/station/42002”, nil)
    w := httptest.NewRecorder()
    beego.BeeApp.Handlers.ServeHTTP(w, r)

    response := struct {
        StationId string json:&quot;station_id&quot;
        Identify string json:&quot;identify&quot;
        LocDesc string json:&quot;location_desc&quot;
        Situation struct {
            Kind string json:&quot;sort&quot;
            Coordinates []float64 json:&quot;coordinates&quot;
        } json:&quot;situation&quot;
        Location struct {
            WindSpeed float64 json:&quot;wind_speed_milehour&quot;
            WindDirection int json:&quot;wind_direction_degnorth&quot;
            WindGust float64 json:&quot;gust_wind_speed_milehour&quot;
        } json:&quot;location&quot;
    }{}
    json.Unmarshal(w.Physique.Bytes(), &response)

    Convey(“Topic: Take a look at Station Endpointn”, t, func() {
        Convey(“Standing Code Ought to Be 200”, func() {
            So(w.Code, ShouldEqual, 200)
        })
        Convey(“The Outcome Ought to Not Be Empty”, func() {
            So(w.Physique.Len(), ShouldBeGreaterThan, 0)
        })
        Convey(“There Ought to Be A Outcome For Station 42002”, func() {
            So(response.StationId, ShouldEqual, “42002”)
        })
    })
}

This check creates a faux name by means of the Beego handler for the desired route. That is superior as a result of we don’t must run the online utility to check. By utilizing goconvey we are able to create assessments that produce good output that’s logical and simple to learn.

Here’s a pattern when the check fails:

Topic: Take a look at Station Endpoint

  Standing Code Ought to Be 200 ✘
  The Outcome Ought to Not Be Empty ✔
  There Ought to Be A Outcome For Station 42002 ✘

Failures:

* /Customers/invoice/Areas/Go/Tasks/src/github.com/goinggo/beego-mgo/check/endpoints/buoyEndpoints_test.go
Line 35:
Anticipated: ‘200’
Precise: ‘400’
(Ought to be equal)

* /Customers/invoice/Areas/Go/Tasks/src/github.com/goinggo/beego-mgo/check/endpoints/buoyEndpoints_test.go
Line 37:
Anticipated: ‘0’
Precise: ‘9’
(Ought to be equal)

3 assertions to this point

— FAIL: TestStation-8 (0.03 seconds)

Here’s a pattern when it’s profitable:

Topic: Take a look at Station Endpoint

  Standing Code Ought to Be 200 ✔
  The Outcome Ought to Not Be Empty ✔
  There Ought to Be A Outcome For Station 42002 ✔

3 assertions to this point

— PASS: TestStation-8 (0.05 seconds)

Conclusion
Take the time to obtain the venture and go searching. I’ve tried to point out you the main factors of the pattern and the way issues are put collectively. The Beego framework makes it straightforward to implement your individual methods to summary and implement boilerplate code, leverage the go testing harness and run and deploy the code utilizing Go customary mechanisms.



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments