Skip to content

Instantly share code, notes, and snippets.

@Leigh-
Last active July 6, 2016 20:24
Show Gist options
  • Save Leigh-/b1739cc464b81c356d084755fc65ebc1 to your computer and use it in GitHub Desktop.
Save Leigh-/b1739cc464b81c356d084755fc65ebc1 to your computer and use it in GitHub Desktop.
Initial version of CreateArticle Example for Apple News API. Tested under CF11
<cfscript>
/*
IMPORTANT: Make sure fileGetMimeType("c:/path/article.json") returns the
correct mime type in your environment:
ie: Should return: "application/json"
... and not : "text/plain"
*/
// Modify these variables for your environment
channelID = "63aFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
apiKeyID = "379FFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
apiKeySecret = "miJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
targetURL = "https://news-api.apple.com/channels/#channelID#/articles";
articlePath = ExpandPath("/apple/article/article.json");
resourcesFolder = ExpandPath("/apple/resources");
// metadata
metadata = { "data":{
"isPreview":true,
"links":{
"sections":[
"https://news-api.apple.com/sections/9e7bfbf2-ed0c-38a2-8c74-2da17348f4e6"
]
}
}
};
// Build properties for article and metadata
requestData = [ { "name" = "article.json"
, "type" = "application/json"
, "path" = articlePath
, "filename" = "article.json"
}
, { "name" = "metadata"
, "type" = "application/json"
, "value" = serializeJSON(metadata)
}
];
// Append resources
// note: file name handling should be more robust
resourceFiles = DirectoryList( resourcesFolder, false );
ArrayEach(resourceFiles, function( path, index ){
arrayAppend(requestData
, { "name" = "file"& arguments.index-1
, "type" = fileGetMimeType(arguments.path)
, "path" = arguments.path
, "filename" = listFirst(listLast(arguments.path, "\/"), ".")
}
);
}
);
writeDump( requestData );
// Initialize variables
utcDateTime = dateConvert( "local2UTC", now() );
dateValue = dateFormat( utcDateTime, "yyyy-mm-dd")&"T"& timeFormat(utcDateTime, "HH:nn:ss")&"Z";
boundary = replace(createUUID(), "-", "", "all");
contentType = "multipart/form-data; boundary="& boundary;
methodName = "POST";
// Generate request body (as binary)
requestBinary = buildRequestBody(boundary, requestData );
canonicalString = methodName & targetURL & dateValue & contentType;
// Note: CF11 workaround for ArrayAppend, which does not merge binary arrays
ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
canonicalBinary = ArrayUtils.addAll( charsetDecode(canonicalString, "utf-8"), requestBinary );
writeOutput("<br>canonicalString (minus body) ="& canonicalString );
// Generate signature and authorization header
signatureHash = hmac(canonicalBinary, binaryDecode(apiKeySecret, "base64"), "HMACSHA256");
signatureBase64 = binaryEncode(binaryDecode(signatureHash, "hex"), "base64");
authorization = "HHMAC; key=""#apiKeyID#""; signature=""#signatureBase64#""; date=""#dateValue#""";
// Initialize connection
urlObject = createObject("java", "java.net.URL").init( targetURL );
connection = urlObject.openConnection();
connection.setConnectTimeout( 15000 );
connection.setReadTimeout( 15000 );
connection.setDoOutput( true );
// Add headers Note: timeouts are in milliseconds (0 == infinite timeout)
connection.setRequestMethod( methodName );
connection.setRequestProperty("Content-type", contentType );
connection.setRequestProperty("Authorization", authorization);
// Copy body into request
outStream = connection.getOutputStream();
outStream.write( requestBinary, 0, arrayLen(requestBinary));
outStream.flush();
outStream.close();
// Get response
response.code = connection.getResponseCode();
response.message = connection.getResponseMessage();
// Read response
stream = (response.code == connection.HTTP_OK) ? connection.getInputStream() : connection.getErrorStream();
ioUtil = createObject("java", "org.apache.commons.io.IOUtils");
response.text = ioUtil.toString( stream, "utf-8" );
// Cleanup
stream.close();
connection.disconnect();
WriteOutput( "<br>authorization ="& authorization );
writeDump( response );
public array function buildRequestBody ( string boundaryMarker, array requestData, string encoding="UTF-8") {
Local.newLine = chr(13) & chr(10);
// Build streams for storing request body
Local.byteStream = createObject("java", "java.io.ByteArrayOutputStream").init();
Local.outStream = createObject("java", "java.io.OutputStreamWriter").init( byteStream, arguments.encoding );
Local.writer = createObject("java", "java.io.PrintWriter").init(Local.outStream, true);
Local.ioUtil = createObject("java", "org.apache.commons.io.IOUtils");
// Write data to request stream
for (Local.requestElem in arguments.requestData) {
// Write headers for new field
Local.writer.write( "--"& arguments.boundaryMarker );
Local.writer.write( Local.newLine );
Local.writer.write( "Content-Type: "& Local.requestElem.type );
Local.writer.write( Local.newLine );
Local.writer.write( "Content-Disposition: form-data");
// Append physical file
if (structKeyExists(Local.requestElem, "path")) {
Local.writer.write("; filename="& Local.requestElem.fileName );
Local.writer.write("; name=" & Local.requestElem.name );
Local.writer.write("; size="& GetFileInfo(Local.requestElem.path).size );
Local.writer.write( Local.newLine );
Local.writer.write( Local.newLine );
Local.writer.flush();
Local.inputStream = createObject("java", "java.io.FileInputStream").init( Local.requestElem.path );
Local.ioUtil.copy( Local.inputStream, Local.byteStream );
}
// Otherwise, assume this is a simple string
else {
Local.valueBinary = charsetDecode(Local.requestElem.value, arguments.encoding );
Local.writer.write("; name=" & Local.requestElem.name);
Local.writer.write("; size="& arrayLen(Local.valueBinary) );
Local.writer.write( Local.newLine );
Local.writer.write( Local.newLine );
Local.writer.flush();
Local.byteStream.write( Local.valueBinary );
}
// Prepare to move to next field
Local.byteStream.flush();
Local.ioUtil.closeQuietly( Local.inputStream );
Local.writer.write( Local.newLine );
}
// Generate closing boundary
Local.writer.write( "--"& boundary &"--" );
Local.writer.write( Local.newLine );
// Cleanup
Local.ioUtil.closeQuietly( Local.writer );
Local.ioUtil.closeQuietly( Local.byteStream );
// Return request binary
return Local.byteStream.toByteArray();
}
</cfscript>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment