Custom post-request with RESTAdapter - ember.js

My models work with the server via Ember's default RESTAdapter.
I just created a custom endpoint /mail on my server which sends an e-mail if provided a name, valid e-mail-adress and text.
How do I make Ember send that custom post-request? Is it possible without Ember.ajax at all?

For me personally, I wouldn't use Ember-Data to handle that scenario; I generally only use Ember-Data to handle my persisted models. If you try to use Ember-Data for other AJAX calls, it's just going to become a mess. Remember that Ember-Data's job is to manage your persisted data and one way that it can do that is with AJAX calls. That doesn't mean that anything that requires an AJAX call should be handled with Ember-Data.
I have this same issue and I wrote a utility module that has functions for all of my non-model AJAX stuff. This makes it really easy to swap out for testing. Here's a small example:
// utils/ajax.js
export function sendHelpEmail(comment) {
return new Promise((resolve, reject) => {
$.ajax({
type: 'POST',
url: '/api/contact_us',
contentType: 'application/json',
data: JSON.stringify({ comment }),
processData: false,
statusCode: {
200: () => Em.run(null, resolve),
500: () => Em.run(null, reject)
}
});
});
}
Then, I can do something like this in my controller:
import { sendHelpEmail} from '../utils/ajax.js';
export default Em.Controller.extend({
actions: {
sendEmail() {
sendHelpEmail(this.get('comment'));
}
}
});

Related

How to use asynchronous service in ember.js?

Before my ember.js app start, I need to access a entry api to get all those api endpoints and csrf token.
I'm trying to do it in service so the response can be accessed everywhere:
import Service from '#ember/service';
import $ from 'jquery'
export default Service.extend({
pageData: null,
init () {
this._super(...arguments)
var self = this
$.ajax({
type: 'get',
url: '/page_data',
dataType: 'json'
}).then((response) => {
self.set('pageData', response)
})
}
});
And I'm injecting the service in initializer:
export function initialize (application) {
application.inject('route', 'api', 'service:page-data');
application.inject('controller', 'api', 'service:page-data');
application.inject('component', 'api', 'service:page-data');
}
export default {
initialize
};
But I can't use the service in my router directly with this.get('api').pageData because it's asynchronous.
I found something on ember.js documentation here:
Operations performed in initializers should be kept as lightweight as possible to minimize delays in loading your application. Although advanced techniques exist for allowing asynchrony in application initializers (i.e. deferReadiness and advanceReadiness), these techniques should generally be avoided. Any asynchronous loading conditions (e.g. user authorization) are almost always better handled in your application route's hooks, which allows for DOM interaction while waiting for conditions to resolve.
But it 's used in initializers, not service.
Any suggests what I can do with my service now?
You can use application's deferReadiness method, to stall your app load.
However, if you require a loading UI, i would suggest to set a promise object to your pageData variable, and as soon as that promise resolves/rejects you can change the state of your app accordingly.
Here's what I did at last:
import Service from '#ember/service';
import $ from 'jquery'
import { Promise } from 'rsvp'
export default Service.extend({
pageData: null,
setup () {
return new Promise((resolve, reject) => {
var self = this
$.ajax({
type: 'get',
url: '/page_data',
dataType: 'json'
}).then((response) => {
self.set('pageData', response)
resolve()
}).catch(() => {
reject()
})
})
}
});
Then in the index route, run the setup in beforeModel hook:
import Route from '#ember/routing/route';
import { all } from 'rsvp'
export default Route.extend({
beforeModel () {
return all([this.get('api').setup()])
},
model () {
window.console.log(this.get('api').pageData)
}
});

ember-simple-auth custom authenticator using ember-data

I'm creating a frontend for a C program with an embedded web interface that has a simple REST api. I'd like to use ember-simple-auth with a customer authenticator and authorizer that talks to that api endpoint.
var Authenticator = AuthenticatorBase.extend({
restore: function(data) {
...
},
authenticate: function(credentials) {
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
... ??? ...
});
},
invalidate: function() {
var _this = this;
return new Ember.RSVP.Promise(function(resolve) {
... ??? ...
});
},
});
In the ember-simple-auth examples, I see the custom authenticator implementation that uses Ember.$.ajax to post to server like this:
authenticate: function(credentials) {
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
url: _this.tokenEndpoint,
type: 'POST',
data: { username: credentials.identification,
password: credentials.password },
}).then(function(response) {
Ember.run(function() {
resolve({ token: response.session.token });
});
}, function(xhr, status, error) {
var response = JSON.parse(xhr.responseText);
Ember.run(function() {
reject(response.error);
});
});
});
},
But I'd rather use ember-data for this (I think) -- new to ember and ember-data, so it's not clear. Assuming my API endpoint is /session, what would my authenticate method look like with ember-data?
On a related note: I'm using ember-cli and running ember server for development. How do I tell ember-data to point to my C-based server for the REST calls? I'm trying this, but doesn't seem to be affecting the ember-data calls - they just go to the ember server:
// app/adapters/application.js
import DS from "ember-data";
export default DS.RESTAdapter.extend({
host: 'localhost:48880',
namespace: '/'
});
When you want to use Ember Data you'd need to have a Session model or so so that when you create an instance of that a POST to /sessions would be triggered. I don't actually think that makes sense though and you don't really get any benefits from using Ember Data in that case - I'd recommend to simply go with plain Ember.$.ajax and use Ember Data for your actual model data.

Mocking HTTP requests in ember-qunit

In an ember-cli app, testing is done using ember-qunit.
I would like to mock HTTP requests, but have not been able to find a recommended way of doing this in the documentation.
I have found this thread which discusses this, but it appears to be out of date (for ember-cli anyway).
How do you mock HTTP requests?
This is how I mock HTTP requests. One improvement could be done by encapsulating mockjax with helper like:
function stubEndpointForHttpRequest(url, json) {
$.mockjax({
url: url,
dataType: 'json',
responseText: json
});
}
So you can easily switch for another library like sinon or whatever.
module('Integration - Signin Tests', {
setup: function(){
App = startApp();
},
teardown: function(){
Ember.run(App, 'destroy');
$.mockjaxClear(); // Don't forget to clear mockjax
}
});
test('Signin with valid data', function(){
expect(2);
stubEndpointForHttpRequest('api_url', 'response_json');
// Write your test
});
I Hope this helps

Is there a difference Ember getJSON if I am using Swagger JS?

to pull a JSON into a model from an API, I would normally do this:
return Ember.$.getJSON('http://....');
However is there a difference in syntax if I am using Swagger?
I just got introduced to this the other day at work. The back-end developers are starting to use it... but this is new to all of us so I don't know how to utilize this on the front-end?
I'm not familiar with Swagger at all, but you can always use a promise and hook up the results that way.
Assuming the swagger connection
swagger = new SwaggerApi({
url: "http://petstore.swagger.wordnik.com/api/api-docs",
success: function() {
if(swagger.ready === true) {
// upon connect, fetch a pet and set contents to element "mydata"
}
}
});
model: function(){
return Ember.RSVP.Promise(function(resolve, reject){
swagger.apis.pet.getPetById({petId:1}, function(data) {
resolve(data.content.data);
});
});
});

How do I use the JSONP datatype with Ember Data?

How do I set up Ember Data to use the JSONP datatype when making its ajax calls? I am going to be using Ember with Phonegap and need to make cross-domain requests.
It's much easier to override the private ajaxOptions function instead of using jQuery. Ember's pipeline includes the removal of the jQuery dependency anyways. So do this instead:
adapters/application.js:
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
ajaxOptions: function(url, type, options) {
var hash = this._super(url, type, options);
hash.dataType = "jsonp";
return hash;
}
});
It would be create if the Ember core team could expose a public method to officially support this (instead of hacking a private api).
https://github.com/emberjs/data/blob/1.0.0-beta.15/packages/ember-data/lib/adapters/rest_adapter.js#L915
You need to create your own adapter which uses jsonp, you can do just that by extending a current one, have a look.
App.MyAdapter= DS.RESTAdapter.extend({})
Then you need to implement the find method among others, to use jsonp, could be something like this
App.MyAdapter= DS.RESTAdapter.extend({
find: function(store, type, id) {
var item;
$.ajax({
url: 'http://api.domain/someModel',
dataType: 'jsonp',
success: function(response){
item = App.someModel.create(order))
}
});
return item;
},
This is not tested, but it should give you the idea of how i can be done. :)