I'm attempting to set up a android application in react-native and it's calling a local API.
Ideally here I'd like the see the API request actually succeed or at least return me a formatted GraphQL exception that should be produced in my back-end.
My GraphQL api is running on localhost:3000
I've already tried the generic solutions for my any question that I've stumbled across
Set up an android emulator HTTP proxy to 10.0.2.2:3000
I've set up the ApolloClient like so
const client = new ApolloClient({
link: new HttpLink({
uri: Platform.select({
android: 'http://"my machine ip here" / ipv4 /graphql'
})
}),
cache: new InMemoryCache(),
});
I've also tried
const client = new ApolloClient({
link: new HttpLink({
uri: Platform.select({
android: 'http://10.0.2.2:3000/graphql'
})
}),
cache: new InMemoryCache(),
});
The API request is made here:
const [login, {data, loading, error}] = useMutation(LoginUserMutation);
return <LoginWrapper>
<Formik
initialValues={{email: '', password: ''}}
onSubmit={async ({email, password}) => {
const user = await login({variables: {email, password}});
}}
>
{({
values,
handleChange,
errors,
setFieldTouched,
touched,
isValid,
handleSubmit
}) => <>
<Input
value={values.email}
onChangeText={handleChange('email')}
onBlur={() => setFieldTouched('email')}
placeholder='E-mail'
/>
<Input
value={values.password}
onChangeText={handleChange('password')}
placeholder='Password'
onBlur={() => setFieldTouched('password')}
secureTextEntry={true}
/>
<Button
onClick={handleSubmit}
text='Sign In'
/>
</>}
</Formik>
</LoginWrapper>
};
The graphql mutation can be seen here
export const LoginUserMutation =
gql(
mutation('loginUser',
params(
{
$args: 'LoginUserInput!'
},
{
updateUser: params({args: '$args'},
{
email: types.string,
}
),
})
)
);
Image of error can be found here -
https://imgur.com/a/6odLPnU
Partial stack trace here -
Possible Unhandled Promise Rejection (id: 0):
Error: Network error: Response not successful: Received status code 400
ApolloError#blob:http://localhost:8081/86efb950-3eff-404f-bc63-41535a310e3a:92518:28
error#blob:http://localhost:8081/86efb950-3eff-404f-bc63-41535a310e3a:93755:30
notifySubscription#blob:http://localhost:8081/86efb950-3eff-404f-bc63-41535a310e3a:141965:20
onNotify#blob:http://localhost:8081/86efb950-3eff-404f-bc63-41535a310e3a:142004:23
So I've solved the problem.
The mutation should have been
export const LoginUserMutation = gql(
mutation('login',
params({$args: 'LoginUserInput!'}, {
login: params({args: '$args'}, {
token: types.string,
}),
})
)
);
The calling of the mutation should have been
const [login, {data, loading, error}] = useMutation(LoginUserMutation);
await login({variables: {args: {email, password}}})
Related
I've checked the redux toolkit docs and don't see an example of this typical use case: do not send the request of the query has an invalid param.
For example, a get request to endpoint /categories/{name} requires a name value. If name does not have a value, then the request should not be made.
const baseQuery = fetchBaseQuery({
baseUrl: Constants.PATHWAY_API_URL
});
export const pathwayApi = createApi({
reducerPath: 'pathwayApi',
baseQuery: baseQueryWithReAuth,
endpoints: builder => ({
getSubCategories: builder.query({
// NETWORK REQUEST SHOULD NOT BE MADE IF "name" param is falsy
query: name => `${Constants.PATHWAY_API.CATEGORIES_PATH_NAME}/${name}`,
}),
}),
});
I want to add this type of param validation to all my queries that require a param value or values. What's the recommended approach / pattern for handling this validation at the createApi (or possibly fetchBaseQuery) layer?
Thanks in advance!
You can actually throw an error in your query function.
export const pathwayApi = createApi({
reducerPath: "pathwayApi",
baseQuery: baseQueryWithReAuth,
endpoints: (builder) => ({
getSubCategories: builder.query({
// NETWORK REQUEST SHOULD NOT BE MADE IF "name" param is falsy
query: (name) => {
if (!name) {
throw new Error("Category name is required.");
}
return `${Constants.PATHWAY_API.CATEGORIES_PATH_NAME}/${name}`;
}
})
})
});
When this happens, your hook will have isError: true but no network request will be made. The error property of your hook will be a SerializedError object with properties name, message and stack, which you can use to display the error in your UI.
This is the same type of error object that you get if you have a TypeError somewhere in your code. Note that JavaScript errors will have error.message while API errors (FetchBaseQueryError) will have error.error.
const Category = ({ name }) => {
const { data, error, isError } = useGetSubCategoriesQuery(name);
return (
<div>
<h3>Name: "{name}"</h3>
{isError && (
<div>{error?.error ?? error?.message}</div>
)}
</div>
);
};
CodeSandbox Link
When user register from client side(mobile app) , user automatically login app i dont want auto login so, I did some research, I had to use a firebase cloud function to solve this.
But I get a few errors when calling the function , how can i fix these errors
First error :
Access to XMLHttpRequest at 'https://***.cloudfunctions.net/createUser' from origin 'http://localhost:8100' 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.
second error :
zone-evergreen.js:2845 POST https://****.cloudfunctions.net/createUser net::ERR_FAILED
Third Error
core.js:4197 ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "https://***.cloudfunctions.net/createUser", ok: false, …}
Firebase Console log
2:02:23.363 ÖS
createUser
Function execution started
2:02:23.390 ÖS
createUser
Function execution took 28 ms, finished with status: 'crash'
cloud function :
const functions = require('firebase-functions');
const cors = require('cors')({ origin: true });
const admin = require('firebase-admin')
admin.initializeApp();
exports.createUser = functions.https.onRequest((request, response) => {
return cors(req, res, () => {
if (request.method !== "POST") {
response.status(405).send("Method Not Allowed");
} else {
let body = request.body;
const email = body.email;
const password = body.password;
admin.auth().createUser({
email: email,
emailVerified: false,
password: password,
})
.then((userRecord) => {
return response.status(200).send("Successfully created new user: " +userRecord.uid);
})
.catch((error) => {
return response.status(400).send("Failed to create user: " + error);
});
}
})
});
client side :
signUp(email,password){
let body = {
email : email,
password : password
}
this.http.post(
'https://****.cloudfunctions.net/createUser',
body
).subscribe(a=>{console.log("Work")});
}
EDIT (new cloud function code) :
1st and 2nd bug fixed 3 still continues but I can create users.
exports.createUser = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', ' POST, OPTIONS');
res.set('Access-Control-Allow-Headers', '*');
if (req.method === 'OPTIONS') {
res.end();
}
else {
let body = req.body;
console.log(body.email)
console.log("body.password")
const email = body.email;
const password = body.password;
admin.auth().createUser({
email: email,
emailVerified: false,
password: password,
})
.then((userRecord) => {
return res.status(200).send("Successfully created new user: " +userRecord.uid);
})
.catch((error) => {
return res.status(400).send("Failed to create user: " + error);
});
}
});
Cross origin error has many reason, first problem is your current url that probably like a ads url, please change the url pattern and clear browser cache. If you are using a VPN turn off it. The Chrome blocks url that contain ads url. This problem is not happen on production environment.
If your problem not fixed with top solution, use chrome in security disable mode.
Open start menu and type chrome.exe --disable-web-security and
make sure that this headers set in your backend
header('Access-Control-Allow-Origin: *');
header('Access-Control-Request-Method:*');
header('Access-Control-Allow-Headers: Origin,token, Authorization, X-Requested-With, Content-Type, Accept');
header('Access-Control-Allow-Credentials: true');
when I try to make requests to a server running on localhost:8080, it sometimes gives a 404 or 405 error depending on the type of request. most recently this has happened when I try unit testing via JEST.
I know for a fact there's nothing wrong with the actual code because it works perfectly fine when other people run it on their PCs.
the exact same fetch requests that fail in unit tests work perfectly fine within a web application.
I first noticed this problem on Postman. The problem seems to occur when I try making requests just before or after the server has started listening, and then I have to wait for a bit before requests work again. Of course it makes sense that it wouldn't work when my server isn't listening yet, but the problem persists for a while after it does. This problem usually doesn't occur on postman anymore now that I make sure to wait for the server to start listening.
here's the response with a GET or POST request:
<!DOCTYPE html>
<html><head><title>Not Found</title></head>
<body>
<h2>Access Error: 404 -- Not Found</h2>
<pre>Cannot open document for: /myroute/mypath</pre>
</body>
</html>
with a PUT request:
<!DOCTYPE html>
<html><head><title>Method Not Allowed</title></head>
<body>
<h2>Access Error: 405 -- Method Not Allowed</h2>
<pre>The "PUT" method is not supported by file handler</pre>
</body>
</html>
simple versions of the code I'm working with (again, I know for a fact this code works on a PC other than mine)
const mongoose = require('mongoose');
require('../src/model/logboekTemplate.js');
const fetch = require('node-fetch');
const SERVERIP = "http://localhost:8080/logboeken/"
const dbName = 'rekenlogboek';
const Logboek = mongoose.model('Logboek');
describe('Logboeken route Tests', () => {
beforeAll(async () => {
mongoose.connect(`mongodb://localhost:27017/${dbName}`, { useUnifiedTopology: true, useNewUrlParser: true, retryWrites: false }).then().catch(err => {
console.log(err);
});
await Logboek.deleteMany({});
});
beforeEach(async () => {
await Logboek.create([
{
naam: "testlogboek",
},
]);
});
afterEach(async () => {
await Logboek.deleteMany({});
});
//laat de gehele lijst logboeken zien
test('get /logboeklijst', async () => {
let response = await fetch(SERVERIP + "/logboeklijst", {
method: 'get', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
});
expect(response.status).toEqual(201);
let body = await response.json()
expect(body[0].naam).toEqual("testlogboek");
})
})
This server works perfectly fine normally, it's just the unit tests that fail and even then only when I do it on my laptop.
const express = require('express')
const http = require('http')
const mongoose = require('mongoose');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
const server = http.createServer(app);
app.use(bodyParser.text());
app.use(bodyParser.json());
app.use(cors());
const { logboekRouter } = require('./routes/logboeken');
app.use('/logboeken', logboekRouter);
//-------------------------------------//
//Mongoose
//-------------------------------------//
let dbName;
dbName = "rekenlogboek";
mongoose.connect(`mongodb://localhost:27017/${dbName}`, { useUnifiedTopology: true, useNewUrlParser: true, retryWrites: false }).then().catch(err => {
console.log(err);
});
server.listen(8080,
function () {
console.log("The Server is listening on port 8080.")
});
and the command line
> project-tests#1.0.0 test C:\Users\Wouter\Documents\GitHub\{my project}
> jest --runInBand --verbose
(node:23248) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
console.warn
Mongoose: looks like you're trying to test a Mongoose app with Jest's default jsdom test environment. Please make sure you read Mongoose's docs on configuring Jest to test Node.js apps: http://mongoosejs.com/docs/jest.html
at Object.<anonymous> (deployment/node_modules/mongoose/lib/helpers/printJestWarning.js:4:11)
at Object.<anonymous> (deployment/node_modules/mongoose/lib/index.js:46:1)
FAIL deployment/routes/logboeken.test.js
Logboeken route Tests
× get /logboeklijst (42 ms)
● Logboeken route Tests › get /logboeklijst
expect(received).toEqual(expected) // deep equality
Expected: 201
Received: 404
212 | mode: 'cors', // no-cors, *cors, same-origin
213 | });
> 214 | expect(response.status).toEqual(201);
| ^
215 | let body = await response.json()
216 | expect(body[0].naam).toEqual("testlogboek");
217 | })
at Object.<anonymous> (deployment/routes/logboeken.test.js:214:33)
at runMicrotasks (<anonymous>)
I'm implementing auth on my website using googleapis. The function plus.people.get doesn't work. I have seen it is deprecated on some forums but it's still documented at google which has me confused. The error I get is "Legacy People API has not been used in project 328985958128 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/legacypeople.googleapis.com then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry." The webpage doesn't even load. My code is
if (!req.body.token) return res.status(500).json({ type: 'error', message: 'No access token provided.' })
const OAuth2 = google.auth.OAuth2
const oauth2Client = new google.auth.OAuth2(keys.client_id, keys.client_secret)
google.options({ auth: oauth2Client });
const plus = google.plus('v1')
oauth2Client.setCredentials({
access_token: req.body.token
})
plus.people.get({
userId: 'me',
auth: oauth2Client
}, (error, response) => {
if (error)
console.log(error)
return res.status(500).json({ type: 'error',error })
const emails = (response.data || {}).emails
You are using google.plus('v1'), which has been deprecated
Instead you should use
const service = google.people({version: 'v1', auth: oauth2Client})
to create a service object.
To perform a request an additional auhtorization is not required anymore, so:
service.people.get({
userId: 'me'
}, (error, response) => {
...
})
Further information:
Creating a service account client with node.js
People API quide for node.js
Forgive me if it's a silly question, but the last time I coded in javascript was almost 20 years ago... I'm re-learning javascript these weeks and I'm not sure I got it all.
I'm using hapi with rest-hapi and want to add some standalone endpoints, basically translating the backend portion of this Autodesk tutorial form express.
I'm using the basic rest-hapi example main script, and tried to add a route with the following code:
//api/forge.js
module.exports = function(server, mongoose, logger) {
const Axios = require('axios')
const querystring = require('querystring')
const Boom = require('boom')
const FORGE_CLIENT_ID = process.env.FORGE_CLIENT_ID
const FORGE_CLIENT_SECRET = process.env.FORGE_CLIENT_SECRET
const AUTH_URL = 'https://developer.api.autodesk.com/authentication/v1/authenticate'
const oauthPublicHandler = async(request, h) => {
const Log = logger.bind('User Token')
try {
const response = await Axios({
method: 'POST',
url: AUTH_URL,
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
data: querystring.stringify({
client_id: FORGE_CLIENT_ID,
client_secret: FORGE_CLIENT_SECRET,
grant_type: 'client_credentials',
scope: 'viewables:read'
})
})
Log.note('Forge access token retrieved: ' + response.data.access_token)
return h.response(response.data).code(200)
} catch(err) {
if (!err.isBoom){
Log.error(err)
throw Boom.badImplementation(err)
} else {
throw err
}
}
}
server.route({
method: 'GET',
path: '/api/forge/oauth/public',
options: {
handler: oauthPublicHandler,
tags: [ 'api' ],
plugins: {
'hapi-swagger': {}
}
}
})
}
The code works and I can display the access_token in nodejs console, but swagger doesn't get the response:
At first I thought that an async function cannot be used as handler, but my hapi version is 17.4.0, and it supports async handlers.
What am I doing wrong?
It turns out it was an easy fix: I just needed to specify the Hapi server hostname in my main script!
The problem was with CORS, since Hapi used my machine name instead of localhost. Using
let server = Hapi.Server({
port: 8080,
host: 'localhost'
})
solved my problem.