HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptModerate

Interactive API documentation page of a RESTful dictionary API using Backbone.js

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
interactivedocumentationbackbonepagerestfulusingdictionaryapi

Problem

I'm working on the interactive API documentation of a RESTful dictionary service.
The page should let testers try the different API calls,
by playing with the parameters using a simple web form.
Changes to the web form should trigger API calls with the appropriate parameters,
display the JSON output,
and a well-formatted curl command that's ready to run.

I'm using Backbone.js to implement the dynamic client-side behavior,
and the following class structure:

-
App.FormView: a base View class, for common form controls,
such as a dictionary selector and a Run button,
to be used by different API endpoint tools

-
App.CurlView: a base View class, for common logic when rendering sample curl commands of different API endpoint,
especially for building the common part of API URLs

-
App.FindByKeywordParams: a Model class,
for capturing the parameters needed for making one of the /find/:method/:keyword type of API calls.
Views can subscribe to change events to trigger refreshing themselves.

-
App.FindByKeywordFormView: a View class, extending App.FormView,
adding custom form controls specialized for the /find/:method/:keyword type of API calls.
It updates a App.FindByKeywordParams object.

-
App.FindByKeywordCurlView: a View class, extending App.CurlView,
adding custom curl URL building logic specialized for the /find/:method/:keyword type of API calls.
Updates to the App.FindByKeywordParams object it references
trigger refreshing the view.

Implementation:

```
var App = window.App = {};

App.API_BASEURL = '/api/v1/dictionaries';

App.FormView = Backbone.View.extend({
_events: {
'click .run': 'runBtn',
'change .dictionary': 'run'
},
_initialize: function () {
this.dictionary = this.$('select[name="dictionary"]');
this.output = this.$('.api-output');
},
runBtn: function (e) {
e.preventDefault();
this.run();
},
runOnEnter: function (e) {
if (e.keyCode != 13)

Solution

Be consistent with your method naming; don't mix camelCase and snake_case, pick one and stick with it. I would recommend picking camelCase as there are a lot of JavaScript projects out there which use it as a convention, but feel free to go with whatever is most readable to you.

I would define your extras object as so; falsey values shouldn't be picked up on the server side code anyway:

var extras = {
    list: list,
    similar: similar
}


As Backbone depends on underscore, don't be afraid to tidy up your code with underscore's methods:

var success = _.bind(function(json) {
    this.onApiSuccess(json);
}, this);


Better yet, you can get rid of the proxy entirely:

$.ajax({
    url: url,
    data: extras,
    success: _.bind(this.onApiSuccess, this),
    error: _.bind(_.partial(this.onApiError, url), this)
});


Instead of string concatenation, underscore templating can make this more readable:

var url = _.template('//find//', {
    baseURL: App.API_BASEURL,
    dictID: dict_id,
    method: method,
    keyword: keyword
});


Don't be afraid of borrowing methods; your _initialize method should be rewritten as initialize so that a later form view could use it, if it didn't need to implement some custom code. Then, instead of doing this._initialize() you can do this:

initialize: function() {
    App.FormView.prototype.initialize.apply(this);
    this.keyword = this.$('.keyword');
    this.keyword.val(this.model.get('keyword'));
}


Your references to this.$el.find() can simply be this.$(), which you've used, but not consistently. :)

Finally, you need to document your code so that you/another developer can know what it does in the future; I recommend JSDoc which can be easily integrated into a task runner/build system such as Grunt or gulp, or if not just use the CLI tool.

Hope this helps. :)

Edit: I've tested the _.bind and _.partial methods and they're working for me, you might want to make sure that you are running the latest version of underscore (upgrading to Backbone 1.0.x might be good too but that may require some additional code changes). Personally I've been using Lo-Dash as underscore instead as the library offers more features and is generally regarded to be more stable/consistent. You can also use the underscore build of Lo-Dash for a drop in replacement.

Code Snippets

var extras = {
    list: list,
    similar: similar
}
var success = _.bind(function(json) {
    this.onApiSuccess(json);
}, this);
$.ajax({
    url: url,
    data: extras,
    success: _.bind(this.onApiSuccess, this),
    error: _.bind(_.partial(this.onApiError, url), this)
});
var url = _.template('<%- baseURL %>/<%- dictID %>/find/<%- method %>/<%- keyword %>', {
    baseURL: App.API_BASEURL,
    dictID: dict_id,
    method: method,
    keyword: keyword
});
initialize: function() {
    App.FormView.prototype.initialize.apply(this);
    this.keyword = this.$('.keyword');
    this.keyword.val(this.model.get('keyword'));
}

Context

StackExchange Code Review Q#60257, answer score: 10

Revisions (0)

No revisions yet.