Flutter post to nodejs API with image file and string field as json string - dart

Hoping to find an example of using Flutter to send a form post to Node.js and pass a string that is JSON and an image file.
I have been trying http.MultipartRequest, but the node service does not get anything in files or fields.
Not sure what I am doing wrong, so any guidance would be great.
var _url = Uri.parse('http://$baseurl/chat/messages/send');
var request = new http.MultipartRequest('POST', _url);
request.fields['json'] = json;
request.files.add(new http.MultipartFile.fromString(widget.mychat.msgkey, myimagefile.path));
Am I missing an easier way? Tried to BASE64 encode the image and add as a string in JSON, but the server keeps crashing even after I changed the amount of client request nginx would allow. I need it to work for an image or video sent from mobile.

I was having the exact same issue. The problem is not with MultipartRequest but the nodejs server.
The body-parser module you are using in the nodejs API can not handle multipart/form-data , it can only handle x-www-form-urlencoded
The solution is : You have to use module like multer in your nodejs API
const multer = require('multer')
let upload = multer({ storage: multer.memoryStorage() });
router.route('/signup').post(upload.single('avatar'),function (req, res) {
console.log('signup page');
console.log(req.file);
console.log(req.body);
//res.status(200).json({"success": "Signup page"});
res.end('hello world');
});
Found a nice solution here http://derpturkey.com/node-multipart-form-data-explained/

Related

Images/Videos CDN URL - Detect file type/extension

I'm trying to implement Story Mention rendering according to IG messenger graph API.
IG webhooks sends the payload URL of the media as CDN URLs that are extensionless,
which means I can't detect the file type(could be any kind of image or a video file).
The purpose is to render the URL to an HTML element and to prevent saving some file extensions.
Did anybody find out how to get this information?
An example for IG CDN URL
https://lookaside.fbsbx.com/ig_messaging_cdn/?asset_id=17952754300482708&signature=AbxVoHUcW3qKGZvE0FwrbpSEKBqkYGH9wFDUY9xnywlxxek8lWtrTwE173Sxhta9jbp0bgDiL17IpyiI82vqHGNPUD1wdMUZphwQOggW-_877cCI1BxaY_aDUZ8hj5OwmHK9E8OnSybqtMVmGXCX_hBF399t1Hb44zspeL3d9NWb9rib
Python:
import requests
res = requests.head(url)
print res.headers
I was able to retrieve the content type by making a request with node-fetch.
const fetch = require('node-fetch');
const response = await fetch(mediaUrl, { method: 'HEAD' });
const contentType = response.headers.get('Content-Type');

React-Native FormData File Requests being sent to the server as [object Object]

I am currently using React Native 0.48 and react-native-image-crop-picker 0.16.
I'm attempting to take a file uri, and send it to a server using FormData and Fetch.
Here is a code snippet of what I am doing:
var image = await ImagePicker.openPicker({
width: 500,
height: 500,
cropping: true,
includeBase64: true,
});
var media = {
uri: image.path,
type: 'image/jpeg',
name: 'file.jpg',
};
var formData = new FormData();
formData.append("file", media);
fetch("https://requestb.in/1e6lgdo1", {
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
body: formData
}).then(function(r){
console.log("Success", r);
}).catch(function(e){
console.log("Error", e);
}).done();
Unfortunately when the request gets sent to the server instead of sending the file contents in the "file" form data field, it's just sending "[Object object]".
Depending on where you send the request to, that either results in the file contents becoming "[object Object]" or the request erring out.
I am unable to determine if this is a problem with my own code, or with react native itself. Any assistance would be greatly appreciated.
Update
I am using https://github.com/jpillora/uploader for my test server. (Note: Go doesn't ever use the notation [object Object] when stringifying an object, so I do not believe the problem lies with the server. In addition I saw this when uploading a file to S3 as well.)
An example of a request that ends up getting sent out is:
------WebKitFormBoundaryzt2jTR8Oh7dXB56z
Content-Disposition: form-data; name="file"
[object Object]
------WebKitFormBoundaryzt2jTR8Oh7dXB56z--
This problem had to do with another package React-Native Debugger hijacking fetch requests in order to allow for inspection in the debugger.
Complete information on the workaround can be found here: https://github.com/jhen0409/react-native-debugger/issues/101
I was able to successfully bypass it however by going back to the Google Chrome debugger.

How to retrieve Medium stories for a user from the API?

I'm trying to integrate Medium blogging into an app by showing some cards with posts images and links to the original Medium publication.
From Medium API docs I can see how to retrieve publications and create posts, but it doesn't mention retrieving posts. Is retrieving posts/stories for a user currently possible using the Medium's API?
The API is write-only and is not intended to retrieve posts (Medium staff told me)
You can simply use the RSS feed as such:
https://medium.com/feed/#your_profile
You can simply get the RSS feed via GET, then if you need it in JSON format just use a NPM module like rss-to-json and you're good to go.
Edit:
It is possible to make a request to the following URL and you will get the response. Unfortunately, the response is in RSS format which would require some parsing to JSON if needed.
https://medium.com/feed/#yourhandle
⚠️ The following approach is not applicable anymore as it is behind Cloudflare's DDoS protection.
If you planning to get it from the Client-side using JavaScript or jQuery or Angular, etc. then you need to build an API gateway or web service that serves your feed. In the case of PHP, RoR, or any server-side that should not be the case.
You can get it directly in JSON format as given beneath:
https://medium.com/#yourhandle/latest?format=json
In my case, I made a simple web service in the express app and host it over Heroku. React App hits the API exposed over Heroku and gets the data.
const MEDIUM_URL = "https://medium.com/#yourhandle/latest?format=json";
router.get("/posts", (req, res, next) => {
request.get(MEDIUM_URL, (err, apiRes, body) => {
if (!err && apiRes.statusCode === 200) {
let i = body.indexOf("{");
const data = body.substr(i);
res.send(data);
} else {
res.sendStatus(500).json(err);
}
});
});
Nowadays this URL:
https://medium.com/#username/latest?format=json
sits behind Cloudflare's DDoS protection service so instead of consistently being served your feed in JSON format, you will usually receive instead an HTML which is suppose to render a website to complete a reCAPTCHA and leaving you with no data from an API request.
And the following:
https://medium.com/feed/#username
has a limit of the latest 10 posts.
I'd suggest this free Cloudflare Worker that I made for this purpose. It works as a facade so you don't have to worry about neither how the posts are obtained from source, reCAPTCHAs or pagination.
Full article about it.
Live example. To fetch the following items add the query param ?next= with the value of the JSON field next which the API provides.
const MdFetch = async (name) => {
const res = await fetch(
`https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/${name}`
);
return await res.json();
};
const data = await MdFetch('#chawki726');
To get your posts as JSON objects
you can replace your user name instead of #USERNAME.
https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/#USERNAME
With that REST method you would do this: GET https://api.medium.com/v1/users/{{userId}}/publications and this would return the title, image, and the item's URL.
Further details: https://github.com/Medium/medium-api-docs#32-publications .
You can also add "?format=json" to the end of any URL on Medium and get useful data back.
Use this url, this url will give json format of posts
Replace studytact with your feed name
https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/studytact
I have built a basic function using AWS Lambda and AWS API Gateway if anyone is interested. A detailed explanation is found on this blog post here and the repository for the the Lambda function built with Node.js is found here on Github. Hopefully someone here finds it useful.
(Updating the JS Fiddle and the Clay function that explains it as we updated the function syntax to be cleaner)
I wrapped the Github package #mark-fasel was mentioning below into a Clay microservice that enables you to do exactly this:
Simplified Return Format: https://www.clay.run/services/nicoslepicos/medium-get-user-posts-new/code
I put together a little fiddle, since a user was asking how to use the endpoint in HTML to get the titles for their last 3 posts:
https://jsfiddle.net/h405m3ma/3/
You can call the API as:
curl -i -H "Content-Type: application/json" -X POST -d '{"username":"nicolaerusan"}' https://clay.run/services/nicoslepicos/medium-get-users-posts-simple
You can also use it easily in your node code using the clay-client npm package and just write:
Clay.run('nicoslepicos/medium-get-user-posts-new', {"profile":"profileValue"})
.then((result) => {
// Do what you want with returned result
console.log(result);
})
.catch((error) => {
console.log(error);
});
Hope that's helpful!
Check this One you will get all info about your own post........
mediumController.getBlogs = (req, res) => {
parser('https://medium.com/feed/#profileName', function (err, rss) {
if (err) {
console.log(err);
}
var stories = [];
for (var i = rss.length - 1; i >= 0; i--) {
var new_story = {};
new_story.title = rss[i].title;
new_story.description = rss[i].description;
new_story.date = rss[i].date;
new_story.link = rss[i].link;
new_story.author = rss[i].author;
new_story.comments = rss[i].comments;
stories.push(new_story);
}
console.log('stories:');
console.dir(stories);
res.json(200, {
Data: stories
})
});
}
I have created a custom REST API to retrieve the stats of a given post on Medium, all you need is to send a GET request to my custom API and you will retrieve the stats as a Json abject as follows:
Request :
curl https://endpoint/api/stats?story_url=THE_URL_OF_THE_MEDIUM_STORY
Response:
{
"claps": 78,
"comments": 1
}
The API responds within a reasonable response time (< 2 sec), you can find more about it in the following Medium article.

Azure blob authorization header

I am trying to use refit to upload to azure blob storage from a Xamarin iOS application. This is the interface configuration I am using for Refit:
[Headers("x-ms-blob-type: BlockBlob")]
[Put("/{fileName}")]
Task<bool> UploadAsync([Body]byte[] content, string sasTokenKey,
[Header("Content-Type")] string contentType);
Where the sasTokenKey parameter looks like this:
"/content-default/1635839001660743375-66f93195-e923-4c8b-a3f1-5f3f9ba9dd32.jpeg?sv=2015-04-05&sr=b&sig=Up26vDxQikFqo%2FDQjRB08YtmK418rZfKx1IHbYKAjIE%3D&se=2015-11-23T18:59:26Z&sp=w"
This is how I am using Refit to call the azure blob server:
var myRefitApi = RestService.For<IMyRefitAPI>("https://myaccount.blob.core.windows.net");
myRefitApi.UploadAsync(photoBytes, sasTokenKey, "image/jpeg"
However I am getting the follow error:
Response status code does not indicate success: 403 (Server failed to
authenticate the request. Make sure the value of Authorization header is
formed correctly including the signature.)
The SAS url is working fine if I call it directly like this
var content = new StreamContent(stream);
content.Headers.Add("Content-Type", "jpeg");
content.Headers.Add("x-ms-blob-type", "BlockBlob");
var task = HttpClient.PutAsync(new Uri(sasTokenUrl), content);
task.Wait();
So basically I am just trying to do the same thing using Refit.
Any idea how to get Refit working with Azure Blob Storage?
Thanks!
[UPDATE] I am now able to upload the bytes to the azure blob server but something seems to be wrong with the byte data because I am not able to view the image. Here is the code I am using to convert to byte array.
byte[] bytes;
using (var ms = new MemoryStream())
{
stream.Position = 0;
stream.CopyTo(ms);
ms.Position = 0;
bytes = ms.ToArray();
}
[UPDATE] Got it fixed by using stream instead of byte array!
I see %2F and %3D and I'm curious if refit is encoding those a second time. Try sending the token without encoding it.
This is incorrect use of Authorization header. You use Authorization header when you want to authorize the requests using account key. If you have the Shared Access Signature then you really don't need this header as the authorization information is included in the SAS itself. You can simply use the SAS URL for uploading files.

How to parse XML from Rails in Flex

I want to upload a file(photo) from Flex to Rails and then send a response back to the server in XML (contains photo URL and ID). I'm sending from my Rails server some XML as follows:
render(:xml => {:id => #photo.id,
:photoURL => #photo.URL,
:thumbPhotoURL => #photo.thumbURL})
This is sent through FileReference object through fileReference.upload()
I try to render it in the complete handler:
fileReference.addEventListener(Event.COMPLETE,function(event:Event):void {
var xml:XML = new XML(event.target.data);
......
it doesn't seem to parse XML properly. I have used similar code before with URLLoader and it worked. Any ideas?
May i ask why you're converting the data to a ByteArray? URLLoader actually has a great property called dataFormat which you can use to specify the way that Flash will handle the loading. You can choose between binary, text or url-encoded variables.
Like Amarghosh said, you're probably better off using the URLLoader for working with XML.
FileReference is for transferring files between user's hard disk and the server - the upload() function is for sending a file from user's machine to the server.
Use URLLoader to load xml from the server to your flex application
var ldr:URLLoader = new URLLoader();
ldr.addEventListener(Event.COMPLETE, onLoad);
ldr.load(new URLRequest(url));
function onLoad(e:Event):void
{
var loadedText:String = URLLoader(e.target).data;
trace(loadedText);
var xml:XML = new XML(loadedText);
trace(xml.toXMLString());
}

Resources