Example: Send A Signed Multi-Part Media HTTP POST Request With Clojure | Clojure, Twitter API, media/upload, OAuth 1.0, multipart/form-data, Authorization, Signed Request
| ;; Example: Send A Signed Multi-Part Media HTTP POST Request With Clojure | |
| ;; | |
| ;; Keywords: Clojure, Twitter API, media/upload, OAuth 1.0, multipart/form-data, Authorization, Signed Request | |
| ;; | |
| ;; Dependencies: [clj-http "2.2.0"] [clj-oauth "1.5.5"] | |
| ;; | |
| ;; Description: | |
| ;; The code is meant to read well as an example, not be idiomatic or efficiently organized. | |
| ;; | |
| ;; I am leaving the raw materials here, put it together how you'd like it! | |
| ;; | |
| ;; This example should work if you have the dependencies and run it. | |
| ;; | |
| ;; If you get this working, the APPEND and FINALIZE commands are just as easy. | |
| ;; Remember to base64 encode your byte array if you use the media_data parameter in your APPEND command request. | |
| ;; Don't try to type convert your byte-array, just pass it into the :content parameter of the multipart entry as is. | |
| ;; | |
| ;; | |
| (ns twitter-signed-multi-part-post-request-example.core | |
| (:require [clj-http.client :as http] | |
| [oauth.client :as oauth])) | |
| ;; I grabbed a JPEG from the internet. | |
| ;; | |
| ;; Wherever your media comes from, just make sure you can turn it into a byte-array. | |
| ;; | |
| (def grab-the-media-url "http://2.bp.blogspot.com/-Idj_-PCo-8k/Uh7bJseIHwI/AAAAAAAAHMU/ph8-m5x3LcY/s640/Autumn-Jpegs3.jpg") | |
| ;; I used the clj-http get function with the {:as :byte-array} option. | |
| ;; | |
| ;; This converts the body of your HTTP response to a byte-array. | |
| ;; | |
| (def media | |
| (let [options {:as :byte-array} | |
| response (http/get grab-the-media-url options)] | |
| (-> response :body))) | |
| ;; I store my OAuth parameters together here for easy access. | |
| ;; | |
| ;; Be sure to replace all the values below. | |
| ;; | |
| (def oauth-parameters | |
| {:consumer-credentials | |
| {:key "<Your Consumer Key Here>" | |
| :secret "<Your Consumer Key Secret Here>"} | |
| :urls | |
| {:request-token "<Current Twitter Request Token URL Here>" | |
| :access-token "<Current Twitter Access Token URL Here>" | |
| :authorize "<Current Twitter Authorize URL Here>"} | |
| :algorithm :hmac-sha1 | |
| :user-credentials | |
| {:token "<Your User Access Token Here>" | |
| :secret "<Your User Access Token Secret Here>"}}) | |
| ;; I create an OAuth consumer here with information from the oauth-parameters map. | |
| ;; | |
| ;; I am making use of the make-consumer function from clj-oauth here. | |
| ;; | |
| ;; The only OAuth parameter not used here is :user-credentials. | |
| ;; | |
| (def oauth-consumer | |
| (let [{:keys [consumer-credentials urls algorithm]} oauth-parameters] | |
| (oauth/make-consumer | |
| (-> consumer-credentials :key) | |
| (-> consumer-credentials :secret) | |
| (-> urls :request-token) | |
| (-> urls :access-token) | |
| (-> urls :authorize) | |
| algorithm))) | |
| ;; I MUST use the following api url for multi-part media uploads. | |
| ;; | |
| (def upload-api-url "https://upload.twitter.com/1.1/media/upload.json") | |
| ;; I MUST use the HTTP POST verb here. | |
| ;; | |
| (def http-method :post) | |
| ;; I create my OAuth credentials for this request. | |
| ;; | |
| ;; I am making use of the credentials function from clj-oauth here. | |
| ;; | |
| ;; The :user-credentials are now being used from oauth-parameters. | |
| ;; | |
| ;; Request parameters are not signed when sending multipart/form-data. | |
| ;; | |
| (def oauth-credentials | |
| (let [{:keys [user-credentials]} oauth-parameters] | |
| (oauth/credentials | |
| oauth-consumer | |
| (-> user-credentials :token) | |
| (-> user-credentials :secret) | |
| http-method | |
| upload-api-url))) | |
| ;; I keep my parameters together here for easy access. | |
| ;; | |
| ;; total-bytes simply comes from a count on the media byte-array | |
| ;; | |
| ;; I'm displaying how to send the INIT command in this example. | |
| (def http-request-parameters | |
| {:command "INIT" | |
| :total-bytes (-> media count str) | |
| :media-type "image/jpeg"}) | |
| ;; I keep my headers together here for easy access. | |
| ;; | |
| ;; I am making use of the authorization-header function from clj-oauth here. | |
| ;; | |
| ;; Check the OAuth 1.0 specification for the Authorizaton hdeader for more information about why this is necessary. | |
| ;; | |
| (def http-request-headers | |
| {:authorization (oauth/authorization-header oauth-credentials)}) | |
| ;; I create an HTTP request before sending it here to bring it all together. | |
| ;; | |
| ;; Note the :multipart parameter -- check the clj-http readme. | |
| ;; | |
| (def signed-http-request | |
| {:method http-method | |
| :url upload-api-url | |
| :headers {"Authorization" (-> http-request-headers :authorization)} | |
| :multipart [{:name "command" :content (-> http-request-parameters :command)} | |
| {:name "total_bytes" :content (-> http-request-parameters :total-bytes)} | |
| {:name "media_type" :content (-> http-request-parameters :media-type)}]}) | |
| ;; I send the signed http request. | |
| ;; | |
| ;; I am making use of the more general request function from clj-http here. | |
| ;; | |
| (http/request signed-http-request) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment