Last active
December 14, 2019 13:49
-
-
Save cjbarre/e93b78c2ef4b704f0eb222691dbdd5fa to your computer and use it in GitHub Desktop.
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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