In the previous two parts of this blog, we developed an API that was able to retrieve a digitized image from the Rijksmuseum and store it locally. For this next part we are going to extend that integration by sending it to the Meural API in order to get the image on our digital canvas.
In order to keep the blog to a reasonable size I’m not implementing everything that you would typically need if you were doing this for real.
Specifically, I’m not implementing the call to get a token which is needed when you upload something to your own Meural. And I’m also not implementing all of the additional capabilities that the API has with regards to creating collections and that sort of stuff.
What I am doing is uploading the art so that it is available on the mobile device and from the mobile device I will select the images and I will push them to the canvas.
I can imagine that you do not have a Meural Canvas 2. So, in this case it would be hard to follow suit but in general there is also value in knowing how to change a message payload in order to make a connection to an API like the one that Meural is using.
The set up
Just to recap what you need if you want to try this out yourself:
- A version of the Micro Integrator (I am using version 4.2.0)
- Integration Studio in order to develop the artifacts that we’re going to deploy (I am using version 8.2)
- An API key from the Rijksmuseum in order to utilize their API
- A Meural canvas if you want to have the complete flow. If not, you can store the image locally
What do we have
What we currently have is an API that is capable of receiving a number of object numbers that will correspond with a digital artifact like a painting or a drawing from the Rijksstudio. The API will iterate through the repeating elements of the payload (in this case the object numbers), for each of these numbers it will try to retrieve information about the object and a download URL where we can actually download the file. This file is then stored locally on our drive and in the final step we are going to submit that file to the Meural API.
I have actually cut out some of the mediation that I covered in the previous blogs because that has not changed. You will see the three dots <…> </…> in the code where I’ve snipped out stuff. I’ve also made changes to the indentation in order to make more fit on one line and removed the token that was used as well as the key to retrieve the original information from the Rijksmuseum.
What is new?
What I have done is introduced a new property that will count the number of elements in the array. This property json-eval($.object.length()) stores the value in a property called ‘totalobjects’ and that value will be returned after the iteration in a custom payload indicating the number of processed objects.
<?xml version="1.0" encoding="UTF-8"?>
<api context="/art" name="Meural" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<property expression="json-eval($.object.length())" name="totalobjects" scope="default" type="STRING"/>
<iterate attachPath="json-eval($.object)" continueParent="true" expression="json-eval($.object)" id="it1" preservePayload="true" sequential="true">
<target>
<sequence>
<...> </...>
<property expression="fn:concat('/opt/wso2/Downloads/',get-property('objectnr'),'.jpg')" name="fp" scope="default" type="STRING"/>
<enrich>
<source clone="false" type="body"/>
<target property="ORIGINAL_PAYLOAD" type="property"/>
</enrich>
<file.write configKey="FC1">
<...> </...>
</file.write>
<enrich>
<source clone="false" property="ORIGINAL_PAYLOAD" type="property"/>
<target type="body"/>
</enrich>
<property name="DECODE_MULTIPART_DATA" scope="axis2" type="BOOLEAN" value="true"/>
<property expression="//ns:binary" name="Message" scope="default" type="STRING" xmlns:ns="http://ws.apache.org/commons/ns/payload"/>
<payloadFactory media-type="xml">
<format>
<root xmlns="">
<file Content-Type="image/jpeg" filename="$1" name="image" xmlns="http://org.apache.axis2/xsd/form-data">$2</file>
</root>
</format>
<args>
<arg evaluator="xml" expression="$ctx:fp"/>
<arg evaluator="xml" expression="get-property('Message')"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="multipart/form-data"/>
<header name="Content-Type" scope="transport" value="multipart/form-data"/
<property name="DISABLE_CHUNKING" scope="axis2" type="STRING" value="true"/>
<header name="Authorization" scope="transport" value="Token {TOKEN]"/>
<call blocking="true">
<endpoint>
<http method="post" uri-template="https://api.meural.com/v0/items">
<...> </...>
</http>
</endpoint>
</call>
<drop/>
</sequence>
</target>
</iterate>
<property expression="count(//retrieve/object)" name="TotalElements" scope="default" type="STRING"/>
<payloadFactory media-type="json">
<format>{"Message" : "$1 Images uploaded"}</format>
<args>
<arg evaluator="xml" expression="get-property('totalobjects')" literal="true"/>
</args>
</payloadFactory>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
/resource>
</api>
I’ve introduced a new mediator called the enrich mediator to save the original payload from retrieving the image that was given to us by the Rijksmuseum. I do this because I don’t want to lose the payload when the file connector overrides it with its response. So, the enrich mediator saves the payload into a property, we continue with the mediation and when we’re done and, in this case, we do not need to do anything with the payload that is possibly created by the file connector, we restore the original payload from the property in order to use it.
The following mediation sequence is partly dictated by what the API from Meural expects and partly the way the Micro ntegrator works in this case.
With the property mediator I set two values that are needed. I set decode_multipart_data to true so we do not encode the message and set the property Message to binary.
The next step uses the payload factory mediator in order to create a message that the Meural API requires.
Within that payload factory mediator, you see two values that start with the $ sign, $1 and $2. These are filled with the arguments you’ll find below the format. The first one is the file name and the second one is the message type.
Another three lines of mediation follow, setting the content type to multipart/form-data, Disable_chunking by setting it to true and finally adding the token to the header in order to authenticate this API call.
I’ve removed the token since it is sensitive information and should never be shared even if it has expired. An expired token cannot be used but in general it’s a good idea never to share tokens, client keys, client secrets or API keys. By not sharing them at any time you reduce the chance of errors / sharing by accident and so on.
Drop the message
At the end of the mediation of the iteration mediator you will see that we actually dropped the message because we are not interested in the response of the Meural API. We assume that everything is correct, and we do not do anything in the area of error handling.
In the real-world scenario of course, this is something that you need to consider and need to make sure that you do the error handling in the proper way.
But this is the nice thing of writing a blog we can abstract it a little bit and do not have to worry about every scenario that is feasible or even imaginable.
When we are done iterating through the JSON array the mediation continues with the next line which gives us a total of the number of objects that were retrieved and upload it to the Meural API.
This is the value that we started up with when the message came into the API where we counted the number of elements.
What I now have in my Meural app are a large number of artworks, that I can now Push to the canvas. This I can also automate but for this blog I will keep it a manual task. Otherwise, I would end up with parts 4 and 5 If I am not careful.
You will find the s with the artifacts at Yenlo Bitbucket
You can see that integration is not only for artists but for almost every developer. You can develop the needed integration to connect the Rijksstudio to Meural, but others can do that as well.
For Meural it can be part of their subscription of curated art that they offer for a monthly or yearly fee. So, there is a win for Meural / Netgear to develop those sorts of connections to museum resources directly. For the Rijksmuseum defining a button on the site to Push directly to a users Meural will allow people to enjoy art more with almost no work. It will boost engagement of the Rijksstudio. They can push digitized images of exhibitions people visited to the Meural at home. The sky is the limit. That is what I call : Digital Imagination.
Digital Imagination
I’m also going to look at what you can do with an API like this given the fact that a lot of resources have an API interface that it is actually quite simple to make a connection to.
I’m not only talking about museums and their collection of art but also about the Google Photos API where you perhaps store all of your holiday snaps.
The mechanism that I’m showing in these blogs in parts 1-2 and 3 can be applied to the Google API as well.
Of course, there will be changes that you need to make because not every API is the same.
On the contrary, organizations have a lot of freedom to create APIs in whatever shape of form they would like. Of course, there are purists and have a very narrow view of what an API is but, in the end, it is not up to the purists. It’s up to the organization, the architects, and the developers to determine how they are going to set up the APIs, establish naming and other guidelines.
Security
With regards to security, I think we still have a lot that we can do in terms of making APIs more secure because APIs are the door to services that you’re offering as an organization and if there is one thing you can be sure of is that your API is going to be attacked. An API management solution together with schema validation utilizing open API 3.0 descriptions will make your APIs more secure. But it’s also a question of making sure that all of the systems are up to date so there are no vulnerabilities that haven’t been patched but also that the transport between the people the person calling the API and the back end is secure.
With regards to that from the back-end perspective take a look at the OWASP 2023 security vulnerabilities list. It will show you the most common mistakes that people make when they’re creating an API with regards to the front end. An API management solution in my opinion is a must for every organization that takes APIs and itself seriously. Finally, Security s not an afterthought design is a principle applied from the beginning.