Performing a PATCH request in Vodapay Mini-Programs - vodapay-miniprogram

I am working on a Vodapay mini-program and would like to know if it is possible to perform a PATCH request using my.request?

You cant perform PATCH requests using my.request.It only supports GET/POST. You can read a about it on the docs here.
You could try overriding the method using X-Method-Override header. This basically tells the server Hey, I know its a POST. But could you use Patch Instead?.
This may need some additional config on your backend. I had to use the method-override package for express.js.
Mini App:
my.request({
url: 'http://localhost:3000',
headers: {
'x-method-override': 'PATCH',
'content-type': 'application/json'
},
method: 'POST',
complete: (res) => {
console.log(res);
}
});
express.js backend :
const express = require('express')
const methodOverride = require('method-override')
const PORT = process.env.PORT || 3000;
const app = express();
app.use(express.json())
app.use(methodOverride('x-method-override'))
app.get('/', (req, res)=>{
res.send('in get')
})
app.post('/', (req, res)=>{
res.send('in post')
})
app.patch('/', (req, res)=>{
res.send('in patch')
})
app.listen(PORT);

Related

Apollo Express Server on Heroku and Refresh Token Cookie on Mobile Browser

Upon visiting/refresh, the app checks for a refresh token in the cookie. If there is a valid one, an access token will be given by the Apollo Express Server. This works fine on my desktop but when using Chrome or Safari on the iPhone, the user gets sent to the login page on every refresh.
React App with Apollo Client
useEffect(() => {
fetchUser();
}, []);
const fetchUser = async () => {
const res = await fetch('https://website.com/token', {
method: 'POST',
credentials: 'include',
});
const { accessToken } = await res.json();
if (accessToken === '') {
setIsLoggedIn(false);
}
setAccessToken(accessToken);
setLoading(false);
};
Apollo Client also checks if whether the access token is valid
const authLink = setContext((_, { headers }) => {
const token = getAccessToken();
if (token) {
const { exp } = jwtDecode(token);
if (Date.now() <= exp * 1000) {
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
};
}
}
fetch('https://website.com/token', {
method: 'POST',
credentials: 'include',
}).then(async (res) => {
const { accessToken } = await res.json();
setAccessToken(accessToken);
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : '',
},
};
});
});
const client = new ApolloClient({
link: from([authLink.concat(httpLink)]),
cache: new InMemoryCache(),
connectToDevTools: true,
});
This handles the token link on the Express server
app.use('/token', cookieParser());
app.post('/token', async (req, res) => {
const token = req.cookies.rt;
if (!token) {
return res.send({ ok: false, accessToken: '' });
}
const user = await getUser(token);
if (!user) {
return res.send({ ok: false, accessToken: '' });
}
sendRefreshToken(res, createRefreshToken(user));
return res.send({ ok: true, accessToken: createAccessToken(user) });
});
And setting of the cookie
export const sendRefreshToken = (res, token) => {
res.cookie('rt', token, {
httpOnly: true,
path: '/token',
sameSite: 'none',
secure: true,
});
};
Same site is 'none' as the front end is on Netlify.
After a day of fiddling and researching, I have found the issue, and one solution when using a custom domain.
The issue is that iOS treats sameSite 'none' as sameSite 'strict'. I thought iOS Chrome would be different than Safari but it appears not.
If you use your front-end, hosted on Netlify, you will naturally have a different domain than your Heroku app back-end. Since I am using a custom domain, and Netlify provides free SSL, half of the work is done.
The only way to set a httpOnly cookie is to set the cookie to secure. The next step would be to set sameSite to 'none' but as mentioned above, this does not work with iOS.
Setting the domain property of the cookie will also not work because the domain property concerns the scope of the cookie and not the cookie origin. If the cookie came from a different domain (Heroku backend), then the frontend (on Netlify) will not be able to use it.
By default, on Heroku, the free dyno will give you a domain like 'your-app.herokuapp.com', which is great because it also includes free SSL. However, for the cookie to work, I added my custom domain that I use with Netlify. To be clear, Netlify already uses my apex custom domain, so I am adding a subdomain to Heroku (api.domain.com). Cookies do work for across the same domain and subdomains with sameSite 'strict'.
The final issue with this is that the custom domain with Heroku will not get SSL automatically, which is why I think it is worth it to upgrade to a $7/month hobby dyno to avoid managing the SSL manually. This I think is the only solution when using a custom domain.
On the other hand, for those who have the same issue and would like a free solution, you can forgo using a custom domain and host your static front-end with the back-end on Heroku.
Hopefully this will save some time for anyone deploying the back-end and front-end separately.

IE 11 issue - automatically cache responses from GET requests - Reactjs

I'm making a GET request to a web service for AJAX call. Internet Explorer, is doing automatically cache responses from GET requests.
Requests work just fine for the first time i try.
As data is modified, i'm still seeing old results.
Everything appears to work correctly in other browsers.
This is the code,
export function fetchReportSet () {
return function(dispatch) {
axios.get(`${ROOT_URL}/api/reports/`, {
headers: {Pragma: 'no-cache'},
headers: {Authorization:'Token '+ localStorage.getItem('token')}
})
.then(response => {
dispatch({type: FETCH_REPORT , payload: response.data});
})
.catch(() => {
});
}
}
Any help will be appreciated.
Try to refer to this thread to add a timestamp in the url, or refer to this article to add the Cache-Control: no-cache header set.
Code like this:
import axios from 'axios';
import { cacheAdapterEnhancer } from 'axios-extensions';
const http = axios.create({
baseURL: '/',
headers: { 'Cache-Control': 'no-cache' },
// cache will be enabled by default
adapter: cacheAdapterEnhancer(axios.defaults.adapter)
});
http.get('/users'); // make real http request
this help me
axios.defaults.headers.get['Pragma'] = 'no-cache';
axios.defaults.headers.get['Cache-Control'] = 'no-cache, no-store';

Apollo Server 2 + Express: req.body missing on post handler

Had this working in version 1, but the whole server config has changed. This is what I have, after adding bodyparser() to the express app as was suggested by Daniel in the comments:
const server = new ApolloServer({
typeDefs,
resolvers,
playground: {
settings: {
'editor.theme': 'light',
}
},
})
// Initialize the app
const app = express();
app.use(cors())
app.use(bodyParser.json())
server.applyMiddleware({
app
})
app.post('/calc', function(req, res){
const {body} = req;
console.log("HOWDYHOWDYHOWDY", body) // <== body is {}
res.setHeader('content-type', 'application/json')
calculate(body)
.then(result => res.send(result))
.catch(e => res.status(400).send({error: e.toString()}))
})
The request body is never making it to the app.post handler, though the handler is called. I see it going out from the browser, though. Any ideas?
Update: Daniel had the correct answer, but I had another problem in the request headers I was using. Once I fixed that, then the post handler received the body.
Apollo's middleware applies the bodyparser middleware specifically to the GraphQL endpoint -- it won't affect any other routes your server exposes. In order to correctly populate req.body, you need to add the bodyparser middleware yourself, for example:
app.use(bodyParser.json())
app.post('/calc', routeHandler)
// or...
app.post('/calc', bodyParser.json(), routeHandler)
I just ran into this as well. Fixed it by passing the following into the headers:
Content-Type: application/json

POST binary data from browser to JFrog / Artifactory server without using form-data

So we get a file (an image file) in the front-end like so:
//html
<input type="file" ng-change="onFileChange">
//javascript
$scope.onFileChange = function (e) {
e.preventDefault();
let file = e.target.files[0];
// I presume this is just a binary file
// I want to HTTP Post this file to a server
// without using form-data
};
What I want to know is - is there a way to POST this file to a server, without including the file as form-data? The problem is that the server I am send a HTTP POST request to, doesn't really know how to store form-data when it receives a request.
I believe this is the right way to do it, but I am not sure.
fetch('www.example.net', { // Your POST endpoint
method: 'POST',
headers: {
"Content-Type": "image/jpeg"
},
body: e.target.files[0] // the file
})
.then(
response => response.json() // if the response is a JSON object
)
You can directly attach the file to the request body. Artifactory doesn't support form uploads (and it doesn't look like they plan to)
You'll still need to proxy the request somehow to avoid CORS issues, and if you're using user credentials, you should be cautious in how you treat them. Also, you could use a library like http-proxy-middleware to avoid having to write/test/maintain the proxy logic.
<input id="file-upload" type="file" />
<script>
function upload(data) {
var file = document.getElementById('file-upload').files[0];
var xhr = new XMLHttpRequest();
xhr.open('PUT', 'https://example.com/artifactory-proxy-avoiding-cors');
xhr.send(file);
}
</script>
Our front-end could not HTTP POST directly to the JFrog/Artifactory server. So we ended up using a Node.js server as a proxy, which is not very ideal.
Front-end:
// in an AngularJS controller:
$scope.onAcqImageFileChange = function (e) {
e.preventDefault();
let file = e.target.files[0];
$scope.acqImageFile = file;
};
// in an AngularJS service
createNewAcqImage: function(options) {
let file = options.file;
return $http({
method: 'POST',
url: '/proxy/image',
data: file,
headers: {
'Content-Type': 'image/jpeg'
}
})
},
Back-end:
const express = require('express');
const router = express.Router();
router.post('/image', function (req, res, next) {
const filename = uuid.v4();
const proxy = http.request({
method: 'PUT',
hostname: 'engci-maven.nabisco.com',
path: `/artifactory/cdt-repo/folder/${filename}`,
headers: {
'Authorization': 'Basic ' + Buffer.from('cdt-deployer:foobar').toString('base64'),
}
}, function(resp){
resp.pipe(res).once('error', next);
});
req.pipe(proxy).once('error', next);
});
module.exports = router;
not that we had to use a PUT request to send an image to Artifactory, not POST, something to do with Artifactory (the engci-maven.nabisco.com server is an Artifactory server). As I recall, I got CORS issues when trying to post directly from our front-end to the other server, so we had to use our server as a proxy, which is something I'd rather avoid, but oh well for now.

Make AJAX request using mootools and node.js with expressjs

I'm trying establish an AJAX connection on node 0.10.3 using mootools. My code is:
Client
var ajax = new Request({
url: '/register',
method: 'post',
onSuccess: function(responseText){
console.log(responseText);
}
})
var json = {data:'data'};
ajax.send(JSON.stringify(json));
//ajax.send(json);
Server
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(1344);
app.post('/register', function(req,res){
//Auth.register()
console.log(req.body);
res.contentType('json');
res.send({ some: JSON.stringify({response:'json'}) })
})
The connection is working Ok. On the client I get the response. So the console.log(responseText) inside the OnSucces method is printing the correct value.
But on the server side, the console.log(req.body) is undefined.
I have a few doubts here. Does mootools converts the javascript object to a json string? Is it necessary to convert de object at all? What is the correct way of sending information trough AJAX to node? Is this ajax.send(JSON.stringify(json)); OK? Or is it like this ajax.send(json);?
Do I need to specify the headers to be json?
Apart for solving the particular problem, it would be nice some article, o some feedback to definitely clarify this concepts around node.js.
EDIT
I'm going to post the correct code, for those who are facing a similar problem. Noah was right about the parser, but there is another detail, the parser is expecting for the key data. Luckily I was using data as example!
Client
var ajax = new Request({
url: '/register',
method: 'post',
onSuccess: function(responseText){
console.log(responseText); //Logs "some": "{\"response\":\"json\"}"
}
})
ajax.send({data:{ok:'OK'}});
Server
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(express.bodyParser());
app.listen(1344);
app.post('/register', function(req,res){
console.log(req.body); //logs {ok:'OK'}
res.contentType('json');
res.send({ some: JSON.stringify({response:'json'}) })
})
In the code you posted you are missing the bodyParser middleware app.use(express.bodyParser().
After you add the bodyParser middleware you will be able to access req.body
var express = require('express');
var app = express();
app.use(express.bodyParser()
app.use(express.static(__dirname + '/public'));
app.use(app.router)

Resources