It's often essential to construct POST with web applications, or when using REST or other HTTP methods. For some posts (such as with attached binaries), there isn't much alternative but to use multipart structures.
This is possibly the first of the tutorials which really shows off some of the strengths of Obyx. The ability to manage and maintain XML representations of complex REST interactions such as multiparts is essential to modern web applications development.
Obyx has a great way of doing a lot of the work for multipart for us, which is always helpful, which is by using the osi:http, and importantly the obyx message namespace. There's not much to the osi:http, it's just a document format that represents a http request; it's required attributes are 'url' (where the request is to be made) and 'method' (GET, POST, etc).
<o:http xmlns:o="http://www.obyx.org/osi-application-layer">
<o:request url="http://my.destination.url" method="POST" >
<!-- the request message goes here -->
</o:request>
</o:http>
The interesting part of the post is the actual request itself. In Obyx, this is done using the message namespace (which is also used for sending and parsing emails also). Messages are made up of two primary sections, a set of headers and a body. (For a great deal of detail on the structure of http, RFC2616 is a good starting point, and for multipart/form-data specifically, RFC2388 is the reference document.). In Obyx, we don't need to add any headers, though we may want to include cookies, or authorisation. The internal structure of the http message itself is going to be looked after for us by Obyx.
<message xmlns="http://www.obyx.org/message">
<body subtype="form-data" type="multipart" >
<!-- parts of our post go here -->
</body>
</message>
So up to this point, there's not much to it. So the next bit, which is a bit more interesting, is the multipart/form-data body to the post. When it's type is "multipart", the body part of a message can also contain messages. This is what makes the structure so flexible.
So let's say that we wish to add a plaintext field to the post named "hello" which holds the value "world".
<m:message>
<m:header name="Content-Disposition" value="form-data">
<m:subhead name="name" value="hello" />
</m:header>
<m:body>world</m:body>
</m:message>
So that's all there is to multipart forms! However, it doesn't show us how to do a binary. So let's try that also. We won't put the actual binary into the file here; instead we can insert that later on. Note that the internal representation of the binary file will be url encoded.
<m:message>
<m:header name="Content-Disposition" value="form-data">
<m:subhead name="name" value="file" />
<m:subhead name="filename" value="tiny.gif" />
</m:header>
<m:body subtype="gif" type="image" urlencoded="true" />
</m:message>
So that's the http POST request structure. The entire request now looks something like this..
<o:http xmlns:o="http://www.obyx.org/osi-application-layer">
<o:request url="http://my.destination.url" method="POST" >
<message xmlns="http://www.obyx.org/message">
<body subtype="form-data" type="multipart" >
<m:message>
<m:header name="Content-Disposition" value="form-data">
<m:subhead name="name" value="hello" />
</m:header>
<m:body>world</m:body>
</m:message>
<m:message>
<m:header name="Content-Disposition" value="form-data">
<m:subhead name="name" value="file" />
<m:subhead name="filename" value="tiny.gif" />
</m:header>
<m:body subtype="gif" type="image" urlencoded="true" />
</m:message>
</body>
</message>
</o:request>
</o:http>
Constructing a request OSI can be a bit complicated at first. However, there's a simple 'trick' that can be used! If you create a tiny obyx file called eg "req.obyx" with the following code, then you can post any form that you like to that, and see how the OSI is composed.
<instruction xmlns="http://www.obyx.org">
<input space="sysenv" value="CURRENT_REQUEST" />
</instruction>
So, how to get Obyx to send this POST. Let's write the control. In brief, we want to load up the POST request, insert the image that we want to send, and then send the request. In order to insert the image using XPath, we will have to load up the message namespace.
<instruction xmlns="http://www.obyx.org" note="send a multipart POST">
<input>
<instruction note="load message namespace">
<output space="namespace" value="m" />
<input value="http://www.obyx.org/message" />
</instruction>
<instruction note="load osi/message post">
<output space="store" value="mypost" />
<input space="file" value="multipart.osi" />
</instruction>
<instruction note="insert binary into post">
<output space="store" value="mypost#//m:body[type='image']/child-gap()" />
<input space="file" value="tiny.gif" encoder="url" />
</instruction>
<instruction note="do request (and release). Also capture errors.">
<output space="store" value="response" />
<output space="error" value="error" />
<input space="store" value="mypost" eval="true" release="true"/>
</instruction>
</input>
</instruction>
Obyx has an output space="error" which handles error responses, both from evaluation issues, and also from Obyx runtimes. Here we want to capture the response, which will be returned as an OSI http response format, but there may be some form of service error also, so we will want to know about that as well.