Yaron 53 Posted November 12, 2018 I am trying to upload JSON data and an image as a MultipartFormData and return a JSON string from mars using the following code: var shareData : TMultipartFormData; jsonStr : String; begin shareData := TMultipartFormData.Create; shareData.AddField('json','{"empty":"empty"}'); shareData.AddFile('image',FileName); jsonStr := NetHTTPRequest.Post(urlAPIBase+urlAPIShareImage,shareData).ContentAsString(TEncoding.UTF8); end; How do I setup mars to give me access to the json field and image fields? I looked at the ContentTypes demo, but I wasn't sure if any of the examples actually covered MultipartFormData. Share this post Link to post
Andrea Magni 75 Posted November 13, 2018 Hi, there was no demo showcasing how to handle multipart/form-data on the server side with MARS. But, since a couple of minutes, there is! 🙂 Have a look here: https://github.com/andrea-magni/MARS/tree/master/Demos/MultipartFormData Build and run the demo, then use a browser to navigate http://localhost:8080/rest/default/helloworld/1 to have a simple HTML page with a multipart/form-data form. The last part of the URL can be 1, 2, 3 or 4. On the server side, you will notice four methods marked with the POST attribute, to handle the 4 requests. It is actually the same http request served through 4 different available ways in MARS (see here: https://github.com/andrea-magni/MARS/blob/master/Demos/MultipartFormData/Server.Resources.pas😞 1) ask the library to inject a dynamic array of TFormParam: [FormParams] AParams: TArray<TFormParam> Implementation of the REST method loops on that array to provide a result value; 2) target specific params (by name) using the following syntax: [FormParam('json')] AJSON: TFormParam; [FormParam('image')] AImage: TFormParam; FormParam is defined in MARS.Core.Utils and can represent both simple parameters and files; 3) push a bit more and ask for automatic deserialization of the first parameter into a TJSONObject. The methods has these arguments defined: [FormParam('json'), Consumes(TMediaType.Application_JSON)] AJSON: TJSONObject; [FormParam('image')] AImage: TFormParam; Note the type of the first argument is no more TFormParam but TJSONObject 4) last version takes advantage of JSON to record serialization (built-in with MARS): [FormParam('json'), Consumes(TMediaType.Application_JSON)] ARecord: TPerson; [FormParam('image')] AImage: TFormParam; All these four variations have a TMyResult record as return value. This record gets automatically serialized to JSON by the library. You should be able to build clients in any language (I tested with Postman and the HTML page, using Chrome). Let me know if everything is clear and working. Sincerely, Andrea 1 Share this post Link to post
Stuart Clennett 15 Posted May 1, 2019 (edited) Hi Andrea, I want to implement this in my server, so I started with your demo above and tried to use Postman to test the API. When I run Postman against your [..]/helloworld/2 endpoint I get the following back: { "JSONData": "{\"name\": \"Stuart\"}", "PersonName": "Stuart", "FileName": "", "FileSize": 0 } This is my PostMan Setup: https://imgur.com/td0fDJ4 (Sorry, can't find anyway to export the Postman config for that request). The json data is picked up okay, but not the file data. I'm sending an Excel file in this case, but I've tried pure binary files like JPGs too. Can you see what I'm doing wrong with Postman? Thanks Edited May 2, 2019 by Stuart Clennett (Added more info about what was being sent & updated Image URL) Share this post Link to post
Andrea Magni 75 Posted May 2, 2019 Hi @Stuart Clennett everything seems fine in your screenshot (as long as you actually loaded a file as param's value but I take this for granted). It turned out to be a bug in MARS I introduced with commit https://github.com/andrea-magni/MARS/commit/a0bcbce5c43dbb45648d89e6bc3a44b74e7996bd Introducing the RequiredAttribute to enforce FormParam validation I broke the reading mechanism of data from multipart/form-data files. I fixed this in the develop branch with commit https://github.com/andrea-magni/MARS/commit/bf84a00b0f5e45d8760ab9b0a24d7c6ee018aca4 I also backported a similar fix to master branch with commit https://github.com/andrea-magni/MARS/commit/63a4bbb36d4f6acb18106086f889b76ac69f2882 Please update your working copy (either develop or master) and confirm this solves the problem. Thanks a lot for pointing this out and sorry for the inconvenience. Sincerely, Andrea Share this post Link to post
Stuart Clennett 15 Posted May 3, 2019 (edited) Hi Andrea, Thanks very much. Confirmed working with Postman and the delphi demo client. Still can't get my HTML to work though - it just uploads the file name not the file contents. Looking into this now. *Edit* My bad forgot the enctype="multipart/form-data" attribute from the form tag (which is ironic given that I was testing multipart/form-data, ha ha) Kind regards, Stuart Edited May 3, 2019 by Stuart Clennett added result of testing with html 1 Share this post Link to post
alejandro 0 Posted July 10, 2020 Hello to all! I am trying to use this demo. I get a positive response from the server, but I can not find the received file. Please tell me where the received file is saved? Share this post Link to post
Stuart Clennett 15 Posted July 13, 2020 (edited) @alejandro The demo does not save the file at all. You are required to implement that. However it is quite simple. For example, in the `StoreDataAndFile` method in `Server.Resources.pas` you could use a memory stream to access the Bytes and save to a file if SameText(LParam.FieldName, 'image') and LParam.IsFile then begin Result.FileSize := Length(LParam.AsFile.Bytes); Result.FileName := LParam.AsFile.FileName; // This will save the file lStream := TMemoryStream.Create; try lStream.Write(LParam.AsFile.Bytes, Length(LParam.AsFile.Bytes)); lStream.SaveToFile(TPath.Combine(C_RootPath, TPath.GetFileName(LParam.AsFile.FileName))); finally lStream.free; end; end In this instance, `C_RootPath` is just a folder on the server where uploaded files should be saved, but you could make this dynamic based on user info in the Token for example. Hope this helps Edited July 13, 2020 by Stuart Clennett Changed formatting of code from HTML to Pascal 1 2 Share this post Link to post
Andre G 0 Posted February 17, 2021 (edited) Hi Andrea and fellows, we personally talked about your framestand on EKON. Now we use MARS in our app very successfully. Its great! But heres the problem... maybe i just dont get it. But i fail with building GET for the multipart/form-data! I send a image from client to server, like in your demo. But the opposite way didnt work. After reviewing the source i recognized that theres no override for AfterGet in the MARS.Client.Resource.FormData.pas. Therefore FResponse wont be upgraded after you did .GET. When i add it like AfterPut and AfterPost, it works. Is there a reason for the missing AfterGet? Best regards Edited February 17, 2021 by Andre G Share this post Link to post