How to mock payload - api

i'm trying to create mock for request in playright. I successfully cought request, but i can't mock it payload data. I tryed to make it like this, but all my data was posted in preview tab of devtools and payload recieved real data
import type { BrowserContext } from '#playwright/test';
export async function mockFinanceOzonru(
context: BrowserContext,
): Promise {
await context.route(https://some url/, (route) => {
route.fulfill({
status: 200,
contentType: 'text/plain;charset=UTF-8',
body: {"data": "my data"}
});
});
}

Related

Axios interceptors don't send data to API in production Heroku app

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.

globalize axios as API wrapper in vue project

I have almost 13 Axios requests in my Vue application. which are almost the same
axios({
method: 'post',
url: `${this.$root.api_url}/v2/cameras/${this.selected.exid}/nvr/snapshots/extract`,
data: {
start_date: moment(this.fromDateTime).format(),
end_date: moment(this.toDateTime).format(),
schedule: this.schedule,
interval: this.interval,
create_mp4: this.create_mp4,
inject_to_cr: this.inject_to_cr,
jpegs_to_dropbox: this.jpegs_to_dropbox,
requester: this.$root.user.email,
api_key: this.selected.api_key,
api_id: this.selected.api_id
}
}).then(response => {
if (response.status == 201) {
this.showSuccessMsg({
title: "Success",
message: "Snapshot Extractor has been added (Local)!"
});
this.$events.fire('se-added', {})
this.clearForm()
} else {
this.showErrorMsg({
title: "Error",
message: "Something went wrong!"
})
}
})
I pass the method, URL and data.. and do a few things in response and in case of error.
How can I reduce that so much code? I have this idea to make an API file for this where, the method will accept, API.get(method, URL, data) and I will have {message, statusCode} in return. and then on the basis of that, I can do other stu7ff.
I tried to follow some documentation online but it didn't work. Is there any suitable way to reduce this code.
Is it even possible to give success and error message as well in API.get or post or delete that it would be very minimal when you send the API request?
EDIT: so i guess you need something like a class here:
class API {
static get(url, callback) {
axios({
method: "get",
url: url,
data: data
}).then(response => {
callback(response);
});
}
static post(url, data, callback) {
axios({
method: "post",
url: url,
data: data
}).then(response => {
callback(response);
});
}
}
API.post("url", data, response => {
console.log(response);
});
API.get("url", response => {
console.log(response);
});
I use yamlful
You make a .yml file which includes
events:
- method: get
get: /events/:id
then API calls become
const response = await this.$api.events.get(2)
Furthermore, I inject methods into my context
// api.js
async function populateEvents (app, id) {
const response = await app.$api.events.get(id)
return response
}
export default ({ app, store }, inject) => {
inject('populateEvents', id => populateEvents(app, id))
}
// any_file.vue
this.populateEvents(12)
and in api.js you can generalize your api calls, so if any 2 api calls do the same stuff, you can refactor that repeated code into a separate method

Problem with PUT request in axios with vue.js

I'm building a smart home application. I have a problem with sending PUT request to my rest api (I building it with flask), but when I try send request it gives me HTTP 400 error (( Uncaught (in promise) Error: Request failed with status code 400 )) . Can you help me?
import axios from 'axios';
export default {
data: function() {
return {
value: 0,
lampName: 'Kitchen',
};
},
mounted () {
axios
.get("http://127.0.0.1:5000/lamp/" + this.$route.params.id)
.then(response => (this.value = response.data))
},
methods: {
updateValue () {
axios
.put('http://127.0.0.1:5000/lamp/' + this.$route.params.id,
{value: this.value},
{headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
})
}
}
}
try to add the method field to the form and send it in post way like this
formData.append('_method', 'PUT')
then try to send the data regularly
I think it work like this:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">
import axios from 'axios';
export default {
data: function() {
return {
value: 0,
lampName: 'Kitchen',
};
},
mounted () {
axios
.get("http://127.0.0.1:5000/lamp/" + this.$route.params.id)
.then(response => (this.value = response.data))
},
methods: {
updateValue () {
let formData = new FormData();
formData.append("value", this.value);
formData.append("lampName", this.lampName);
formData.append('_method', 'PUT');
axios
.post('http://127.0.0.1:5000/lamp/' + this.$route.params.id,
formData
})
}
}
}
</script>
So this is the failing request:
axios
.put('http://127.0.0.1:5000/lamp/' + this.$route.params.id,
{value: this.value},
{headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
})
I don't know what your server is expecting but you're setting a content-type of application/x-www-form-urlencoded while sending JSON data. It seems likely this mismatch is the cause of your problems. You should be able to see this if you inspect the request in the Network section of your browser's developer tools.
If you need to use application/x-www-form-urlencoded then I suggest reading the axios documentation as you can't just pass in a data object like that:
https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format
In short, you need to build up the body string manually, though there are utilities to make that less onerous.
If you actually want JSON data then just remove the content-type header. Axios should set a suitable content-type for you.
Pass your method as post method and define put in form data formData.append('_method', 'PUT') .
updateValue () {
axios
.post('http://127.0.0.1:5000/lamp/' + this.$route.params.id,
{value: this.value, _method: 'PUT'},
{headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
})
}

cant import vuex store to request file

i am trying to call a mutation when a request is sent and response has came.
this is my request file:
import axios from 'axios'
import router from '#/router'
import _ from 'lodash'
const instance = axios.create({
baseURL: process.env.BASE_URL,
timeout: 31000,
headers: {
Accept: 'application/json'
},
});
const token = localStorage.getItem('access_token');
if(!_.isNil(token)) {
instance.defaults.headers.Authorization = 'Bearer ' + token;
}
instance.interceptors.response.use(function (response) {
return response
}, function (error) {
if (error.response.status === 401) {
router.push('/introduction')
}
});
export default instance
and this is my main store
const vuexLocal = new VuexPersistence({
storage: window.localStorage
});
Vue.use(Vuex);
axios.defaults.baseURL = 'http://api.balatar.inpin.co/';
export const store = new Vuex.Store({
plugins: [vuexLocal.plugin],
modules: {
user,jobPost, company, application, cvFolder, event
},
state: {
loader:''
},
getters: {
},
mutations: {
LOADER:function (state, payload) {
state.loader=payload;
console.log('MUTATION')
}
},
actions: {
},
});
when i try to import store like below
impotr {store} from '#/store/store'
and then access the LOADER mutation like this:
store.commit('LOADER')
it returns error that cannot read property commit of undefined. how should i do this?
You should write an action, then send your request by your action and as soon as response arrives you will be able to commit a mutation
for example in the following action:
{
/**
* Login action.
*
* #param commit
* #param payload
*/
login: async function ({ commit }, payload) {
commit('LOGGING_IN')
try {
const result = await fetchApi({
url: 'http://api.example.com/login',
method: 'POST',
body: payload
})
commit('LOGIN_SUCCESS', result)
} catch (error) {
commit('LOGIN_FAILURE', error)
}
}
}
as you can see above, as soon as you call login, it calls LOGGING_IN mutation and sends a request to some address, then it waits for a response.
if it gets success response the LOGIN_SUCCESS mutation with a payload of result commits otherwise it commits LOGIN_FAILURE with a payload of cached error.
note: you should provide your own fetchApi method which is a promise.

I can't seem to find my headers in the response from my express back-end in nativescript angular response

I can't seem to find any headers in the response from my express back-end in nativescript angular response,i previously had res.header but wasn't any different.
Express back-end :
router.post('/login', (req, res) => {
User.findOne({
email: req.body.email
})
.then((foundUser) => {
if (!foundUser) res.send('Email Or Password Is Invalid');
else {
bcrypt.compare(req.body.password, foundUser.password) //compare hashed with db string
.then((validPassword) => {
if (!validPassword) res.send('Invalid Email Or Password').status(400);
else {
const token = jwt.sign({
_userID: foundUser.userID
}, config.get('jwtPrivateKey'));
res.set({
'content-type': 'application/json',
'x-auth-token': token
}).send('Logged In').status(200);
}
});
}
}).catch((err) => {
res.send('Oops something went wrong').status(500);
});
});
Nativescript Http:
onLogin(){
console.log(this.textScrap());
this.registartion.Login(this.textScrap())
.subscribe((response) => {
console.log(response);
},(err) => {
console.log(err);
},() => {
// this.router.navigateByUrl() Navigate to homePage when ready
})
}
Then I end up with this response but no header included
{
JS: "headers": {
JS: "normalizedNames": {},
JS: "lazyUpdate": null,
JS: "headers": {}
JS: },
JS: "status": 200,
JS: "statusText": "Unknown Error",
JS: "url": null,
JS: "ok": false,
JS: "name": "HttpErrorResponse",
JS: "message": "Http failure during parsing for (unknown url)",
JS: "error": {}
JS: }
I had a similar issue in NativeScript using Angular6 (and 7), and it turned out to be the Angular HttpClient rejecting empty responses with a status code of 200 instead of 204 (no content). The log showed the same message that you receive.
Even though your server code seems to send a non-empty response on successful logins ('Logged in'), you can try to add an Interceptor in your Angular appplication
to inspect the error further.
In my case I added an Interceptor which sets the body to null in case the HttpClient encounters an error and the status code indicates a successful response:
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Injectable } from '#angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpResponse,
HttpEvent,
HttpErrorResponse
} from '#angular/common/http';
#Injectable()
export class EmptyResponseBodyErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest, next: HttpHandler): Observable> {
return next.handle(req).pipe(
catchError((err: HttpErrorResponse, caught: Observable>) => {
if (err.status >= 200 && err.status &lt 300) {
const res = new HttpResponse({
body: null,
headers: err.headers,
status: err.status,
statusText: err.statusText,
url: err.url
});
return of(res);
}
throw err;
}
));
}
}
Add it to providers in your app.module.ts:
{ provide: HTTP_INTERCEPTORS, useClass: EmptyResponseBodyErrorInterceptor, multi: true },
I did not experience the same issue when running this in Chrome, Firefox or Safari, though - only in NativeScript (both Android and iOS).