Validate all possible API param shapes / types

Hello,

I am writing an elixir library that wraps an HTTP API. If you check out this endpoint ReDoc Interactive Demo you’ll see the POST body can have multiple shapes as there are some fields that are optional and some that are required. I am seeking some advice on how to properly validate all possible API params (and their types) for a given endpoint.

In the simplest form I envision my library having a function build_transaction(params) that accepts a params variable and then validates its shape and types.

I did some research and saw there are some validation libraries out there but wanted to see what you guys use.

This endpoint ReDoc Interactive Demo is a good example of how complex a POST body can be. If you expand the metadata field you’ll see that the type has a set number of possibilities and also per each selection there are additional fields required.

Thanks for any help / guidance!

Something that caught my attention was this pattern from Sasha https://medium.com/very-big-things/towards-maintainable-elixir-the-core-and-the-interface-c267f0da43

I like the idea of being able to define the shape of a map by specifying its keys, types and if its required or not.

I am seeking some advice on how to properly validate all possible API params (and their types) for a given endpoint.

What kind of content type for POST’s body are you looking to validate? Is it JSON (like in the linked example), or is it arbitrary form data too?

If it’s JSON, would you consider following OpenAPI/Swagger approach, e.g. using a JSON Schema to validate the shape of incoming request? If yes, then perhaps you could get inspired from libraries that attempt to doing a similar thing, e.g. Xema and ExJsonSchema, see: Xema and JsonXema - Schema validatiors

I have something like this in my head. It looks gross but kinda conveys what im after - being able to define what is required, what type it is and also the key names. The below snippet is for ReDoc Interactive Demo

%{
  network_identifier: [type: :map, required: true, [%{network: [type: :string, required: true]}]],
  entity_identifier: [type: :map, required: true, %{address: [type: :string, required: true],
                                                    sub_entity: [type: :map, required: false, [%{address: [type: :string, required: true]},
                                                                                                %{metadata: [type: :map, required: false, [%{validator_address: [type: :string, required: false]},
                                                                                                                                            %{epoch_unlock: [type: :integer, required: false]}]]}]]}]}

Awesome links - and how i have things setup right now is the user of my library would build an elixir map and then pass it to my build_transaction method which would then send it as the body of a POST request to ReDoc Interactive Demo

Based on your description, I would strongly suggest looking into JSON Schema, which is currently being standardised.

Effectively, with JSON Schema you define a JSON object with rules (think of Elixir map here). Then you take a JSON with request body, and attempt to match it with a JSON object containing rules. This would be the validation of request.

This document should give you an idea of what’s possible with JSON schemas. In a nutshell, you’re able to specify:

  • what fields the request may contain,
  • what is optional/required,
  • what expected types of values are,
  • if it’s an array, what is the min/max number of acceptable items it may have,
  • enums,
  • etc.

The link I posted in my previous message refers to two existing implementations of JSON Schema in Elixir.

1 Like