CRUD APP dosent send anything to my API. Do you have an idea what the Problem could be?
On localhost:8080
I get Status 200 + "Transmission failed"
On localhost:3000
NETWORK-TAB give me Status 200. Got nothing from localhost:8080
I also checked my Cache.
Backend: (localhost:3000)
set Cors
set body-parser
Checked connection to DB is running and fetching data from the database.
Firewall:
1.disabled than tried again... nothing.
2.created incoming and outgoing rules for port 8080 and for 3000. They are active.
Frontend: (localhost:8080) Vue:
<template>
<div class="home">
<h1>Test</h1>
<div class="user-add">
<h2>Add user</h2>
<input type="text" v-model="name" /> <br />
<button #click="storeUser">Store</button>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
name:'CRUD2',
data() {
return {
user: {},
};
},
mounted() {
},
methods: {
async storeUser() {
try {
const user = await axios.post(
"http://localhost:3000/easy",
{
name: this.name,
}
);
console.log(user)
if (user.status === 201) {
console.log("Transmission successful
");
} else {
console.error("Transmission failed
");
}
} catch (error) {
console.error(error);
}
},
}
};
</script>
Backend: index.js Node(express) localhost(3000):
const express = require("express");
const oracledb = require('oracledb');
const cors = require('cors');
const bodyParser = require("body-parser");
const app = express();
app.use(express.json());
app.use(cors({
origin: 'http://localhost:8080'
}))
/* I tried also do this..
app.use(function(req, res, next) {
req.header("Access-Control-Allow-Origin", "*");
req.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});*/
app.use(bodyParser.json());
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
//GET
app.get("/easy", async (req, res) => {
let con;
try {
con = await oracledb.getConnection({
user: "user",
password: "password",
connectString: "h2922093.stratoserver.net:1521/orcl.stratoserver.net"
});
const data = await con.execute(`SELECT * FROM EASY`);
res.json(data.rows);
} catch (err) {
console.error(err);
res.sendStatus(500);
} finally {
if (con) {
await con.close();
}
}
});
//POST
app.post("/easy", async (req, res) => {
let con;
try {
con = await oracledb.getConnection({
user: "user",
password: "password",
connectString: "h2922093.stratoserver.net:1521/orcl.stratoserver.net"
});
const body = req.body;
const sql = `INSERT INTO EASY (NAME)
VALUES (:name)`;
const result = await con.execute(sql, [
body.name,
]);
if(result.rowsAffected){
res.send({
message: `${result.rowsAffected} row(s) inserted`,
status: 201
})
}else {
res.sendStatus(500);
}
} catch (err) {
console.error(err);
res.sendStatus(500);
} finally {
if (con) {
await con.close();
}
}
});
app.listen(3000, () => {
console.log("Server started on http://localhost:3000");
});
localhost:8080
localhost:8080
localhost:3000
`
`I tried:
Check my code in Backend;
Check my code in Frontend;
Backend: (localhost:3000)
-set Cors
-set body-parser
-Checked connection to DB is running and fetching data from the database.
Firewall:
1.disabled than tried again... nothing.
2.created incoming and outgoing rules for port 8080 and for 3000. They are active.
I´m expecting:
to send POST {test2} from localhost:8000 to localhost:3000 and INSERT test2 into Table EASY`
I solved the Issue myself:
Frontend:
async addData() {
//You can give an id for your input (id="nameInput")
const name = nameInput.value;
nameInput.value = "";
fetch('http://localhost:3000/easy', {
headers: {
'Content-type': 'application/json'
},
method: 'POST',
body: JSON.stringify({
name: name
})
})
.then(response => response.json())
}
}
Backend:
And please not forget in backend in your index.js file to define (and install of course the pakets):
const express = require('express');
const app = express();
const cors = require('cors');
const oracledb = require('oracledb');
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
I tested with Postman:
Get Request works properly that means I got only the one Object and Status 200 back
[{
“NAME”: “Test”
}]
Post Request http: //localhost:3000/easy: I send it as a JSON : { “name”: “test2”} and I got also the message Status 201. But that is strange because nothing was inserted into my table or see anything on my localhost:3000/easy except the one Object with the name: Test.
{
"message": "1 row(s) inserted",
"status": 201
}
I set also the headers:
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
And I changed the CORS Library to cors-express: const cors = require('cors-express');
Related
I have sent a GET request using clash of clans API and axios and provided the authentication for it to work locally however it doesn't work when deployed as heroku uses dynamic Ip addresses.
I am looking to use static Ip addresses which Heroku will use to authorize my api request. I have chosen fixie however I dont think my server is actually using the static IP as when navigate to the endpoint, the page fails and the network tab shows a remote connection from what seems to be a heroku IP address. Essentially I need to whitelist an Ip.
Here is my code:
require("dotenv").config();
const express = require("express");
const axios = require("axios");
const app = express();
const path = require('path');
const url = require('url');
const fixieUrl = url.parse(process.env.FIXIE_URL);
const requestUrl = url.parse('https://api.clashofclans.com/v1/players/%232889v22uq');
// const URL = "https://api.clashofclans.com/v1/players/%232889v22uq";
const options = {
headers: {
Host: requestUrl.host,
'Proxy-Authorization': `Basic ${Buffer.from(fixieUrl.auth).toString('base64')}`,
"Authorization": `Bearer ${process.env.API_TOKEN}`
},
host: fixieUrl.hostname,
port: fixieUrl.port,
path: requestUrl.href,
};
app.get("/api", (req, res) => {
const clashReq = async () => {
try {
const response = await axios.get(requestUrl, options);
const {
name,
townHallLevel,
trophies,
bestTrophies,
builderHallLevel,
league: {
name: leagueName,
iconUrls: { medium: mediumIcon },
},
legendStatistics: {
previousSeason: { trophies: previousTrophies},
bestSeason: { trophies: bestSeasonTrophies},
currentSeason: { trophies: currentTrophies},
},
} = response.data;
res.json({
name,
townHallLevel,
trophies,
bestTrophies,
builderHallLevel,
leagueName,
mediumIcon,
previousTrophies,
bestSeasonTrophies,
currentTrophies
}
);
} catch (error) {
console.log(error);
}
};
clashReq();
console.log(res.statusCode);
});
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "/client/build")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "/client/build", "index.html"));
});
}
app.listen(process.env.PORT || 3001, () => {
console.log(`Server running`);
});
Axios can make HTTPS requests over a proxy out of the box. You just need to provide a proxy configuration object in options:
const axios = require('axios');
const url = require('url');
const fixieUrl = url.parse(process.env.FIXIE_URL);
const fixieAuth = fixieUrl.auth.split(':');
axios.get('https://example.com', {
proxy: {
protocol: 'http',
host: fixieUrl.hostname,
port: fixieUrl.port,
auth: {username: fixieAuth[0], password: fixieAuth[1]}
}
}).then(response => {
console.log(response.status);
});
If you do this, you can remove the Proxy-Authorization and Host headers, as well as the explicit host, port, and and path options.
What Axios is doing under the hood is that it makes a CONNECT request to Fixie to open an HTTP tunnel to the remote, and the request to the remote is then made over that tunnel. This is different than how an HTTP request is proxied, but Axios abstracts that difference away.
I have a nextjs app with a backend api where I am sending an email out.
I have seen a couple of other posts with the same issue, have tried their resolutions and not sure what I am missing.
Any insight is appreciated.
The code in the API is below.
const nodemailer = require('nodemailer');
export default function (req, res) {
const mailData = {
from: 'xxxxx',
to: req.body.email,
subject: 'Message to Full On Consulting',
text: req.body.message,
html: '<div>'+req.body.message+'</div>'
}
sendMail(mailData)
.then((result) => {
console.log('Email sent...', result);
res.status(200).json({ status: 'SUCCESS' })
})
.catch((error) => console.log('Error ... ' + error.message));
}
async function sendMail(mailData) {
try {
let transport = nodemailer.createTransport({
host: "mail.xxxxxxxxxx.com",
port: 587,
secure: false,
auth: {
user: process.env.GMAIL_UID,
pass: process.env.GMAIL_PW
}
});
const result = await transport.sendMail(mailData)
return result;
} catch (error) {
console.log("CATCH ERROR: " + error)
return error;
}`enter code here`
}
I wrapped the sendmail call in a promise and that seems to have worked.
var promise = new Promise( (resolve, reject) => {
let result = transport.sendMail(mailData);
});
promise.then( result => {
console.log("PRomise Success ...");
}, function(error) {
console.log("Promise Failure...");
});
When implementing an auth GraphQL module a resolver calls an external API via RESTDataSource.
async logout() {
return await this.post('/logout', { credentials: 'include' })
}
This return an empty body object (expected) and headers that include * Set-Cookie: access_token=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT
The expected result is that the access_token cookie is deleted from the browser. If this is called directly using fetch then it happens but not when done via GraphQL.
Here is the setup:
# Resolver
Mutation: {
logout: async (_parent, _args, context) => {
const api = context.injector.get(UserAPI);
const response = await api.logout();
return response;
},
},
and the server...
# Apollo Server
function apolloGraphqlServer(app: Express) {
const server = new ApolloServer({
schema,
context: ({ req }): { token: string } => {
return {
token: req.headers.authorization,
};
},
introspection: true,
});
server.applyMiddleware({ app });
}
and the client (on Express)
const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: new SchemaLink({
schema,
context: {
session: req,
token: authCookie ? `Bearer ${authCookie}` : null,
},
}),
credentials: 'include',
ssrMode: true,
});
How do I get the cookie to delete given the response
Solved this with passing the response into the context...
const server = new ApolloServer({
schema,
context: ({ req, res }): { token: string; res: Response } => {
return {
token: req.headers.authorization,
res,
};
},
});
and then in the datasource, intercepting the received response and setting the header if available.
# datasource
didReceiveResponse(response: Response, request: Request) {
if (response.headers.get('set-cookie')) {
this.context.res.set('set-cookie', response.headers.get('set-cookie'));
}
return super.didReceiveResponse(response, request);
}
Not sure if this is the most elegant solution but works for now
I wrote a Sapper app with session management following the RealWorld example:
polka()
.use(bodyParser.json())
.use(session({
name: 'kidways-app',
secret: 'conduit',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 31536000
},
store: new FileStore({
path: 'data/sessions',
})
}))
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
pdfMiddleware,
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
Then on my _layout.sevlte:
<script context="module">
export async function preload({ query }, session) {
console.log('preload', session)
return {
// ...
};
}
</script>
<script>
import { onMount, createEventDispatcher } from 'svelte';
import { Splash } from 'project-components';
import * as sapper from '#sapper/app';
import { user } from '../stores';
import client from '../feathers';
const { session } = sapper.stores();
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});
console.log($session)
</script>
<h1>{$session.token}</h1>
This work on client side rendering, but the token is still undefined on preload, making my SSR template rendering broken.
What did I missed?
When a page renders, session is populated according to the return value of the function you specified here:
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
So while the client may have an up-to-date token, it won't take effect on page reload unless you somehow persist the token to the server in such a way that the session middleware knows about it.
Typically you'd achieve this by having a server route, like routes/auth/token.js or something...
export function post(req, res) {
req.session.token = req.body.token;
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end();
}
...and posting the token from the client:
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
await fetch(`auth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token })
});
// writing to the session store on the client means
// it's immediately available to the rest of the app,
// without needing to reload the page
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});
I've read several articles about this, but none of them work for me.
https://github.com/graphql/express-graphql/issues/14
Here is my expressjs code:
app.use("/graphql", function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
// apply graphql middleware
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootResolver,
graphiql: true,
}))
If I do it this way, the pre-flight OPTIONS is successful, but the actual POST request fails.
I am using this function to make request to local graphql server.
function postFn(url, payload) {
return $.ajax({
method: 'POST',
url: url,
contentType: 'application/json',
xhrFields: {
withCredentials: true
},
data: payload
});
}
Here is the front-end code to trigger the POST request:
let query = `
query myqury($offset: Int, $limit: Int) {
clients(limit:$limit , offset:$offset ) {
docs{
_id
full_name
}
total
limit
offset
}
}
`
var variables = {
offset: offset,
limit: limit
}
let payload = {
query: query,
variables: variables
}
return request.post(graphQlEndpoint, payload)
The error message is:
No 'Access-Control-Allow-Origin' header is present on the requested resource
I had the same issue as you. Using the graphQL on an express server.
Try using express cors
Use it in your express code like this
const express = require( `express` );
const graphqlHTTP = require( `express-graphql` );
const cors = require( `cors` );
const app = express();
app.use( cors() );
app.use(
`/graphql`,
graphqlHTTP( {
schema: schema, // point to your schema
rootValue: rootResolver, // point to your resolver
graphiql: true
} )
);
Fetch example based on GraphQL Documentation
fetch( url, {
method : `post`,
headers: {
'Content-Type': `application/json`,
'Accept' : `application/json`
},
body: JSON.stringify( {
query: `
{
person {
name
}
}`
} )
} )
.then( response => response.json() )
.then( response => console.log( response ) );
I had the same issue when making calls using Vue client. The only way I could resolve was to disable the Cross-Origin restriction on the browser for testing purposes.
Please insert below code in your server.js file
const graphQLServer = express();
const corsOptions = {
origin(origin, callback) {
callback(null, true);
},
credentials: true
};
graphQLServer.use(cors(corsOptions));
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type,token');
next();
}
graphQLServer.use(allowCrossDomain);
I think this may solve your problem