Tired of json-schema, try dry-validation

Validating JSON schemas with rspec + dry-validation

Photo by Siavash Ghanbari on Unsplash

Why you should use dry-validation over json-schema?

An example of old way testing JSON responses. First define the JSON schema:


{
"type": "object",
"required": ["user"],
"properties": {
"user" : {
"type" : "object",
"required" : [
"id",
"token",
"token_expired_at",
"email",
"firstname",
"lastname",
"gender",
"phone_number",
"birthday"
],
"properties" : {
"id" : { "type" : "integer" },
"token" : { "type" : "string" },
"token_expired_at" : { "type" : "string" },
"email" : { "type" : "string" },
"lastname" : { "type" : "string" },
"firstname" : { "type" : "string" },
"gender" : { "type" : "string" },
"phone_number" : { "type" : "string" },
"brithday" : { "type" : "string", "format": "date-time" },
"updated_at" : { "type" : "string", "format": "date-time" },
"created_at" : { "type" : "string", "format": "date-time" },
}
}
}
}

Then write your test

describe "Sign in" do
context "anonymous user" do
it "returns data in the specified format" do
sign_in_as_anonymous
expect(response).tomatch_response_schema("users/anonymous_detail")
end
end
en

]

Not speaking of bad errors, you have to switch to JSON schema syntax and Ruby over and over again (context switching) and there your are you’ve lost your time and focus. Now I’m going to show you a better way to validate your mighty JSON with ease.

Creating the custom matcher

group :test do
gem "dry-validation"
end

spec/support/matchers/match_schema.rb

RSpec::Matchers.define :match_schema do |schema|
match do |response|
@result = schema.call(JSON.parse(response.body, symbolize_names: true))
@result.success?
end
def failure_message
@result.errors
end
end

Here I’ve chosen /spec/support/matchers/* for my custom matchers with a name convention of match_*. Also in schema.call “schema” is dry-validation class and “call” initializes the schema class with the given parameters then I return the result of validation which is a true/false value. I’ve even defined “failure_message” to be able to see the errors that have been generated from validating the schema inside rspec result.

Defining the anonymous user schema

require "support/views/schemas"

spec/support/views/schemas.rb

Now defining anonymous user schema:

AnonymousUserSchema = Dry::Validation.Schema do
required(:user).schema do
required(:email)
required(:token).filled
required(:token_expired_at).filled
required(:firstname)
required(:lastname)
required(:gender)
required(:phone_number)
required(:birthday)
end
end

Now you can change your spec to this:

describe "Sign in" do
context "anonymous user" do
it "returns data in the specified format" do
sign_in_as_anonymous

expect(response).to match_schema(AnonymousUserSchema)
end
end
end

There you go! What if when I added a new field? You just add the field with the needed condition to end of the block.

AnonymousUserSchema = Dry::Validation.Schema do
required(:user).schema do
required(:email)
required(:token).filled
required(:token_expired_at).filled
required(:firstname)
required(:lastname)
required(:gender)
required(:phone_number)
required(:birthday)
required(:age).maybe(int?)
end
end

With dry-validation you can do pretty much everything. For further information please checkout the link down below.

I hope you have enjoyed :D

∞ Travel | Coding | Lifestyle ⦿ Bangkok | ✧ #freelancer ▷ Got a project? ⭣ www.upwork.com/fl/al3rez