内容简介:Last week I took a look at three data specification libariers in Clojure:Data specification language.This is the foundation of every data specification library: a way to describe the data with a schema. You could use an existing language such asValidation.
Last week I took a look at three data specification libariers in Clojure: Schema, Spec, and Malli . This week, let’s talk about the essential features of these libraries.
Data specification language.This is the foundation of every data specification library: a way to describe the data with a schema. You could use an existing language such as JSON Schema , but in practice that’s clunky and everybody develops their own language.
;; Let's model users. We want to know the user's name and the year of birth. ;; Schema (require '[schema.core :as schema]) (def User {:name schema/Str, :year-of-birth schema/Int}) ;; Spec (require '[clojure.spec.alpha :as spec]) (spec/def ::year-of-birth int?) (spec/def ::name string?) (spec/def ::user (spec/keys :req-un [::name ::year-of-birth]))
Validation.The basic operation is to validate data against a schema. What is interesting is what happens when the validation fails. Easy-to-read error messages are essential for the developers, but having errors as data is a useful building block, too. For example, you could build front-end form validation on top of a data specification library, and then you’d know what was the problem and in which field.
;; Our user data example is missing the year of birth. Who gives out their ;; real year of birth, anyway, to the services we (the software industry) build? (def a-user {:name "hello@example.com", :year-of-birth nil}) (schema/validate User a-user) ;; Execution error (ExceptionInfo) at schema.core/validator$fn (core.clj:155). ;; Value does not match schema: {:year-of-birth (not (integer? nil))} (spec/valid? ::user a-user) ;; => false (spec/explain ::user a-user) ;; nil - failed: int? in: [:year-of-birth] at: [:year-of-birth] spec: :user/year-of-birth
Conforming.This feature is only implemented by Spec, but the idea is more general. A data specification language allows you to declare a grammar for your data structure. Conforming is parsing your data against that grammar. The result is akin to an abstract syntax tree, and Spec calls the conversion in the other direction “unforming”.
;; The regular expression specs and spec/or reveal the power of conforming. ;; Let's model hiccup-style HTML data. (spec/def ::hiccup (spec/cat :tag keyword? :options (spec/? map?), :children (spec/* (spec/or :tag ::hiccup, :text string?)))) ;; Now let's parse an anchor tag into a neat map. (spec/conform ::hiccup [:a {:href "http://www.example.com/"} "Check out " [:i "example.com"]]) ;; {:tag :a, ;; :options {:href "http://www.example.com/"}, ;; :children [[:text "Check out "] ;; [:tag {:tag :i, ;; :children [[:text "example.com"]]}]]}
Coercion.Coercion, or more generally, schema-driven transformation of data means that you walk your data and schema together and apply transformations to build new data. This allows you to do things like converting date strings in JSON to java.time instants and vice versa.
Program instrumentation.Yet another use case for data validation is to define a contract for a function: what kind of inputs it takes, what kind of data it returns, and how these are related. This is what Spec’s fdef
does.
(require '[clojure.spec.test.alpha :as stest]) (defn plus [x y] (+ x y)) (spec/fdef plus :args (spec/cat :x int? :y int?) :ret int?) (stest/instrument `plus) (plus 1 2) ;; => 3 (plus 1 "2") ;; Execution error - invalid arguments to user/plus at (REPL:1). ;; "2" - failed: int? at: [:y]
Schema introspection.The ability to inspect the schema enables features such as generating JSON Schema from your schemas, as shown by spec-tools .
Performance.Data specification libraries can end up playing a pretty important role in your application. For REST APIs, JSON coercion is part of every request, and if you use instrumentation, validation is literally everywhere.
In my experience, indiscriminate use of Spec’s instrumentation makes programs crawl. Michael Borkent shared a similar experience on The REPL podcast :
If you have an application and you have like 100 core specs and then you start instrumenting those, the application becomes really really slow, even in just in development. So the overhead of calling spec validations on every function call in Clojure program becomes too much for core functions. That is what I had found and I was a little bit disappointed that it didn’t work out, so, at least for dev purpose.
The performance matters and your data specification library can become a bottleneck.
As far as I know, no data specification library for Clojure has all of the features mentioned above. Hopefully this list helps you to choose one – or to decide to roll your own!
以上所述就是小编给大家介绍的《Essential features of data specification libraries》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Cascading Style Sheets 2.0 Programmer's Reference
Eric A. Meyer / McGraw-Hill Osborne Media / 2001-03-20 / USD 19.99
The most authoritative quick reference available for CSS programmers. This handy resource gives you programming essentials at your fingertips, including all the new tags and features in CSS 2.0. You'l......一起来看看 《Cascading Style Sheets 2.0 Programmer's Reference》 这本书的介绍吧!