KrakenD: Trouble to upload file though gateway via POST request using Form-Data - krakend

Describe what are you trying to do
In one of my applications, I need to upload a file to my server from my angular website.
Basically, to do this I use the FormData object to which append several informations, like the file name, and others.
To send the file itself I will append to the FormData an fs.readStream().
Then I post this via axios to my server endpoint.
Exemple of code (postman request using form-data):
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
data.append('avatar', fs.createReadStream('/home/file.mp3'));
data.append('title', 'test');
data.append('description', 'test');
var config = {
method: 'post',
url: 'localhost:8080/upload-file',
headers: {
...data.getHeaders()
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
Concerning the server, it is developed in node.js and I use the "multer" middleware to retrieve the file.
Exemple of an endpoint code :
import {Response, Request} from "express";
public static async UploadFile(req: Request, res: Response): Promise<any> { }
Without krakend gateway, it's works perfectly and I can then retrieve the file in my endpoint so that: req.file
The others informations sent like "title", "description" are in req.body
Using krakend, I get all the information on the server side except the file, in the request, I only find the req.body and not the req.file
So my question is, how come krakend is not sending the file data to the backend and what would be the solution in order to send file via POST request a FormData to krakend ?
Your configuration file
The content of your krakend.json:
{
"version": 3,
...
{
"endpoint": "/upload",
"method": "POST",
"output_encoding": "no-op",
"backend": [
{
"method": "POST",
"encoding": "no-op",
"url_pattern": "/upload-file",
"host": [
"http://containername:8080"
]
}
]
}
}
I tried to use the different "no-op" annotations but nothing works, I have the impression that krakend does not interpret my file upload
Commands used
How did you start the software?
I use docker-compose:
krakend:
container_name: 'Gateway'
image: devopsfaith/krakend
volumes:
- ./KrakenD/dev/:/etc/krakend
ports:
- "8080:8080"
- "1234:1234"
- "8090:8090"
links:
- some containers
- ...
restart: always
network_mode: bridge
Logs
I don't have a specific log, only my backend which returns a 400 code as it can't find the file information in the request.

for those who are going through the same problem. Please note that postman was the cause of the problem for me, KrakenD does support sending bodies as multipart/form-data, so don't forget to let the headers through as needed.
The problem is that when passing through postman, I can't explain but the file is badly sent to krakenD. Use Insomnia, or a simple Curl to do your tests.

Maybe you have to include "Content-Type" at input-headers.
"input_headers": [
"Authorization",
"Content-Type"
],
Here you can find more info about it.

Related

Use axios post to access mediawiki API

I have been using MediaWiki API for some time using properly formatted URLs, but i need to access a wiki with a required login.
I tried using fetch to make the request, and also axios, and the result is the same: the HTML page of the API, the same I would get if i just put the URL of the api in a browser.
My axios call is this:
axios.post('/wiki/api.php', {
logintoken: "this. Token",
action: "clientlogin",
username: "xxxxx",
password: "yyyyyy",
loginreturnurl: "http://localhost/",
format: "json"
}).then(function (response) {
console.log(response. Data);
})
It is as if the post request is simply not made. I tested using the Wikipedia api, and the result is the same.
Any help?
I believe you should add a ?format=json parameter?
Even though it is a post request
In the end it all came down to the fact that the MediaWiki API was expecting the parameters in the application/x-www-form-urlencoded format, and not application/json or text/plain ones.
When I changed that, I was able to login as expected, regardless of using axios or simply fetch.
The final code looks like this (token obtained via another API call):
const opts = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
"logintoken": this.token,
"action": "clientlogin",
"username": "username",
"password": "password",
"loginreturnurl": "http://localhost/",
"format": "json"
})
};
const res = await fetch('/wiki/api.php', opts).

Workbox Stale-while-revalidate strategy always returns response from network call instead of cache

I am using workbox-webpack-plugin, below is code in webpack config
new GenerateSW({
runtimeCaching: [
{
urlPattern: new RegExp('^https://devapi\.mysite\.xyz/'),
handler: 'staleWhileRevalidate',
options: {
cacheableResponse: {
statuses: [200]
}
}
}
]
})
Below is flow of stale while revalidate strategy as per google doc
I am calling API from cross domain, what I observed is each time response is given back to UI not from cache but from network call response.
I am expecting when same API is called 2nd time, I should get response from cache and then cache should be updated from response of network call.
I think all the info in this "Handle Third Party Requests" guide should help.
In particular, make sure that your remote server is using CORS, or else you'll get back a response that has a status of 0. You're explicitly configuring the cacheableResponse plugin to only cache responses with a status of 200.
For anyone stumbling upon this now, the correct snippet should be.
Workbox listens to StaleWhileRevalidate not staleWhileRevalidate.
new GenerateSW({
runtimeCaching: [
{
urlPattern: new RegExp('^https://devapi\.mysite\.xyz/'),
handler: 'StaleWhileRevalidate',
options: {
cacheableResponse: {
statuses: [200]
}
}
}
]
})

How to upload a large file to OneDrive using Microsoft Graph

I'm getting a 404 - File name not provided in url response when creating an upload session.
My request looks like (without any body):
POST /v1.0/drives/{drive-id}/items/{item-id}/createUploadSession
Authorization: bearer <token>
Content-Type: application/json
This problem is only with the consumer OneDrive, OneDrive for Business works fine.
It worked for me:-
POST - https://graph.microsoft.com/v1.0/me/drive/root:/filename.txt:/createUploadSession
In Headers:-
Content-Type : application/json
Authorization: Bearer EwCIA8l6BAAUO...9chh8cJaAg==
In Body:-
{
"item": {
"#odata.type": "microsoft.graph.driveItemUploadableProperties",
"#microsoft.graph.conflictBehavior": "rename",
"name": "filename.txt"
}
}
I could upload a file in a personal account using this URL for create the storage session:
https://graph.microsoft.com/v1.0/me/drive/items/{folderID}:/{fileID}:/createUploadSession
var config = {
method: 'post',
url: 'https://graph.microsoft.com/v1.0/me/drive/items/{folderID}:/{fileID}:/createUploadSession',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer
}
Response:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"expirationDateTime": "2020-11-06T14:25:27.662Z",
"nextExpectedRanges": [
"0-"
],
"uploadUrl": {url}
}
Then:
To create the file you gonna need to send a PUT request for the
{uploadUrl} that you got in the response.
I've never run across your particular scenario but I suspect this is due to the folder that was shared with you via OneDrive for Business being part of the same tenant as your own OneDrive for Business. When you're accessing a shared folder from a consumer OneDrive however, you are effectively accessing a drive in a completely separate tenant.
Since using the root:/{path}:/ method I suggested works, it sounds like this scenario may cause some issues with the API determining the file's information from the {itemId}. I'm looking to confirm this so I can update the documentation going forward.

Why is there "no response from server" in Swagger UI?

My API calls work correctly in Postman. But when I send requests from Swagger UI, it shows "no response from server" for all requests:
Response Body
no content
Response Code
0
Response Headers
{
"error": "no response from server"
}
What can the problem be and how to fix it?
The browser console shows these errors:
Failed to load resource: net::ERR_CONNECTION_REFUSED
Uncaught TypeError: Cannot read property 'length' of undefined
at showStatus (index.js:24)
at showErrorStatus (index.js:24)
at error (index.js:607) at spec-converter.js:533
at Request.callback (index.js:24)
at Request.crossDomainError (index.js:24)
at XMLHttpRequest.xhr.onreadystatechange (index.js:24)
net::ERR_CONNECTION_REFUSED sounds like you need to enable CORS on your localhost, so that it sends the Access-Control-Allow-Origin: * header in responses. How you do this depends on the server you use. More info here:
https://enable-cors.org/server.html
https://github.com/swagger-api/swagger-ui/#cors-support
You may also need to allow OPTIONS pre-flight requests.
Swagger returns 0 response code due to the Reference Looping in your serializer response.
Ignore the reference looping while getting the serializer response back.
If you are using Web API, use the following code
services.AddMvc()
.AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
remove schemes from swagger config json file(in my case tsoa.json) and restart the server. It worked for me.
{
"readme": "https://github.com/lukeautry/tsoa/blob/HEAD/tsoa.json",
"swagger": {
"outputDirectory": "./dist/src",
"entryFile": "./src/server.ts",
"basePath": "/",
"schemes": [
"http",
"https"
],
"securityDefinitions": {
"basic": {
"type": "basic"
}
}
},
"routes": {
"basePath": "/",
"entryFile": "./src/server.ts",
"routesDir": "./src",
"authenticationModule": "./src/security/Authentication"
}
}
In my case there was a problem with https. In swagger config the http scheme was "disabled" (not available). I had it like this:
GlobalConfiguration.Configuration.EnableSwagger(c => { c.Schemes(new[] { "https" }); });
And I had to change it to make it work in debug on localhost:
GlobalConfiguration.Configuration.EnableSwagger(c => { c.Schemes(new[] { "https", "http" }); });
The first snippet worked on production with enabled https but id didn't work while debugging in Visual Studio in default config.
In my case I was sending very simple text response e.g. "Resource not found" in the body and set Content-Type to "application/json". Depends on version Swagger has a hard time deserializing simple text to json, so im my case changing Content-Type to "text/plain" did the trick.

How to POST JSON request in cross domain in sencha touch

I have got following URL
https://development.avalara.net/1.0/tax/get
and would like to POST following JSON request body
{
"DocDate": "2011-05-11",
"CustomerCode": "CUST1",
"Addresses":
[
{
"AddressCode": "1",
"Line1": "435 Ericksen Avenue Northeast",
"Line2": "#250",
"PostalCode": "98110"
}
]
}
which then will give JSON response
{
"DocCode": "78b28084-8d9a-477c-9f26-afab1c0c3877",
"DocDate": "2011-05-11",
"Timestamp": "2011-05-11 04:26:41",
"TotalAmount": 10,
"TotalDiscount": 0,
"TotalExemption": 0,
"TotalTaxable": 10,
"TotalTax": 0.86,
“TotalTaxCalculated”: 0.86,
"TaxDate": "2011-05-11",
.......
}
I have tried to use
Ext.Ajax.request
but get error
Origin http://localhost is not allowed by Access-Control-Allow-Origin.
which might be due to having different domain.
So, then i tried to use JSONP
Ext.data.JsonP.request
(
{
url: 'https://development.avalara.net/1.0/tax/get',
callbackName: 'test',
method: 'POST',
jsonData: '{"DocDate": "2011-05-11", "CustomerCode": "CUST1", "Addresses": [ { "AddressCode": "1", "Line1": "435 Ericksen Avenue Northeast","Line2": "#250", "PostalCode": "98110" } ] }' ,
success: function(response) {
//do some successful stuff
Ext.Msg.alert(response);
},
failure: function(response) {
//complain
Ext.Msg.alert('fail');
}
});
But URL 404(Not Found) error is encountered and request method is GET instead of POST.
Can anyone help me how POST request body(JSON) and obtaind JSON response from different domain?
Thanks in advance
You have four options:
Use CORS. development.avalara.net would need to setup CORS on the server and allow the domain that the Sencha page is running on.
Reverse Proxy requests through a server on the domain that the Sencha page is running on:
Sencha page (mydomain.com) ---> Web Server (mydomain.com) ---> development.avalara.net
Sencha page (mydomain.com) <--- Web Server (mydomain.com) <--- development.avalara.net
You could also POST the form as a regular form post action, or POST the form inside a hidden iframe.
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.form.Basic-cfg-standardSubmit
Run the Sencha app inside phonegap/cordova which does not block cross-domain requests.
You cannot do JSON-P with POST requests, JSON-P only supports GET requests. Your options are:
Use a GET request with JSON-P
Move the server functionality to the same server your ST app is running
Use something like Cordova and Whitelist the server you want to use for your AJAX POST requests, then use Ext.Ajax.request.

Resources