Getting file name from POST request in Spray-can - spray

I am using Spray-can to host a REST service to which a user will be able to upload a file. The block of code that listens for incoming requests is given below:
def receive: Receive = {
case _: Http.Connected => sender ! Http.Register(self)
case req#HttpRequest(HttpMethods.POST, Uri.Path("/upload"), headers, entity, _) =>
logger.info("Received file upload request.")
// Process the uploaded data using the 'entity' object
I upload the file using this curl command:
curl --data-binary #inputFile.csv 'devserver:8998/upload?tenant=DressShop&facility=CityCenter&customer=Jimmy'
The challenge I am facing is that I'm not able to pick up the filename "inputFile.csv" from the request, though I'm getting the data from the "entity" object. I tried poring through the API but couldn't find out any way to get the filename.
My objective is to ensure that I allow upload of only csv files.

You need to process the entity as form data using as
as[MultipartFormData]
Then you can get the file name from the header fields:
def processFormData(data: MultipartFormData) = {
var attForm = ""
val bodyPart = data.fields(0)
data.fields foreach {
bodyPart => println(bodyPart.headers.find(h=> h.is("content-disposition")).get.value)
}
}

This might help:
The filename can be found in parameters.

Related

Zapier trigger that returns file: what is the format of the z.dehydrateFile call?

I am writing a Zapier trigger that will return a file. I understand that my trigger endpoint does not return the contents of the file, but rather a pointer to it.
All the example documentation shows the JavaScript example:
var Zap = {
your_trigger_post_poll: function(bundle) {
var records = z.JSON.parse(bundle.response.content);
return _.map(records, function(record) {
// if you just do url, we'll include any standard authentication headers
record.file = z.dehydrateFile('https://yoursite.com/files/download/' + record.id);
return record;
});
}
}
I am not writing my trigger in JavaScript. I would like to return the data in the correct format, but I can't find any examples of what that should be.
What is the output of z.dehydrateFile? Can you provide a JSON example?
If you want to return a file form your trigger to Zapier, you need to return the URL where Zapier can access that file as a record named 'file'.
If you want your trigger to return "converted_csv_file.xlsx" which can be found on your web server, your trigger would return the following JSON:
{
"file": "https://goodgrids.com/converted_spreadsheets/converted_csv_file.xlsx"
}
Note that the URL matters. The last part of the URL will be used as the file name. This is normal when serving up static files. However, if your service generates files on the fly, make sure that you have the file name as part of the URL, even if the actual key used to access the file is somewhere else in your URL.
{
"file": "https://goodgrids.com/converted_spreadsheets/9234659832475982372345876/converted_csv_file.xlsx"
}
Suggestion to Zapier: Please look at the Content-Disposition header returned when reading the file, to see if it contains a filename.

How to get file stream in the output of Object.get

I a writing a Rails API, with help of aws-sdk-ruby, which retrieves a file from AWS and returns in the response of API. Can I get somehow file stream in response of object.get, which I can directly return from the Rails API.
s3 = Aws::S3::Resource.new
bucket_name = "my_bucket"
bucket = s3.bucket(bucket_name)
object = bucket.object("a/b/my.pdf")
Rails.logger.info 'Downloading file to AWS'
downloaded_data = object.get({})
send_data(downloaded_data,
:filename => "my.pdf",
:type => "mime/type"
)
But it does not return file.
One option I know is to first save the file in local using this line:
object.get(response_target: '/tmp/my.pdf')
Than I can return this file but is there a way to skip this step and directly return the response of object.get without saving in local.
I can not use this solution as my URL are not public and I am just creating a REST API.
I got screen like following when I tried this solution.
As of now what I am doing is getting a URL from the object like this:
url = object.presigned_url(:get, expires_in: 3600)
and using following code to send the response:
data = open(url)
send_data data.read, filename: file_name, type: "mime/type"

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.

Attach POST data to BackgroundDownloader

I am implementing a Windows Phone 8.1 application that creates BackgroundDownloaders to restore cloud files back to the phone.
The cloud requires to POST the file ID as an additional JSON POST request and i cannot find a way to define it the BackgroundDownloader object.
Any ideas?
The way to do it is by creating a temp file to hold the JSON post data and send it to the CreateDownload function (as the last StorageFile parameter).
In addition, i added a Content-Type header to describe it (for me it is application/x-www-form-urlencoded) and add it with SetRequestHeader.
//set the Content-Type header
BackgroundDownloader^ downloader = ref new BackgroundDownloader();
Platform::String^ SKey2 = ref new Platform::String(L"Content-Type");
Platform::String^ SValue2 = ref new Platform::String(L"application/x-www-form-urlencoded");
downloader->SetRequestHeader(SKey2, SValue2);
//Create a temporary file and write the POST data into it
StorageFile^ postDataFile = nullptr;
....
//Call CreateDownload with the postDataFile
downloader->CreateDownload(uri, file, postDataFile);
That worked for me.

WebAPI: Upload picture & get byte array

I want the user to be able to upload a file via my application. I don't have DB access, all my data calls get completed via a web-service that another person is writing. I needed to secure the web service, so I've consumed it & exposed it via WebAPI, & added OAuth security.
Now to my problem.
I've written the following.
public Task<FileResult> Post()
{
if (Request.Content.IsMimeMultipartContent())
{
var task = Request.Content.ReadAsByteArrayAsync().ContinueWith(
o =>
{
var result = this.Client.UploadPicture(this.UserId, o.Result);
if (result.ResultCode == 0)
{
return new FileResult()
{
Message = "Success",
FileId = result.ServerId
};
}
throw new HttpResponseException(...);
});
return task;
}
...
}
I'm pretty much a noob when it comes to WebAPI & multithreading (I'm not sure why this needs to be handled async? I'm sure there is a reason, but for now I'd just like a working example and get to the why later..).
My code is loosely based on some R&D & samples I've found on the net, but i haven't come across a scenario like I'm needing to complete... Yet it doesn't seem like I'm doing something out of the ordinary...
Upload a file to the server, and pass the image byte[] object to either sql or another service?
In this line
var result = this.Client.UploadPicture(this.UserId, o.Result);
I'm uploading a byte[] array of something....
Then later (the retrieval method works, I've managed to retrieve & view a test image)
When retrieving the byte array of the "image" i uploaded i get an array of idk what.. EG, i get a valid result of something, but it ain't no picture. Which leads me to believe that the uploaded data is bogus :|
O_o
How to get the image byte[]?
Mime Multipart is more than just your array of bytes. It also has metadata and boundary stuff. You need to treat it as MultiPartContent and then extract the image byte array out of that.
Filip has a blog post on the subject here.

Resources