I am calling following function on click of button.
login.ts
public login() {
this.showLoading()
this.http.get('http://laravel.dev/test').map(res => res).subscribe(data => {
console.log(data)
},
error => {
this.showError(error);
});
}
What I want that this API call should be come from service file. As I am new to Ionic 2 That's Why I am unable to get how can I call above API through service and receive it in login.ts.
auth.service.ts
public login(credentials) {
// Here I want to call Above API and return it to the `login.ts`
}
Please help me.
The http.get request is an Observable. You can return the observable from the service and subscribe in the component/page.
auth.service.ts
public login(credentials) {
return this.http.get('http://laravel.dev/test').map(res => res.json())
}
map function returns the data after decoding the json response assuming your http returns json.
login.ts
public login() {
this.showLoading()
this.authService.login(credentials).subscribe(data => {
console.log(data)
},
error => {
this.showError(error);
},
()=>this.dismissLoading());
}
Inject the service through the constructor in your component and subscribe to the login function.
Related
This is part 2 of me debugging my application in production
In part 1, I managed to at least see what was causing my problem and managed to solve that.
When I send a request to my API which is hosted on Heroku using axios interceptor, every single request object looks like this in the API
{ 'object Object': '' }
Before sending out data to the API, I console.log() the transformRequest in axios and I can see that the data I am sending is actually there.
Note: I have tested this process simply using
axios.<HTTP_METHOD>('my/path', myData)
// ACTUAL EXAMPLE
await axios.post(
`${process.env.VUE_APP_BASE_URL}/auth/login`,
userToLogin
);
and everything works and I get data back from the server.
While that is great and all, I would like to abstract my request implementation into a separate class like I did below.
Does anyone know why the interceptor is causing this issue? Am I misusing it?
request.ts
import axios from "axios";
import { Message } from "element-ui";
import logger from "#/plugins/logger";
import { UsersModule } from "#/store/modules/users";
const DEBUG = process.env.NODE_ENV === "development";
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_URL,
timeout: 5000,
transformRequest: [function (data) {
console.log('data', data)
return data;
}],
});
service.interceptors.request.use(
config => {
if (DEBUG) {
logger.request({
method: config.method,
url: config.url
});
}
return config;
},
error => {
return Promise.reject(error);
}
);
service.interceptors.response.use(
response => {
console.log('axios interception response', response)
return response.data;
},
error => {
const { response } = error;
console.error('axios interception error', error)
if (DEBUG) {
logger.error(response.data.message, response);
}
Message({
message: `Error: ${response.data.message}`,
type: "error",
duration: 5 * 1000
});
return Promise.reject({ ...error });
}
);
export default service;
Login.vue
/**
* Sign user in
*/
async onClickLogin() {
const userToLogin = {
username: this.loginForm.username,
password: this.loginForm.password
};
try {
const res = await UsersModule.LOGIN_USER(userToLogin);
console.log("res", res);
this.onClickLoginSuccess();
} catch (error) {
throw new Error(error);
}
}
UsersModule (VUEX Store)
#Action({ rawError: true })
async [LOGIN_USER](params: UserSubmitLogin) {
const response: any = await login(params);
console.log('response in VUEX', response)
if (typeof response !== "undefined") {
const { accessToken, username, name, uid } = response;
setToken(accessToken);
this.SET_UID(uid);
this.SET_TOKEN(accessToken);
this.SET_USERNAME(username);
this.SET_NAME(name);
}
}
users api class
export const login = async (data: UserSubmitLogin) => {
return await request({
url: "/auth/login",
method: "post",
data
});
};
I'm not sure what you're trying to do with transformRequest but that probably isn't what you want.
A quote from the documentation, https://github.com/axios/axios#request-config:
The last function in the array must return a string or an instance of Buffer, ArrayBuffer, FormData or Stream
If you just return a normal JavaScript object instead it will be mangled in the way you've observed.
transformRequest is responsible for taking the data value and converting it into something that can actually be sent over the wire. The default implementation does quite a lot of work manipulating the data and setting relevant headers, in particular Content-Type. See:
https://github.com/axios/axios/blob/885ada6d9b87801a57fe1d19f57304c315703079/lib/defaults.js#L31
If you specify your own transformRequest then you are replacing that default, so none of that stuff will happen automatically.
Without knowing what you're trying to do it's difficult to advise further but you should probably use a request interceptor rather than transformRequest for whatever it is you're trying to do.
I am trying to connect SignalR hub to a Vue component but I fail doing that. i googled "vue with signalr" and real almost every link up to second page.
I getting a cors origin, but I dont think that this is the main problem, since my post/get call to web api are working well.
c# port number 63213 , client at 8080
I also using vuex and i am wonder if I should connect in at the store.
here are code examples. I use vue/vuex with typescript falvor.
mounted: function() {
//... under mounted, signalR connection. i am using import * as signalR from "#aspnet/signalr";
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:63213/ChatHub")
.build();
// connecting to the hub
this.hubConnection
.start()
.then(() => console.log("connection started"))
.catch(err => console.log("connecting hub failed err is : ", err));
//at the hub there is a function named broadcastMessage, should return string that will be added to an array. should it be at sotr's getter
this.connection.on("broadcastMessage", function(msg: string) {
this.messages.push({ msg });
});
},
c#
public class Startup
{
public void Configuration(IAppBuilder app)
{
var policy = new CorsPolicy()
{
AllowAnyOrigin = true,
AllowAnyHeader = true,
AllowAnyMethod = true,
SupportsCredentials = true
};
policy.Origins.Add("http://localhost:8080");
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
pot get to web api are working well.
hub
public class ChatHub : Hub
{
public static void SendMessage(string msg)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
hubContext.Clients.All.broadcastMessage(msg, " !! !! ");
}
}
error is:
Access to XMLHttpRequest at 'http://localhost:63213/ChatHub/negotiate' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
should i pass the hub connention to the store?
what am i doing wrong?
thank you.
switched to .core object.
under "Configure"
app.UseCors(builder => builder.WithOrigins("http://localhost:8080").AllowAnyMethod().AllowAnyHeader().AllowCredentials());
app.UseSignalR(route => {route.MapHub<UserHub>("/user-hub");} );
under
ConfigureServices
services.AddSignalR();
services.AddCors();
at vue component (ts)
created: function() {
this.$userHub.$on("user-added-event", this.userAddedEvent);
},
beforeDestroy: function() {
//clean SignalR event
this.$userHub.$off("user-added-event", this.userAddedEvent);
},
user-hub.js used to handle connection.
imported as vue plugin
import { HubConnectionBuilder, LogLevel } from "#aspnet/signalr";
export default {
install(Vue) {
const connection = new HubConnectionBuilder()
.withUrl(`${Vue.prototype.$http.defaults.baseURL}/user-hub`)
.configureLogging(LogLevel.Information)
.build();
const userHub = new Vue();
Vue.prototype.$userHub = userHub;
connection.on("AddUserEvent", (userId, userName) => {
userHub.$emit("user-added-event", { userId, userName });
});
// if connection closed, reopen it
let startedPromise = null;
function start() {
startedPromise = connection.start().catch(err => {
return new Promise((resolve, reject) =>
setTimeout(
() =>
start()
.then(resolve)
.catch(reject),
5000
)
);
});
return startedPromise;
}
connection.onclose(() => start());
start();
}
};
full project will be uploaded to git.
I use the following function to Post a object of a given class.
public Post<T>(object: T, url: string, httpOptions: {}): Observable<T> {
return this.httpClient.post<T>(`${environment.apiEndpoint}` + url, object, httpOptions)
.pipe(
catchError(this.handleError)
);
}
This function is called in all the service that wants to post something. Like this.
public addEquipment(equipment: Equipment): Observable<Equipment> {
return this.shared.Post<Equipment>(equipment, this.url, this.header);
}
addEquipment is then executed within the component that uses that service. Like this.
this.equipmentService.addEquipment(result)
.subscribe((data: any) => { this.alertService.success(data) }, (error: any) => this.alertService.error(error));
The problem is when the API returns a error (that I can see includes a error message, in the network tab) it tells me that there is no body in the response. The API returns a HttpResult where the error message is added to the response field.
return new HttpResult { StatusCode = HttpStatusCode.Conflict, Response = "Error message"}
I use the following function to handle the errors.
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
}
else {
console.log(error);
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
console.log(error);
return throwError(
error.error)
};
It is Angular 6 and a ServiceStack API.
All suggestions would be appreciated.
FYI it's preferable to return structured error responses in ServiceStack which you can do with:
HttpError.Conflict("Error message");
Which will let you catch it when using ServiceStack's TypeScript ServiceClient with:
try {
var response = await client.post(request);
} catch (e) {
console.log(e.responseStatus.message);
}
But from this answer for handling errors with Angular HTTP Client it suggests the error body should be accessible with:
this.httpClient
.get("data-url")
.catch((err: HttpErrorResponse) => {
// simple logging, but you can do a lot more, see below
console.error('An error occurred:', err.error);
});
I'm making a web app that uses Axios.
I have a base service class that has an interceptor that will add the access token to each request. However, the interceptor wont add the token on my PATCH request, only on the GET request.
My base api service
import axios from 'axios'
export default class api {
constructor (path) {
this.api = axios.create({
baseURL: 'http://localhost:1337/' + path
})
this.api.interceptors.request.use(config => {
config.headers['x-access-token'] = localStorage.getItem('jwt-token')
return config
})
this.api.interceptors.response.use(undefined, (err) => {
if (err.response.status === 401) {
throw err
} else {
throw err
}
})
}
}
The service that extends the base
import Api from './api'
export default class ProfileService extends Api {
constructor () {
super('profile/')
}
me () {
return this.api.get('/me')
}
updateProfile (uuid, data) {
return this.api.patch('/' + uuid, data)
}
}
Axios does add the token to PATCH requests if I make a global interceptor like this:
axios.defaults.headers.common['x-access-token'] = localStorage.getItem('jwt-token');
I do not want to do this though, as it will send the token to other servers as well.
Any ideas on why my interceptor wont add the token when specified per instance? Is this a bug with Axios?
The OPTIONS-request has the following headers:
Access-Control-Allow-Headers:x-access-token,X-Requested-With,Content-Type,Accept,Authorization,Origin
Access-Control-Allow-Methods:GET,PUT,POST,PATCH,OPTIONS
Thanks in advance,
Axel
As I said in my previous questions, I am trying to learn how to use sails.js, what I'm trying to do now is to cache the response of an api to redis. I have searched on how to do this, but I can't make it to work. Without caching, I call the api through ajax.
Any thoughts on how I will be able to do it using my controller? How can I call the api using the controller in sails.js and cache the response using redis?
You can use https://github.com/mranney/node_redis
Steps:
Add to package.json
"redis": "^0.12.1"
Run
npm install
Create a service module /api/services/CachedLookup.js
var redis = require("redis"),
client = redis.createClient();
module.exports = {
rcGet: function (key, cb) {
client.get(key, function (err, value) {
return cb(value);
});
},
fetchApi1: function (cb) {
var key = 'KEY'
CachedLookup.rcGet(key, function (cachedValue) {
if (cachedValue)
return cb(cachedValue)
else {//fetch the api and cache the result
var request = require('request');
request.post({
url: URL,
form: {}
}, function (error, response, body) {
if(error) {
//handle error
}
else {
client.set(key, response);
return cb(response)
}
});
}
});
}
}
Inside the controller
CachedLookup.fetchApi1(function (apiResponse) {
res.view({
apiResponse: apiResponse
});
});