Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

JSON Schema: Your API's Secret Weapon

1.323 visualizaciones

Publicado el

Publicado en: Ingeniería
  • Sé el primero en comentar

JSON Schema: Your API's Secret Weapon

  1. 1. JSON Schema: Your API’s Secret Weapon API Craft Boston / 2016-03-10 Pete Gamache / pete@appcues.com / @gamache
  2. 2. JSON Schema Describes the structure of JSON data using a JSON-based language Standards-track Simple Great at nested objects Generally treated as documentation Good library support, though
  3. 3. Example: Event {
 "name": "button_click",
 "timestamp": 1457437187,
 "attributes": {
 "button_id": 271828,
 "page": "/"
 }
 }
  4. 4. Example JSON Schema {
 "$schema": "http://json-schema.org/draft-04/schema#",
 "title": "Example Schema",
 "definitions": {
 "event": {
 "type": "object",
 "required": ["name", "timestamp"],
 "properties": {
 "name": {"type": "string"},
 "timestamp": {"type": "integer"},
 "attributes": {"type": "object"}
 }
 },
 // ...
  5. 5. Example: Event Collection {
 "events": [
 {
 "name": "button_click",
 "timestamp": 1457437187,
 "attributes": {
 "button_id": 271828,
 "page": "/"
 }
 },
 // ...
 ]
 }
  6. 6. Example JSON Schema {
 "$schema": "http://json-schema.org/draft-04/schema#",
 "title": "Example Schema",
 "definitions": { // ...
 "event_collection": {
 "required": ["events"],
 "properties": {
 "events": {
 "type": "array",
 "items": {"ref": "#/definitions/event"}
 }
 }
 },
 // ...
  7. 7. It would be a shame for a lovely, machine-readable doc like that to be wasted on humans...
  8. 8. JSON Validation with Elixir and ExJsonSchema iex> schema = File.read!("schema.json") |> Poison.decode! |> ExJsonSchema.Schema.resolve
 
 iex> event_schema = schema.schema["definitions"]["event"]
 
 iex> ExJsonSchema.Validator.validate(schema, event_schema, %{})
 [{"Required property name was not present.", []},
 {"Required property timestamp was not present.", []}]
 
 iex> ExJsonSchema.Validator.validate(schema, event_schema, %{"name" => "hi", "timestamp" => 1})
 []
  9. 9. JSON Validation with Elixir and ExJsonSchema, cont. iex> event_collection_schema = schema.schema["definitions"] ["event_collection"]
 
 iex> ExJsonSchema.Validator.validate(schema, event_collection_schema,
 ...> %{"events" => [
 ...> %{"name" => "event 1", "attributes" => %{"awesome" => true}},
 ...> %{"name" => "event 2", "timestamp" => "whenever"},
 ...> %{"name" => "event 3", "timestamp" => 1234567890}
 ...> ]})
 [{"Required property timestamp was not present.", ["events", 0]},
 {"Expected "whenever" to be a valid ISO 8601 date-time.",
 ["events", 1, "timestamp"]}]
  10. 10. Use Case 1: Input Validation Writing data validators is a pain, especially for anything complex Not only do we have to validate input, we need to generate coherent error messages Lots of opportunity to reinvent the wheel, but let's not
  11. 11. API Input Validation with Elixir and ExJsonSchema defmodule MyApp.EventsController do
 use MyApp.Web, :controller
 plug :validate_params
 
 defp validate_params(conn, _params) do
 case JsonSchema.validate(conn.params, :event_collection) do
 [] ->
 conn |> assign(:event_collection, conn.params)
 errors ->
 json_errors = errors |> JsonSchema.errors_to_json
 conn |> put_status(422) |> json(%{errors: json_errors}) |> halt
 end
 end
 
 def save_events(conn, params) do
 event_collection = conn.assigns[:event_collection]
 # ... do something here
 conn |> put_status(202) |> json(%{ok: true})
 end
 end
  12. 12. Use Case 2: Output Validation Pointing to the JSON Schema in API docs is great for humans Performing JSON Schema validation in API tests ensures your docs aren't lying*. This is also great for humans
 * at least not about output data structure format
  13. 13. API Output Validation with Elixir and ExJsonSchema defmodule MyApp.EventsControllerTest do
 use Plug.Test
 
 test "it returns well-formed event collection" do
 resp = conn(:post, "url goes here", %{params: ...})
 |> MyApp.Router.call(MyApp.Router.init([]))
 resp_object = resp.resp_body |> Poison.decode!
 assert([] ==
 JsonSchema.validate(resp_object, :event_collection))
 end
 
 # ... more tests here
 end
  14. 14. References http://json-schema.org/ JSON Pointer -- https://tools.ietf.org/html/rfc6901 https://github.com/jonasschmidt/ex_json_schema https://engineering.appcues.com/2016/01/20/ex-json- schema.html http://www.slideshare.net/petegamache/ jsonschema20160310
  15. 15. Questions?
  16. 16. Love APIs? Appcues is hiring! APIs in Elixir and ES6/AWS Lambda/API Gateway Frontend in ES6/Redux/React http://tinyurl.com/appcues-full-stack

×