How to make requests to GraphQL-server from my redux action? - javascript

I have react+redux application and I want to replace rest-requests in my actions to grapqhl-requests. What is the most simple method to do it?
I read about apollo, but I just to want add graphql in my existing requests.

You must change the way you will get the data because Apollo is a layer between you and the Api requested where you can join many Apis into one single query call.
The example above is very simple and just to explain the way will place your querys and how it connects to Apollo Server. You can set middlewares to log requests on add some headers too.
You will install [https://github.com/apollographql/react-apollo] and [https://github.com/apollographql/graphql-tag]
After that create a connection file in your project that imports
graphClient.js
import { ApolloClient, createNetworkInterface } from 'react-apollo';
const networkInterface = createNetworkInterface({
uri: 'yourserver address'
});
const client = new ApolloClient({
networkInterface,
});
export default client;
yourRequestFile.js
import gql from 'graphql-tag';
import client from './graphClient';
export const getYourData = () => ({
query: gql`
query {
products() {
info {
value {
qty
value
}
}
}
}`,
});
const returnYourData = async () => client.query(getYourdata());
export default returnYourData;

Related

Jest mock axios does not work if the class is initialised in the setupTests

I'm trying to test my backend class which uses axios to get some data from the backend. I've mocked axios and stubbed the get function to return some values. This works great!
However if I create a new instance of the Backend in the setupTests the test fails. If I remove the beforeEach from the setupTests and add it to the test file, the test succeeds again.
The test fails because the stub has not been called.
I'm using the setupTests to mock the dependencies for other tests. Whilst mocking this, I create a subclass instance of the Backend.
Test:
import {Backend} from "../../../shared/utils/backend";
import axios from "axios";
jest.mock("axios");
describe("backend", () => {
test("When getList is called data is returned", async () => {
(axios.get as jest.Mock) = jest.fn().mockResolvedValue(Promise.resolve({
data: [{
prop: "test",
otherProp: 2
}]
}));
const backend = new Backend("baseUrl");
const data = await backend.getList("testUrl");
expect(axios.get).toHaveBeenCalledWith("baseUrl/testUrl");
expect(data).toHaveLength(1);
});
});
SetupTests
import "#testing-library/jest-dom";
import {Backend} from "./shared/utils/backend";
new Backend("test");
Backend class
import axios from "axios";
export class Backend {
private _baseUrl: string;
constructor(baseUrl: string) {
axios.defaults.headers.get["Access-Control-Allow-Origin"] = "*";
axios.defaults.headers.get["Access-Control-Allow-Credentials"] = "true";
this._baseUrl = baseUrl;
}
async getList(url: string): Promise<any[] | undefined> {
const data = await axios.get<any[]>(`${this._baseUrl}/${url}`);
if (data) {
return data.data;
}
return undefined;
}
}
In the end I managed to circumvent the problem. My dependencies wanted a Backend in the constructor. My BackendMock was an extension of the Backend class. This resulted in implicitly creating a Backend whenever I created the mock.
I created an interface for the Backend and changed the dependencies to use the interface instead of the class. Now the Backend is no longer created and the tests now work.

"query is not a function" Next Js getServerSideprops and firebase error

I'm using NextJS and firebase as my primary database for the app that I'm currently building for an NGO. and I ran into an issue.
import {
collection,
where,
query,
getDocs
} from '#firebase/firestore';
import { db } from '../../../services/firebase';
export async function getServerSideProps({query}) {
const user = await getDocs(query(collection(db, 'members'), where('id', '==', query)))
return {
props: {
// VisionInfo: JSON.stringify(user.docs.map(item => item.data()))
json: JSON.stringify('Hello')
}
};
}
The only way to get Query from the URL in NextJS in serverSideProps is to use the keyword "query" but the same keyword is used to fetch firebase document.
The error shows "query is not a function"
Is there anyway I could get Query into serversideprops ?
The issue arises because you also have "query" in getServerSideProps parameters. Try naming the import from Firestore SDK (or the query param) as shown below:
import { query as fireQuery } from '#firebase/firestore';
export async function getServerSideProps({query}) {
const user = await getDocs(fireQuery(collection(db, 'members'), where('id', '==', query)))
// use fireQuery here ^^^
})

Problems accessing data from a GraphQL query in Javascript with Svelte

Below I have my working function using a normal REST response that I want to try to convert into a GraphQL version, it fetches a JSON doc from my Phoenix Server and stores the object values from the JSON doc into an object. The problem is, here I can use await and then assign the new object values from the object within the JSON document, but using GraphQL I cannot access this data to assign it because there is no await function as its just a Query. (From what I know)
async function updatePageWithNewCompany(company){
const res = await fetch(`http://localhost:4000/${company}`);
profile = await res.json();
profile = profile.companyProfile
DashboardStore.update(currentData => {
return {
id: profile.id,
companyName: `${profile.company_name}`,
averageLength: profile.average_length,
}
})
Ultimately I am asking if there is a way to access and assign data from a GraphQL query in JavaScript so I can manipulate it before displaying it in my frontend Svelte app.
Example of current GraphQL query:
import { gql } from '#apollo/client'
import { client } from './apollo';
import { query, setClient } from "svelte-apollo";
setClient(client)
const GET_COMPANY = gql`
query{
companyProfile(){
companyName
averageLength
}
}
`;
const response = query(GET_COMPANY)
...
svelte-apollo queries return
a svelte store of promises that resolve as values come in
as stated in the example query displayed in the documentation.
As such, you can exploit that format directly in the script section. Here is an example:
...
async function getCompany() {
const companyStore = query(GET_COMPANY)
const company = (await $companyStore).data.companyProfile
return company // format will be an object with keys { companyName, averageLength } according to your query
}
...
On a side-note I would recommend always getting the id of objects in your GraphQL queries as it is usually the key used internally by the Apollo client to manage its cache (unless explicitly stated otherwise).
I have found a working solution with the help of #Thomas-Hennes
import { client } from '../apollo.js';
import { onMount } from "svelte";
import { gql } from '#apollo/client'
export const COMPANY_LIST = gql`
query {
listCompanies{
companyName
}
}
`;
async function listCompanies() {
await client.query({query: COMPANY_LIST})
.then(res => {
companyList.update( currentData =>
[...res.data.listCompanies.companyName])})
};
onMount(() =>{
listCompanies()
})
await didn't like being assigned to a variable or having its data manipulated so i used it as a promise instead and manipulated the response.
The below link helped me find the final piece of the puzzle.
https://docs.realm.io/sync/graphql-web-access/using-the-graphql-client

How to use axios in Vue (Typescript)?

I would like to use axios in vue (Typescript) but I get into trouble with my code. This is my main.ts
import axios from 'axios'
Vue.prototype.$axios = axios
axios.defaults.baseURL = 'http://192.168.1.225:8088'
and this is my vue code
screenshot here
This is the first time I use typescript,before I used it another way in javaScript and I did not have any problem, so how can I use it in TypeScript?
Thank you for your time and solution.
I do this and work perfectly on main.ts
import Vue from 'vue';
import axios, { AxiosStatic } from 'axios';
axios.defaults.baseURL = 'http://192.168.1.225:8088';
Vue.prototype.$axios = axios;
declare module 'vue/types/vue' {
interface Vue {
$axios: AxiosStatic;
}
}
I'm encapsulate HTTP/REST operations in separate .ts files. Here I also use async/await to have better readable code. Each method declared its input and return types.
import axios from 'axios'
const http = axios.create({
baseURL: `${SOME_SERVICE_URL}/base-path`,
headers: { 'Content-Type': 'application/json' }
})
export async function getItemById (itemId: string): Promise<Item> {
const response = await http.get(`/${itemId}`)
return response.data
}
export async function createItem (item: Item): Promise<Item> {
const response = await http.post('/', JSON.stringify(item))
return response.data
}
Are you sure to use POST request? It seems like GET request because of 'GetTreeTenant' and you can try only axios instead $axios.
let uri = '<url here>';
this.axios.post(uri, data).then((response) => {
console.log(response);
});
I want to suggest you use a service for your http request using axios. I would do this by separating my http services into separate files. Say you have an API and you use a resource say hero then the code will look something like this:
// services/http.ts
import axios from 'axios';
export default axios.create({
baseURL: 'http://192.168.1.225:8088',
params: {
// API params go here
}
});
For hero service you could do this:
// services/hero.ts
import http from './http';
export default class HeroService {
getHero(heroId: string) {
return axios.get(`heroes/${heroId}`);
}
...
}
// A singleton instance
export const heroService = new HeroService();
In typescript,we can use module augmentation.
https://v2.vuejs.org/v2/guide/typescript.html#%E5%A2%9E%E5%BC%BA%E7%B1%BB%E5%9E%8B%E4%BB%A5%E9%85%8D%E5%90%88%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8
declare module 'vue/types/vue' {
interface Vue {
}}
One quick and dirty solution would be to set your Vue object to type any. TypeScript is letting you know that it doesn't recognize the $axios property on the Vue Object.
When you tell TypeScript that the Vue object can be anything, you're allowed to add whatever properties you want.
const app : any = new Vue({})

Use Jest to mock external user module in an imported module

I don't know if I'm missing something in the docs, but I have this situation:
// test.js
import User from './user'
it("should load initial data", async() => {
const users = new User()
const user = await users.load()
})
// User.js
import Api from './api'
export default class User {
async load() {
const res = await Api.fetch() // prevent/mock this in testing
}
}
What is the Jest-way to prevent/mock the external Api module in User.js. I do not want User.js to make a real network request within the test.
Further to this, I'm looking for a more generic mocking solution, ie. say I'm testing in React Native, and I want to mock NativeModules.SettingsManager.settings.AppleLocale, for example. Lets say Api.fetch() calls the line above, and doesn't make a HTTP request
spyOn in combination with mock functions like mockImplementation will provide what you are looking for.
Here is a working example:
// ---- api.js ----
export const getData = () => {
return Promise.resolve('hi');
}
// ---- user.js ----
import { getData } from './api'
export default class User {
async load() {
return await getData(); // mock this call in user.test.js
}
}
// ---- user.test.js ----
import User from './user'
import * as Api from './api'; // import * so we can mock 'getData' on Api object
describe('User', () => {
it('should load initial data', async() => {
const mock = jest.spyOn(Api, 'getData'); // create a spy
mock.mockImplementation(() => Promise.resolve('hello')); // give it a mock implementation
const user = new User();
const result = await user.load();
expect(result).toBe('hello'); // SUCCESS, mock implementation called
mock.mockRestore(); // restore original implementation when we are done
});
});
If you need to mock responses to HTTP requests, then you should check out nock. It has a clean API that allows a lot of flexibility in creating HTTP responses to specific requests.

Categories

Resources