此帖子与此问题相同:https://elixirforum.com/t/simple-api-where-create-function-send-me-400-bad-request-but-i-cant-figure-out-why/16456,但该解决方案对我不起作用。
这是我的控制人:
defmodule ApaecWeb.UserController do
use ApaecWeb, :controller
alias Apaec.Auth
alias Apaec.Auth.User
action_fallback ApaecWeb.FallbackController
def index(conn, _params) do
IO.puts "user"
users = Auth.list_users()
render(conn, "index.json", users: users)
end
def create(conn, %{"user" => user_params}) do
with {:ok, %User{} = user} <- Auth.create_user(user_params) do
conn
|> put_status(:created)
|> put_resp_header("location", Routes.user_path(conn, :show, user))
|> render("show.json", user: user)
end
end
def show(conn, %{"id" => id}) do
user = Auth.get_user!(id)
render(conn, "show.json", user: user)
end
def update(conn, %{"id" => id, "user" => user_params}) do
user = Auth.get_user!(id)
with {:ok, %User{} = user} <- Auth.update_user(user, user_params) do
render(conn, "show.json", user: user)
end
end
def delete(conn, %{"id" => id}) do
user = Auth.get_user!(id)
with {:ok, %User{}} <- Auth.delete_user(user) do
send_resp(conn, :no_content, "")
end
end
def sign_in(conn, %{"email" => email, "password" => password}) do
case Apaec.Auth.authenticate_user(email, password) do
{:ok, user} ->
conn
|> put_status(:ok)
|> put_view(ApaecWeb.UserView)
|> render("sign_in.json", user: user)
{:error, message} ->
conn
|> put_status(:unauthorized)
|> put_view(ApaecWeb.ErrorView)
|> render("401.json", message: message)
end
end
end
我的模式:
defmodule Apaec.Auth.User do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "users" do
field :email, :string, null: false
field :is_active, :boolean, default: false, null: false
field :password, :string, virtual: true
field :password_hash, :string
timestamps(type: :utc_datetime_usec)
end
@doc false
def changeset(user, attrs) do
user
|> cast(attrs, [:email, :is_active, :password])
|> validate_required([:email, :is_active, :password])
|> unique_constraint(:email)
|> put_pass_hash()
end
defp put_pass_hash(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{password: pass}} ->
put_change(changeset, :password_hash, Pbkdf2.hash_pwd_salt(pass))
_ ->
changeset
end
end
end
我的FallbackController:
defmodule ApaecWeb.FallbackController do
@moduledoc """
Translates controller action results into valid `Plug.Conn` responses.
See `Phoenix.Controller.action_fallback/1` for more details.
"""
use ApaecWeb, :controller
def call(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> put_view(ApaecWeb.ErrorView)
|> render(:"404")
end
def call(conn, {:error, %Ecto.Changeset{}}) do
conn
|> put_status(:unprocessable_entity)
|> put_view(ApaecWeb.ErrorView)
|> render(:"422")
end
end
我的路线:
defmodule ApaecWeb.Router do
use ApaecWeb, :router
pipeline :api do
plug :accepts, ["json"]
end
scope "/api", ApaecWeb do
pipe_through :api
resources "/users", UserController, except: [:new, :edit]
post "/users/sign_in", UserController, :sign_in
end
end
当我在终端中使用curl -H "Content-Type: application/json" -X POST http://localhost:4000/api/users -d {"user":{"email":"some@email.com","password":"some apssword"}}
时。我不断得到:
[info] POST /api/users
[info] Converted error Plug.Parsers.ParseError to 400 response
我尝试删除user
部分或改用users
。我不太了解涉及记录器的解决方案,但这不是解决问题的方法。
编辑: 另外在powershell上运行它,我会收到此错误:
Invoke-WebRequest : Cannot bind parameter 'Headers'. Cannot convert the "Content-Type: application/json" value of type
"System.String" to type "System.Collections.IDictionary".
At line:1 char:9
+ curl -H "Content-Type: application/json" -X POST http://localhost:400 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-WebRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
所以我尝试了:
PS C:\Users\Me> $user = @{ email='dave@Dave.com'
>> password='pass'
>> }
PS C:\Users\Me> $json = $user | ConvertTo-Json
PS C:\Users\Me> Invoke-RestMethod 'http://localhost:4000/api/users' -Method POST -Body $json -ContentType 'application/json'
Invoke-RestMethod : {"errors":{"detail":"Bad Request"}}
At line:1 char:1
+ Invoke-RestMethod 'http://localhost:4000/api/users' -Method POST -Bod ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
它仍然给出不好的结果,但是控制台中有很多信息:
info] POST /api/users
[debug] Processing with ApaecWeb.UserController.create/2
Parameters: %{"email" => "dave@Dave.com", "password" => "[FILTERED]"}
Pipelines: [:api]
[info] Sent 400 in 0┬Ás
[info] Converted error Phoenix.ActionClauseError to 400 response
[info] POST /api/users
[info] Converted error Plug.Parsers.ParseError to 400 response
答案 0 :(得分:2)
我认为您的报价不正确
bash-3.2$ echo {"user":{"email":"some@email.com","password":"some apssword"}}
{user:email:some@email.com} {user:password:some apssword}
bash-3.2$ echo '{"user":{"email":"some@email.com","password":"some apssword"}}'
{"user":{"email":"some@email.com","password":"some apssword"}}
答案 1 :(得分:1)
感谢@Evadne,您让我有了探究终端和语法的想法。
PS C:\Users\Me> $json = '{"user":{"email":"some@email.com","password":"some apssword"}}'
PS C:\Users\Me> Invoke-RestMethod 'http://localhost:4000/api/users' -Method POST -Body $json -ContentType 'application/json'
导致预期的行为。不要认为api有什么问题,只是在Visual Studio代码终端中的curl实现。