[SOLVED]REST web application: sending/receiving binary object and JSON together? lazarus / 38-Networking and Web Programming ---------------------------------------------------------------------- BigChimp · 2013-02-23 14:29 Hi, Another day, another newb question For my document scanning application, I want to let users select an existing document from a list and remember the DocumentID. So far so good. Then the user should be able to upload an image giving the DocumentID, and let the server add that to the document database (and process/OCR any existing images associated with the document, the new image and finally generate a PDF with image+text). My question: how can I send both a documentID (e.g. encoded as JSON) - or really arbitrary JSON stuff - and a binary image to the server? I could put the JSON in the URL query of course, or I could create a JSON object with the DocumentID and e.g. the base64 encoded image and POST that, but I'm sure there's a more elegant way of doing this. Perhaps put the JSON data in custom headers? Any advice or search terms I can look for? Have searched a bit but haven't really found anything. Same question for getting binary stuff from the server (e.g. a TIFF or PDF of the document currently is downloaded in the body as application/pdf or application/tiff, which works ok, but suppose I want to add some metadata?) Thanks! ---------------------------------------------------------------------- Silvio Clécio · 2013-02-23 18:43 Hello buddy. I will give my MHO on what I learned... Unfortunately (or fortunately? ), there is no an universal standard on how to send binary to REST APIs, but this is no a problem, the HTTP server handles binaries in transparent way to us. You can use two ways (both are excellent, you choose the one that best meet their): 1. Convert the binary to base64 and send it directly in your JSON (a little slow, but easy to manipulate); 2. Send the binary in raw format, using form-data (fast and nice for big files, but boring to manipulate using purely FCLWeb, but easy if using Brook ); I personally use the two above. Google APIs too. Amazon APIs uses 2., Twitter APIs uses 1., Github APIs uses 2. etc etc etc. Soon, Brook will have the Files property in own actions. It will manage uploads, allowing read them directly as stream or base64. E.g.: Code: [Select]procedure TMyAction.Post; begin   Files.First.Save('doc.pdf'); end; or: Code: [Select]procedure TMyAction.Post; begin   Write(Files.First.AsBase64) end; But currently the Brook already offers support to creating REST APIs allowing to handle binary contents. If you want, I create a small example showing how to send files (your docs) and fiels (your DocumentID) using form-data in a REST API. ---------------------------------------------------------------------- BigChimp · 2013-02-24 08:24 Obrigado, Silvio! I think I'll first reorganize my URLs some (I haven't yet embedded the document number in the URL)... that solves the uploading part with a documentID. As for the downloading, I'll probably use option 1 with a precompressed bitmap or something as it seems easiest for now... but perhaps I'll change my mind later. Thanks for the offer to create a sample - don't think I'll need it right now - but you never know, with my fluctuating coding skills Thanks a lot! ---------------------------------------------------------------------- Silvio Clécio · 2013-02-24 21:51 Olá amigo! Quote from: BigChimp on February 24, 2013, 09:24:46 am... I think I'll first reorganize my URLs some (I haven't yet embedded the document number in the URL)... that solves the uploading part with a documentID. ... If your structure is based on REST architecture, then: In the create (POST), the documentID must be generated automatically. In the update (PUT), it must be showed in URL. Please see a nice style of routing here: http://brookframework.org/demos/db/rest/addressbook/rails_routing.html ---------------------------------------------------------------------- BigChimp · 2013-02-25 06:49 Ciao Silvio, tudo bem? Quote from: silvioprog on February 24, 2013, 10:51:59 pmIf your structure is based on REST architecture, then: In the create (POST), the documentID must be generated automatically. In the update (PUT), it must be showed in URL. Yep, exactly. Got sidetracked a little but will have to find out how this works in fpweb ---------------------------------------------------------------------- Silvio Clécio · 2013-02-25 12:49 Try Brook after. Is very eazy to use Brook even without REST, eg: Code: [Select]  TMyAction = class(TBrookAction)   public     procedure Get; override;   end; implementation procedure TMyAction.Get; begin   Write('I''m a GET'); end; initialization   TMyAction.Register('*'); or: Code: [Select]type   TMyAction = class(TBrookAction)   public     procedure Post; override;   end; implementation procedure TMyAction.Post; begin   Write('I''m a POST'); end; initialization   TMyAction.Register('*'); ---------------------------------------------------------------------- Silvio Clécio · 2013-02-25 13:08 ... I think the most interesting thing of Brook is your routing (documentation is a bit outdated compared to the GIT code, but ...): http://docs.brookframework.org/BrookAction.TBrookAction.html#Register No other web framework Pascal offers routing. I can not see myself programming REST APIs without a routing. I use routing in Slim framework (http://docs.slimframework.com/) and Rails (http://guides.rubyonrails.org/routing.html) too, and I brought this modernity to the Pascal. ---------------------------------------------------------------------- BigChimp · 2013-02-25 13:17 Yep, Brook looks very intersting from that point of view. Thanks for the examples. Apparently in fpweb you can do something like this: Code: [Select]procedure TFPWebModule1.uploadimageRequest(Sender: TObject; ARequest: TRequest;   AResponse: TResponse; var Handled: boolean); //<- generated by event handler ... if ARequest.Method='POST' then... //or something. Air code/untested ... If my experiments with fpweb don't work out, I'm sure what I'll do next ---------------------------------------------------------------------- Silvio Clécio · 2013-02-25 13:34 Nice. Currently, it's very easy to handle uploads with Brook, but will be even easier: https://github.com/silvioprog/brookframework/issues/15. Feel free to explore the possibilities to implement uploads (with fpWeb, Brook or others). Soon, if you want, we solved this issue above, further facilitating our lives. ---------------------------------------------------------------------- BigChimp · 2013-02-25 14:40 Nice. I have a sneaking suspicion I'll move to Brook anyway because AFAIU fpweb does not support HTTPS connections... we'll see, first I'm going to learn some more and get a working application over HTTP... Oh, and FYI, Michael Van Canneyt's response on how to enable fpweb to deal with URLs like Code: [Select]GET http://server/cgi-bin/tigercgi/documents/301/is in this thread: http://www.mail-archive.com/fpc- pascal@lists.freepascal.org/msg31598.html ---------------------------------------------------------------------- Silvio Clécio · 2013-02-25 15:14 Hehehe... with Brook, I would use (pseudo code): Code: [Select]procedure TUploadImageAction.Post; begin   // if you add ":foo" in pattern, "foo" is returned as JSON in Values: "{ "foo": 301 }". You can use Values['foo'].AsInteger too. :)   Table.Open.Locate(Values) ... blah blah blah; end; initialization   TUploadImageAction.Register('mytabledocuments', '/documents/:id'); And would call with "http://server/cgi-bin/tigercgi/documents/301", "http://server/cgi-bin/tigercgi/documents/1000" etc.