Proper Use of Redux-Ovservable ajax http methods: put, delete, post - rxjs5

I'm new to Redux and Redux-Observable. I'm having success in getting information from a rest API with GET and GET(ID), but I cannot get the Delete and Post to work. Sample code below that is issuing a GET request:
[EPIC File]
import { debounceTime, Observable } from 'rxjs';
import { ajax } from 'rxjs/observable/dom/ajax';
import ActionTypes from '../actions/ActionTypes';
import { receiveFeedBack, receiveDeleteFeedBackId,
receiveFeedBackId } from '../actions/FeedBackActions';
export const fetchFeedBack = (action$) => ... Working
export const fetchFeedBackId = (action$) => ... Working
//Not Working
export const deleteFeedBackById = (action$) =>
action$.ofType(ActionTypes.DELETE_FEEDBACK_REQUEST)
.debounceTime(500)
.switchMap(action =>
ajax.delete(`${ActionTypes
.FEEDBACK__URL}/posts/${action.payload.feedbackId}?key=${ActionTypes
.FEEDBACK__API_KEY}`)
.map(receiveDeleteFeedBackId.bind(action))
.takeUntil(action$.ofType(ActionTypes.DELETE_FEEDBACK_CANCELED))
.catch(error => Observable.of({
type: ActionTypes.DELETE_FEEDBACK_ERROR,
payload: error
}))
);
What am I doing wrong?

Related

Axios requests front-end instead of server

I have used breeze-next as a boilerplate.
User register and login work perfectly but when I create a custom hook to interact with the server, Axios sends requests to front-end address, instead of the server.
I have declared the server address in .env file:
NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
Axios configuration:
import Axios from 'axios'
const axios = Axios.create({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
withCredentials: true,
})
export default axios
My custom hook:
export const useAccount = () => {
const csrf = () => axios.get('/sanctum/csrf-cookie')
const {data: user, error, mutate} = useSWR('/api/user', () =>
axios
.get('/api/user')
.then(res => res.data)
.catch(error => {
if (error.response.status !== 409) throw error
router.push('/verify-email')
}),
)
const start = async ({setErrors, setStatus, ...props}) => {
await csrf() // <-- Fails Here
axios.post('/user/account/start', props)
.then(() => mutate())
.catch(error => {
setErrors(Object.values(error.response.data.errors).flat())
})
}
return {
start
}
}
When axios sends a get request it sends the request to http://localhost:3000/sanctum/csrf-cookie which is the front-end address.
The problem was with wrong import.
I didn't pay attention to what file is IDE importing as axios into account Hook.
It was like this:
import axios from "axios"
So I changed it to:
import axios from "#/lib/axios"

How to test nestjs with graphql by end to end?

In the test/posts/posts.e2e-spec.ts file
import { INestApplication } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Test, TestingModule } from '#nestjs/testing';
import request = require('supertest');
import { PostsModule } from '../../src/posts/posts.module';
describe('Posts (e2e)', () => {
const posts = {
id: 1,
name: 'FirstPost #1',
};
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
...
}),
PostModule,
],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
describe('post', () => {
it('should retrieve all post data', async () => {
request(app.getHttpServer())
.post('/graphql')
.send({
query:
`{findPosts() {
name
}}`,
})
.expect(200)
.expect((res) => {
console.log(res.body.data)
expect(res.body.data.post.length).toEqual(posts.length)
})
})
})
});
I created migration and inserted data into database first, then run this test, it can't go to the expect items. Even set console log I can't see anything in the output.
So maybe the /graphql can't be access in this way? I can access the endpoint from browser as http://localhost:3000/graphql.
If import supertest as
import * as request from 'supertest';
In the line request it showed:
This expression is not callable. Type ‘typeof supertest’ has no call signatures.
The version of them:
supertest: 6.1.3
#types/supertest: 2.0.11
Check out this very useful link https://github.com/jmcdo29/testing-nestjs/tree/main/apps/graphql-sample. It explains a lot of things regarding tests including graphql nestjs testing along with sample application

admin-on-rest / restClient : call a resource with no auth

I made a register page that use restClient to send a POST to /users api.
But my problem is that the only way to send a POST is to be logged first as I receive this error log from the restClient :
'Could not find stored JWT and no authentication strategy was given'
Is there a way to desactivate the authentication middleware for a specific api call ?
// registerActions.js
import { CREATE } from 'admin-on-rest'
export const USER_REGISTER = 'AOR/USER_REGISTER'
export const USER_REGISTER_LOADING = 'AOR/USER_REGISTER_LOADING'
export const USER_REGISTER_FAILURE = 'AOR/USER_REGISTER_FAILURE'
export const USER_REGISTER_SUCCESS = 'AOR/USER_REGISTER_SUCCESS'
export const userRegister = (data, basePath) => ({
type: USER_REGISTER,
payload: { data: { email: data.username, ...data } },
meta: { resource: 'users', fetch: CREATE, auth: true },
})
//registerSaga.js
import { put, takeEvery, all } from 'redux-saga/effects'
import { push } from 'react-router-redux'
import { showNotification } from 'admin-on-rest'
import {
USER_REGISTER,
USER_REGISTER_LOADING,
USER_REGISTER_SUCCESS,
USER_REGISTER_FAILURE
} from './registerActions'
function* registerSuccess() {
yield put(showNotification('Register approved'))
yield put(push('/'))
}
function* registerFailure({ error }) {
yield put(showNotification('Error: register not approved', 'warning'))
console.error(error)
}
export default function* commentSaga() {
yield all([
takeEvery(USER_REGISTER_SUCCESS, registerSuccess),
takeEvery(USER_REGISTER_FAILURE, registerFailure),
])
}
You'll probably have to make your own feathers client and explicitly bypass the call to authenticate for this specific request
You can also write a rest wrappper this will intercept the call for this particular case and bypass auth
https://marmelab.com/admin-on-rest/RestClients.html#decorating-your-rest-client-example-of-file-upload
So something like below
const restWrapper = requestHandler => (type, resource, params) => {
import { fetchUtils } from 'admin-on-rest';
if (type === 'CREATE' && resource === 'users') {
return fetchUtils.fetchJson(url, params)
.then((response) => {
const {json} = response;
return { data: json };
})
}
Eliminates the need of rewriting an entire Rest Client when you only want to override the default behaviour for a single case

nock: reply is not a function

I am using nock to intercept my http requests in a mocha / chai environment. Also i am using supertest and supertest-chai to query my own express server. Like this:
import { it } from 'mocha';
import chai, { should } from 'chai';
import request from 'supertest';
import supertestChai from 'supertest-chai';
import Joi from 'joi';
import chaiJoi from 'chai-joi';
// others
function itRespondsTo({ url, response, description, parameters = {} }) {
const maxAge = parameters.maxAge || serverConfig.defaultCacheAge;
const params = parameters ? `${Object.entries(parameters).map(([name, val]) => `&${name}=${val}`).join('&')}` : '';
const path = `/oembed?url=${encodeURIComponent(url)}${params}`;
const desc = description || `/oembed?url=${url}${params}`;
it(`should respond to ${desc}`, (done) => {
request(server)
.get(path)
.expect(200)
.expect('Content-Type', /json/)
.expect('Access-Control-Allow-Methods', 'GET')
.expect('Cache-Control', `public, max-age=${maxAge}`)
.expect(res => Object.values(OEMBED_TYPES).should.include(res.body.type)) // [1]
.expect(res => Joi.validate(res.body, OEMBED_SCHEMAS[res.body.type]).should.validate)
.expect(response)
.end(done);
});
}
describe('YouTube endpoint', () => {
beforeEach(() => {
nock(/youtube\.com/)
.reply(200, remoteResponse);
});
afterEach(() => {
nock.restore();
});
itRespondsTo({ url: 'https://youtu.be/m4hklkGvTGQ', response });
itRespondsTo({ url: 'https://www.youtube.com/embed/m4hklkGvTGQ', response });
itRespondsTo({ url: 'https://www.youtube.com/watch?v=m4hklkGvTGQ', response });
itRespondsTo({ url: 'https://www.youtube.com/?v=m4hklkGvTGQ', response });
});
When I run my tests, the first call of itRespondsTo will always throw an error:
1) YouTube endpoint "before each" hook for "should respond to /oembed?url=https://youtu.be/m4hklkGvTGQ":
TypeError: nock.reply is not a function
And it will always be the first call of itRespondsTo. If I remove the first call, the next call will throw the error and so on. I have no idea why this is happening.
I found the reason I got an error. I had to put a get in between:
nock('https://www.youtube.com')
.get('/oembed')
.query(true)
.reply(200, remoteResponse);

Angular2: How to make several GET requests at once

With a promise JS library (https://github.com/stackp/promisejs) I can make this:
promise.join([
promise.get('/settings'),
promise.get('/translations'),
promise.get('/main-data')
]).then(function(results) {
console.log(results);
});
Now I need to do this with Angular2. So I made a service with methods getSettings, getTranslations, etc. - but how do I join them in the component that uses this service ?
(And join them in such way that when and only when all requests finish - I'll run a functionality that uses all the responses?)
You can use the forkJoin operator for this
import {Observable} from 'rxjs/Rx';
//...some code
Observable.forkJoin(
this.http.get('/settings').map((res:Response) => res.json()),
this.http.get('/translations').map((res:Response) => res.json())
)
.subscribe(data => {
console.log(data[0], data[1]);
});
The answer didn't solved the problem, mostly because I didn't understand how to get the data in the component. But it still guided me very well :)
So, here is the final code:
// Service - "AppService.ts":
import {Observable} from 'rxjs/Rx';
export class AppService {
getAllData() {
return Observable
.forkJoin(
this._http.get('/settings').map(res => res.json()),
this._http.get('/translations').map(res => res.json())
)
}
}
// Component - "AppComponent.ts":
import {AppService} from './app.service';
export class AppComponent {
AllData = {};
appService
.getAllData()
.subscribe(
data => {
console.log('Responses from AJAX:');
console.log(data);
this.AllData = JSON.stringify(data)
},
error => alert(error)
);
}

Resources