-
-
Save drewblas/b8f81c9fdba1824ec2939c5847871051 to your computer and use it in GitHub Desktop.
Revisions
-
drewblas revised this gist
Mar 30, 2016 . 1 changed file with 14 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -82,6 +82,20 @@ defmodule JsonSchema do {:ok, schema} end ### FROM DREW: ### This is a more minor quible, but I thought I'd throw it in to try and help: # # Calling validate should not be done from inside the GenServer # Doing so means that there is essentially a single-line queue where ALL # validate calls are passing through this single synchronous mailbox. # So if you've got 1,000 phoenix connections/processes all trying to validate # input, they will wait one by one to validate. # # There's no reason for this, as the only thing the GenServer should be responsible # for is holding the state (the resolved schema). Validating doesn't CHANGE the state. # So a normal module function can fetch the resolved schema from the GenServer # and use it in the validate call. # def handle_call({:validate, object, type}, _from, schema) do errors = get_validation_errors(object, type, schema) |> transform_errors -
drewblas revised this gist
Mar 30, 2016 . 1 changed file with 5 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -102,6 +102,11 @@ defmodule JsonSchema do ## validate throws a BadMapError on certain kinds of invalid ## input; absorb it (TODO fix ExJsonSchema upstream) try do ### FROM DREW: ### This call is a big problem: # type_schema is a %{} (Plain map). It's *NOT* a completely resolved schema (it's no longer a %ExJsonSchema.Schema.Root{} # This means that it will match on https://github.com/jonasschmidt/ex_json_schema/blob/238f565a62acaf6e304c66c3cca4d80d2ef43d22/lib/ex_json_schema/validator.ex#L23-L25 # and RE-CALL .resolve every time. Exactly what you were trying to avoid ExJsonSchema.Validator.validate(schema, type_schema, string_keyed_object) rescue _ -> [{"Failed validation", []}] -
gamache revised this gist
Jan 20, 2016 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ ## `priv/schema.json` ```json { @@ -76,7 +76,7 @@ defmodule JsonSchema do use GenServer def init(_) do schema = File.read!(Application.app_dir(:myapp) <> "/priv/schema.json") |> Poison.decode! |> ExJsonSchema.Schema.resolve {:ok, schema} -
gamache created this gist
Jan 20, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,129 @@ ## `schema.json` ```json { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Events API Schema", "definitions": { "event_collection": { "type": "object", "required": ["events"], "properties": { "events": { "type": "array", "items": { "$ref": "#/definitions/event" } } } }, "event": { "type": "object", "required": ["name", "timestamp"], "properties": { "name": { "type": "string" }, "timestamp": { "type": ["string", "integer"], "format": "date-time" }, "attributes": { "type": "object" } } } } } ``` ## `json_schema.ex` ```elixir defmodule JsonSchema do @moduledoc ~S""" A service which validates objects according to types defined in `schema.json`. """ @doc ~S""" Validates an object by type. Returns a list of {msg, [columns]} tuples describing any validation errors, or [] if validation succeeded. """ def validate(server \\ :json_schema, object, type) do GenServer.call(server, {:validate, object, type}) end @doc ~S""" Returns true if the object is valid according to the specified type, false otherwise. """ def valid?(server \\ :json_schema, object, type) do [] == validate(server, object, type) end @doc ~S""" Converts the output of `validate/3` into a JSON-compatible structure, a list of error messages. """ def errors_to_json(errors) do errors |> Enum.map(fn ({msg, _cols}) -> msg end) end use GenServer def init(_) do schema = File.read!("./schema.json") |> Poison.decode! |> ExJsonSchema.Schema.resolve {:ok, schema} end def handle_call({:validate, object, type}, _from, schema) do errors = get_validation_errors(object, type, schema) |> transform_errors {:reply, errors, schema} end defp get_validation_errors(object, type, schema) do type_string = type |> to_string type_schema = schema.schema["definitions"][type_string] not_a_struct = case object do %{__struct__: _} -> Map.from_struct(object) _ -> object end string_keyed_object = ensure_key_strings(not_a_struct) ## validate throws a BadMapError on certain kinds of invalid ## input; absorb it (TODO fix ExJsonSchema upstream) try do ExJsonSchema.Validator.validate(schema, type_schema, string_keyed_object) rescue _ -> [{"Failed validation", []}] end end @doc ~S""" Makes sure that all the keys in the map are strings and not atoms. Works on nested data structures. """ defp ensure_key_strings(x) do cond do is_map x -> Enum.reduce x, %{}, fn({k,v}, acc) -> Map.put acc, to_string(k), ensure_key_strings(v) end is_list x -> Enum.map(x, fn (v) -> ensure_key_strings(v) end) true -> x end end end ```