I have an ASP.NET MVC 4 application, that serves as the host for my ServiceStack AppHost. Everything is working fine in development, but in my first test deployment, I realized I neglected to handle differences in my AJAX url values between my environments (development/test/staging/deployment). My app is really just a Knockout-based SPA that makes calls to ServiceStack, so MVC merely provides the hosting.
So my javascript has this:
self.DoSomething = function (event) {
// here is my problem. the service url is
// specific to the current environment
var service_url = '/api/some_method';
$.ajax({
url: service_url,
dataType: 'json',
type: 'POST',
success: function (data) {
// do something
}
})
};
In a 'normal' ASP.NET MVC app, where I'm calling controller actions, I'd do this:
var service_url = '#Url.Action("MyControllerAction", "MyController")'
The best solution I have so far is this:
var service_url = '#Url.Content("~")api/some_method';
It works fine, but it looks uglier than I would have thought possible for a single line of code. It also looks like the sort of thing that could get messed up without noticing until the AJAX calls start failing...
My inclination would be to wrap this up into a js helper file, which could be referenced from any similar page, but the js helper wouldn't get resolved by the razor engine.
Does anyone know if there is a 'best practice' way to do this?
Related
I am using mithril in an IoT framework. I am trying to isolate the front-end development from backend API implementation tasks. In jQuery, I have used jQuery-mockjax and a similar mechanism in Angular. What I understand is that those libraries intercept ajax function call an appropriately respond with data that are setup using $.mockjax (or similar functions)
The mechanism recommended here https://groups.google.com/forum/#!topic/mithriljs/FzpCPMfauf0, does not give the flexibility to implement this. There is no easy way to use mock for a selected few APIs.
After looking through the code, I realized is, to implement this, I need to get access to the ‘ajax’ function (or just the XHR processing section), so that it can be overridden using my own implementation that can mock selected APIs. The problem is that ajax is a local function in the library. If it is exposed as m.ajax, my library can override it and get the functionality I need.
My question is, is there a better way to achieve the same? If you have done similar things please share.
My code structure will be something like this:
// in mithril-mockjax.js, implements mockjax function
m.mockjax = function (options) { … }
// in app-api-mocks.js
m.mockjax({
method: GET,
url: /sessions/123,
response: { …}
});
m.mockjax({
method: POST,
url: /sessions,
data: {},
response: { … }
});
The above two files are inserted in the page when I am in the development mode. The rest of the code remains the same.
You can do this by either mocking m.request by monkey-patching it or you add a layer of abstraction between m.request and your code that you are then able to mock away.
I need to make an API request to an external API using an API Key. I know how to make this API request in React by writing a onSubmit function. But since I have an API key that I want to keep a secret I am going to write a simple Node app to house env variables.
Besides messing around in node this is my first production experience with Node and I am wondering if my thought process is correct and if not, the better way to do this.
Most of this question will be pseudo code since I haven't started with the Node portion yet.
The idea is that from within the React component it would call the Node app who in turn would call the external API.
React -> Node -> External API
So the React component would be something like so:
handleSubmit: function() {
var data = this.refs.testData.getDomNode().value;
$.ajax({
url: '/my-node-endpoint',
dataType: 'json',
type: 'POST',
data: { test: data },
success: function(data) {
// Whatever success call I want to make
}.bind(this)
})
}
And then in my Node app it would like something like this:
app.post('/my-node-endpoint', function(req, res) {
// Store the values we are posting as JSON
// Start the post request
// On End tell the React component everything is ok
// Prosper
});
As always, thanks for any help that is offered.
Your thought process looks right to me.
If the API you are calling is from a different domain, you will have to build a wrapper on your node server like you did here. Unless the external API supports cross-origin requests with no domain restrictions (such as MapBox web services), you will have to do this.
Several improvements to your code:
As far as I know, you can use React.findDOMNode(this.refs.testData).value instead of this.refs.testData.getDomNode().value. getDomNode() is deprecated in v0.13.
For all the AJAX calls, you can use the Store concept in Flux. The store keeps the states of the data, including updating data through AJAX request. In your React UI code, you just need to call the methods of the store, which makes your UI code clean. I usually create a store class myself without using Flux.
I come from a completely non web-development background, but having seen the traction that mean.js is picking up, i really wanted to give it a shot.
I've followed tutorials online so I've basically started, run and modified the example app but am now trying to do something thats off of the tutorials. As a result I have a basic understanding of express and angular
I've been trying to integrate the activator npm package (https://www.npmjs.org/package/activator) into the app, and while I've managed to fit in the angular bits, I'm having trouble plugging in the express bits. Which brings me to a very fundamental doubt, the answers to which I haven't really been able to find. I know that in Mean, the angular code connects to the express code using REST API's created in express. And that I believe happens using angular services. But I don't understand how. For instance, the users module has the following service defined:
angular.module('users').factory('Users', ['$resource',
function($resource) {
return $resource('users', {}, {
update: {
method: 'PUT'
}
});
}
]);
Can anyone explain how this works ?
Also if I have some code on the express side say:
var sayHello = function(name){
return "Hello"+name;
}
How can I call this through angular? I know we use $resource for that from the ngResource module, but I dont really understand how.
Any help would be much appreciated.
Connecting these things together can be a bit confusing. I think the thing to understand is that when using Express on the server side, you need to model your API around a route, and handle communication with the req and res objects you'll be handed.
So first on the client side, taking a simple example, I generally use the $resource as a way of wrapping the HTTP/ajax details which I don't want to worry about. So I'll write my service as such:
"use strict";
angular.module("myModule").factory("UserService", ["$resource",
function($resource) {
var resource;
resource = $resource("/api/users", null, {
listUsers: {
method: "GET",
isArray: true
}
});
return resource;
}
]);
(Notice that I'm passing the isArray parameter to this resource since I expect an array of users to return -- which is not always the case with all APIs).
Then to take advantage of that resource, perhaps in my controller I'll have code like this:
"use strict";
angular.module("myModule").controller("UserCtrl", ["$scope", "UserService",
function($scope, userService) {
$scope.loadUsers = function() {
userService.listUsers(function(resource, headers) {
// this function is called on success, with the result
// stored within the `resource` variable
// ...
}, function(response) {
// this function is called on error
// ...
});
};
}
]);
Now assuming everything goes right on the server side, we'll receive our list of users to play around with passed in to the first function as the resource.
On the server side, we'll need to configure our routes (wherever those are configured) to include our users controller, which will serve as our users API. So perhaps within this app we have a routes directory which contains all our Express routes (see the app.route documentation for more information on Express routes). We also have a controllers directory which contains all our Express controllers that handle the logic for our routes. Keeping with the "users" example, we'll have a route defined that matches the /api/users $resource route we defined above in our Angular code:
"use strict";
var controller = require("../controllers/user");
module.exports = function(app) {
app.route("/api/users").get(controller.listUsers);
};
This code takes in the Express app as input, and defines a single route for /api/users as a GET HTTP request (notice the .get function called). The logic for this route is defined in the user controller, which would be something like this:
"use strict";
exports.listUsers = function(req, res) {
var users;
// ...somehow populate the users to return...
res.send(users);
};
We've left the details on how to populate that array of users, but hopefully this gives you the idea. This controller is passed the req (request) and res (response) HTTP objects as input, so it can query the request object for details on what the user passed in, and must send some response back to the user to complete the request/response loop. In this example I'm using the res.send function to simply send back our JavaScript array (which will be passed as JSON).
Does that make sense?
I'm quite new to AngularJS and NodeJS. I'm trying to develop an app using MEAN stack. I just looked through the sample code in the mean.io boilerplate. I created my own app referring the sample app. I'm trying to submit the AngularJS front end and expecting it to call NodeJs server side but it isn't working. I think service.js is messing up something. Here is the service code of sample app. Can any one explain what this code does with respect to Angular client side and NodeJS Server side.
'use strict';
//Articles service used for articles REST endpoint
angular.module('mean.articles').factory('Articles', ['$resource', function($resource) {
return $resource('articles/:articleId', {
articleId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}]);
It creates a new factory in angular called Articles. The Articles factory has the $resource service injected. The $resource object is used to setup an object for communicating with a RESTful service, in this case "articles/:articleId" the articleId will be pulled from the _id of the resource objects that are returned from queries using this $resource. When you call to update on one of the resources it will use the PUT HTTP Verb.
By itself this just defines the factory but doesn't actually make any calls you would need to inject this and use it somewhere like Articles.query();
From the docs
If the parameter value is prefixed with # then the value of that
parameter is extracted from the data object (useful for non-GET
operations).
I have a RESTful Java backend which I made using Jersey, a JAX-RS implementation. This backend is running on a glassfish server on port 8084. I've also made some HTML5/JS/AJAX pages which display the data so I know my REST implementation is working.
I'm trying to develop an HTML5 / JS frontend for this application using the Angular.js framework but I'm experiencing some trouble. I have managed to develop some small webapps in angular which I'm running on Microsoft's IIS on port 80.
Unfortunately, there appears to be a problem with the communication between the two applications. Since I'm new to Angular, I'm unsure if I made a mistake in my frontend code, or if I'm experiencing CORS problems. I already tried running the backend on a Tomcat 7 with the CORS filter but that didn't solve anything.
My angular code looks like this:
services.js
var serviceModule = angular.module('ServiceModule', ['ngResource']);
serviceModule.factory('NodeService', function($resource) {
var NodeService = $resource('http://localhost:port/HtmlJerseyJava/service/node/get/3',{},
{
'get' : { method: 'GET',params:{port:':8084'}}
}
)
return NodeService;
});
controllers.js
function NodeDetailCtrl($scope, NodeService){
var node3 = NodeService.get();
$scope.data = JSON.stringify(node3) ;
}
I hardcoded the ID 3 for now, because I also need to figure out how I can pass the value of an input field from the view to the controller and then to the service. Eventually, the 3 in the service url would be replaced by a variable :nodeId
Any help would be greatly appreciated.
Try the following simplified code:
app.js (for test purposes I suggest you to put functions in one js file)
var serviceModule = angular.module('ServiceModule', ['ngResource']);
serviceModule.factory('Node', function($resource) {
return $resource('http://localhost:port/HtmlJerseyJava/service/node/get/3',{port:':8084'},
{
get {method:'GET'}
});
});
serviceModule.controller('NodeDetailCtrl', function($scope, Node){
$scope.data = Node.get();
}
It would be interesting to now what JSON data your client gets from the REST call.
Greets Marc
I found the solution. There were several steps to fix this problem:
Add a CORS filter to the Jersey servlet on Glassfish.
Upgrade the Angular version to 1.1.x (currently still unstable)
Set a custom header in your resource.
Enjoy a working application.
Big thanks Marcbaur for helping me out here.