Hey besically the title says it,
I am trying to send a file to my elixir api and, i just noticed that in the router it has this plug: plug(:accepts, ["json"])
, but since i am trying to send a file i am sending a multipart request not json.
Thoughts?
You shouldn’t need to change anything in the Plug pipeline - the file should be included as part of the form wrapped in a Plug.Upload struct. If you’re not seeing the file in your params it might be that you’re hitting the upload limits? The blog post on uploads would have more info: https://phoenixframework.org/blog/file-uploads
no i dont think i hit it, i am trying to send the file like this :
let data = new FormData();
data.append("xd", {
recording: rec,
challenge_id: 1,
user_id: 1,
mod_score: 3
});
console.log(data);
axios
.post(
config.API_URL + "recordings",
{ data },
{
headers: {
Authorization: "Bearer " + this.props.auth.token,
"content-type": "multipart/form-data"
}
}
)
but only an empty struct %{} show up
Can you also show the code of your controller?
glady
def create(conn, %{"recording" => recording_params}) do
with {:ok, %Recording{} = recording} <- Web.create_recording(recording_params) do
challenge = Web.get_challenge!(recording.challenge_id)
number_of_days_between = Date.diff(challenge.due_date, recording.inserted_at)
calculated_score = number_of_days_between * challenge.difficulty * 100
user = Web.get_user!(recording.user_id)
IO.inspect(user)
score_to_insert = user.score + calculated_score
updated_user = %{
score: score_to_insert
}
Web.update_user(user, updated_user)
send_resp(conn, 200, [])
# conn
# |> put_status(:created)
# |> render("show.json", recording: recording)
end
end
youcould see most of the related code in this post: Sending and recieveing a file(audio) from app to elixir api issue
im chaing the request to try to match but no success yet
And where is it you see only an empty map?
i am runnign the server with foreground command and says this
info] POST /api/recordings
[debug] QUERY OK source="users" db=0.3ms decode=0.1ms queue=0.2ms
SELECT u0."id", u0."name", u0."password_hash", u0."score", u0."avatar", u0."role_id", u0."team_id", u
0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) [2]
[debug] QUERY OK source="roles" db=0.2ms queue=0.2ms
SELECT r0."id", r0."name", r0."inserted_at", r0."updated_at", r0."id" FROM "roles" AS r0 WHERE (r0."i
d" = $1) [1]
[debug] QUERY OK source="teams" db=0.2ms queue=0.5ms
SELECT t0."id", t0."name", t0."inserted_at", t0."updated_at", t0."id" FROM "teams" AS t0 WHERE (t0."i
d" = $1) [2]
[debug] Processing with Userteam1Web.RecordingController.create/2
Parameters: %{}
Pipelines: [:api, :jwt_authenticated]
[info] Sent 400 in 38ms
[debug] ** (Phoenix.ActionClauseError) could not find a matching Userteam1Web.RecordingController.cre
ate clause
to process request. This typically happens when there is a
parameter mismatch but may also happen when any of the other
action arguments do not match. The request parameters are:
%{}
here at the end
ok something intersting, if i remove this: ```
"content-type": "multipart/form-data"
then this shows up, still doesnt match but it shows up:
%{"data" => %{"_parts" => [["recording", %{"_duration" => -1, "_fsPath" => "/data/user/0/com.cobrn/files/filename.mp4", "_lastSync" => -1, "_options" => %{"autoDestroy" => true}, "_path" => "filename.mp4", "_position" => -1, "_recorderId" => 0, "_state" => -2}], ["challenge_id", 1], ["user_id", 1]]}}
it very much seems like our api does not accept formdata
According to axios’ documentation JS part should be like this:
let data = new FormData();
data.append("recording[file]", rec);
data.append("recording[challenge_id]", 1);
data.append("recording[user_id]", 1);
data.append("recording[mod_score]", 3);
console.log(data);
axios.post(
config.API_URL + "recordings",
data,
{
headers: {
Authorization: "Bearer " + this.props.auth.token,
"Content-Type": "multipart/form-data"
}
}
);
To match your controller.
Hey really really appreciate the answer, i tried this code and got this reponse:
`%{"challenge_id" => "1", "mod_score" => "3", "user_id" => "1"}`
and a 422 response code
so it seems like the file is not there for some reason, but the request is correct
could you link that part of their docs? I can’t seem to find it
figured it out, the upload was incorrect, it is working like this:
data.append("recording[path_to_recording]", {
uri: "file://" + rec._fsPath,
name: "filename.mp4",
type: "audio/mp4"
});
figured it out, the upload was incorrect, it is working like this, you need to specify the type
data.append("recording[path_to_recording]", {
uri: "file://" + rec._fsPath,
name: "filename.mp4",
type: "audio/mp4"
});
Actually it was not the docs but an example https://github.com/axios/axios/tree/master/examples/upload .
You can also check this link https://serversideup.net/uploading-files-vuejs-axios/
Are you using Plug.Parsers? https://hexdocs.pm/plug/Plug.Parsers.html
hm, in endpoint.ex i have it yes
Hello, I am having the same / similar issue.
I try including multipart in my header.
My endpoint.ex shows
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Poison
I upload as a post with the body being a dictionary, key: photo, value: (the form data).
In logging conn
and params
in my controller I see nothing indicative of data being sent up.
Is there something else I have to configure in my controller to allow file upload? The JS side looks fine with the uploading of FormData.
Are you using nginx in front of Phoenix? I had this problem once and found out nginx had a maximum size for post data and was rejecting them before they got to Phoenix. I had to google to find out how to raise that maximum limit in nginx but it fixed my situation.
For me the issue was on the js side, the elixir side was fine as it turned out, your form data might be incorrect.
What we did was that we appended everything to the formdata and only sent that like this for example:
function uploadAvatar(user, file, token) {
let fd = new FormData();
fd.append("user[avatar]", {
uri: file.path,
name: "test.jpg",
type: file.mime
});
fd.append("id", user.id);
return {
types: [
userConstants.UPLOAD_AVATAR_REQUEST,
userConstants.UPLOAD_AVATAR_SUCCESS,
userConstants.UPLOAD_AVATAR_FAILURE
],
callAPI: () =>
axios
.put(config.API_URL + "user", fd, {
headers: { Authorization: "Bearer " + token }
})
.then(res => res.data)
};
}
and you see where you append you need to set the key like it is in the example like “id” and if it is a param then you do like “user[avatar]” so your controller can use it to do what yo want to do