elixir-maru / maru

Elixir RESTful Framework
https://maru.readme.io
BSD 3-Clause "New" or "Revised" License
1.32k stars 84 forks source link

Maru ignores input parameter if its value is null #41

Closed take-five closed 7 years ago

take-five commented 7 years ago

Hello!

I wanted to give Elixir a try and tried to implement very simple JSON API using Maru. Maru is looking good for me at the moment, but I've found strange behavior recently.

Here is Maru router which describes what I've found:

defmodule API do
  before do
    plug Plug.Parsers,
      pass: ["*/*"],
      json_decoder: Poison,
      parsers: [:urlencoded, :json, :multipart]
  end

  params do
    optional :phone, type: String
  end
  post do
    conn |> json(params)
  end
end

I expect that this endpoint will return a JSON containing exact value of given phone param. It works in most cases:

$ curl -H "Content-Type: application/json" -X POST -d '{"phone":"123"}' http://localhost:4000/
{"phone":"123"}

But if I pass "null" value, maru will discard this parameter completely:

$ curl -H "Content-Type: application/json" -X POST -d '{"phone":null}' http://localhost:4000/
{}

This behaviour restricts JSON API very much, so as an API designer I can't provide ability to use null values for certain keys (which is necessary in my case).

Is this intentional or is it a bug? Thanks :)

falood commented 7 years ago

Hi @take-five , This is intentional. It's suitable in my case and I followed this guide Null_Property_Values. Could you please show me your case used it?

take-five commented 7 years ago

I'm designing a simple REST API which supports CRUD operations. Let's say, I want to update user information via REST API. "phone" column can have null values, it's a legacy DB and I can't change it. So how do I set "phone" to null via REST API? I can pass empty string, but that's very confusing for API user.

take-five commented 7 years ago

Also, I guess Google guide refers mostly to JSON response rather than request

falood commented 7 years ago

how about decide whether keep it by an option like this: when I pass {"phone": null} to endpoint, optional :phone, keep_blank: true will get %{phone: nil} and optional :phone will get %{} ?

take-five commented 7 years ago

Sounds like a good plan. Will optional :phone, keep_blank: true implicitly set parameter to nil if it wasn't passed? I believe it shouldn't.

falood commented 7 years ago

It shouldn't.