%% Usage: %% upload_request(<<"site.com/api/upload">>, <<"path/to/file.png">>, <<"upload">>, <<"image/png">>, [], <<"some-token">>) %% %% Usage with RequestData: %% Payload = [{upload_type, <<"user_picture">>}], %% PayloadContent = jsx:encode(Payload), %% RequestData = [ %% {<<"payload">>, PayloadContent} %% ] %% upload_request(<<"site.com/api/upload">>, <<"path/to/file.png">>, <<"upload">>, <<"image/png">>, RequestData, <<"some-token">>) -spec upload_request(URL, FilePath, Name, MimeType, RequestData, AuthorizationToken) -> {ok, binary()} | {error, list()} when URL:: binary(), FilePath:: binary(), Name:: binary(), MimeType:: binary(), RequestData:: list(), AuthorizationToken:: binary(). upload_request(URL, FilePath, Name, MimeType, RequestData, AuthorizationToken) -> Method = post, Filename = filename:basename(FilePath), {ok, Data} = file:read_file(FilePath), Boundary = generate_uuid(), RequestBody = format_multipart_formdata(Data, RequestData, Name, [Filename], MimeType, Boundary), ContentType = "multipart/form-data; boundary=" ++ binary_to_list(Boundary), ContentLength = integer_to_list(length(binary_to_list(RequestBody))), Headers = [ {"Content-Length", ContentLength}, case AuthorizationToken =/= undefined of true -> {"Authorization", "Bearer " ++ binary_to_list(AuthorizationToken)}; false -> {} end ], HTTPOptions = [], Options = [{body_format, binary}], inets:start(), httpc:request(Method, {binary_to_list(URL), Headers, ContentType, RequestBody}, HTTPOptions, Options). -spec format_multipart_formdata(Data, Params, Name, FileNames, MimeType, Boundary) -> binary() when Data:: binary(), Params:: list(), Name:: binary(), FileNames:: list(), MimeType:: binary(), Boundary:: binary(). format_multipart_formdata(Data, Params, Name, FileNames, MimeType, Boundary) -> StartBoundary = erlang:iolist_to_binary([<<"--">>, Boundary]), LineSeparator = <<"\r\n">>, WithParams = lists:foldl(fun({Key, Value}, Acc) -> erlang:iolist_to_binary([ Acc, StartBoundary, LineSeparator, <<"Content-Disposition: form-data; name=\"">>, Key, <<"\"">>, LineSeparator, LineSeparator, Value, LineSeparator ]) end, <<"">>, Params), WithPaths = lists:foldl(fun(FileName, Acc) -> erlang:iolist_to_binary([ Acc, StartBoundary, LineSeparator, <<"Content-Disposition: form-data; name=\"">>, Name, <<"\"; filename=\"">>, FileName, <<"\"">>, LineSeparator, <<"Content-Type: ">>, MimeType, LineSeparator, LineSeparator, Data, LineSeparator ]) end, WithParams, FileNames), erlang:iolist_to_binary([WithPaths, StartBoundary, <<"--">>, LineSeparator]). % Thanks to https://github.com/afiskon/erlang-uuid-v4 generate_uuid() -> <> = crypto:rand_bytes(16), Str = io_lib:format("~8.16.0b-~4.16.0b-4~3.16.0b-~4.16.0b-~12.16.0b", [A, B, C band 16#0fff, D band 16#3fff bor 16#8000, E]), list_to_binary(Str).