ndaljr

ndaljr

What's the standard for validating json bodies for an api?

I’m still new to phoenix, prolly somewhere around 2 weeks old. I’m trying to build a json api and I’m having difficulty finding the best practice for validation. For example if my json api expects a body like

{ 
  name: "hello",
  email: "test@gmail.com"
}

And my client only sends

{
  name: "test"
}

My appliation immediately throws a 500. What’s the current best practice for resolving this?

Most Liked

soup

soup

As above, you can use Ecto + schemaless changesets to validate anything, so I would reach for that.

There are a few ways, you can pipe and pattern match or whatever. Just pass the changeset around to whatever function.

  # warning: written in brief, may not compile but should give 
  # idea of method.
  def my_changeset(attrs) do
    changeset =
      echo_schemaless_stuff()
      |> base_changeset(attrs)
      # inspect the changeset in the function
      |> maybe_validate_price()
      # or send the value as param
      |> maybe_validate_color(Map.get(attrs, :color, :maybe_some_default))
    #or you can just if attrs.value do ... etc
  end

  def maybe_validate_price(changeset) do
    case Ecto.Changeset.get_field(changeset, :price) do
      # dont validate
      nil ->
        changeset

      value when is_integer(value) ->
        changeset
        |> validate_number(value, greater_than: 0)
        # ...

      value when is_binary(value) ->
        changeset
        |> validate_format(...)
    end
  end

  def maybe_validate_color(changeset, :maybe_some_default) do
    # no validation
    changeset
  end

  def maybe_validate_color(changeset, color) when color in ~w(red green blue) do
   # correct colors
    changeset
  end

  def maybe_validate_color(changeset, color) do
    #  fail
    changeset
    |> add_error(:color, :some_error)
  end

Its also common(?) (maybe becoming common?) to have schemaless models backing your forms/api vs your actual CRUD operations (which also still have their own changesets).

This can give you some separation between “API validation” and “Data validation” if that makes sense. You then don’t need your form to match your schema exactly. You could, as a very trite example, accept “length” + “unit” in your form, validate that as you like, then always convert it to “length in mm” before sending to your actual db schema type which can just validate that the number between 0 and 100000 or whatever. This becomes more applicable as your model complexity increases, for basic stuff you can often stick with 1:1 or a simple “pass through”.

E: in terms of nested JSON, you can make schemaless types for each “nested section” to validate independently too. I do this for a pretty complex migration aide where you can have many different types of data cross associated and it works well and is pretty “brainable”.

NobbZ

NobbZ

Can you please provide an example action where this happens?

I assume, you are haveing a line like {:ok, data} = JSON.decode(body_data) where it isn’t able to match due to the incomplete data. Thats where you need to use a case expression where you branch depending on the result of the call to JSON.decode/1 (which in reality can have any other name and arity, depends on the tools you use, which you didn’t even told us which that were).

dom

dom

Ecto changesets are pretty much the standard. If you’re not saving the JSON to a DB, you can use “schemaless” changesets:

Your example for instance would work with validate_required.

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New

Other popular topics Top

jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement