{"id":18883,"date":"2020-09-11T09:15:50","date_gmt":"2020-09-11T15:15:50","guid":{"rendered":"https:\/\/www.fullcontact.com\/?p=18883"},"modified":"2020-09-11T11:41:33","modified_gmt":"2020-09-11T17:41:33","slug":"code-is-data-data-is-code","status":"publish","type":"post","link":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/","title":{"rendered":"Code is Data, Data is Code"},"content":{"rendered":"<h2>Rewriting API Documentation with Markdown and ClojureScript<\/h2>\n<p><span style=\"font-weight: 400;\">We recently decided to explore rewriting the FullContact API documentation. One of the primary goals of this project was to see if we could accomplish this using our existing component library, which would allow us to incorporate any kind of functionality we want beyond the standard, static HTML documentation we have had in the past. An additional requirement of the project was that the documentation would be generated via markdown, so that changes wouldn\u2019t have to be made directly by the engineering team.<\/span><\/p>\n<p><b>The Foundation<\/b><\/p>\n<p><span style=\"font-weight: 400;\">The current front-end stack at FullContact relies heavily on ClojureScript, and our component library is written in <\/span><a href=\"https:\/\/github.com\/reagent-project\/reagent\"><span style=\"font-weight: 400;\">reagent<\/span><\/a><span style=\"font-weight: 400;\"> (ClojureScript interface to react), so this became the centerpiece of our project. We started looking around at options for converting markdown into something more familiar to the ClojureScript world. We found a <\/span><a href=\"https:\/\/github.com\/mpcarolin\/markdown-to-hiccup\"><span style=\"font-weight: 400;\">library that converts markdown into hiccup data structures<\/span><\/a><span style=\"font-weight: 400;\">, which is exactly what reagent uses.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Initially, we used this library to parse the markdown on the client and generate our reagent components, but we ran into a couple of issues. First, we use inline styles in our components that are generated from ClojureScript maps, but the library was leaving the styles in their string format. In order to have the styles from our markdown in a data structure that we could work within our components, we wrote the following code to add style maps to components:<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">(defn string-&gt;tokens [style]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0(-&gt;&gt; (clojure.string\/split style #\";\")<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(mapcat #(clojure.string\/split % #\":\"))<\/span>\r\n\r\n<span style=\"font-weight: 400;\"> \u00a0\u00a0\u00a0\u00a0\u00a0(map clojure.string\/trim)))\r\n<\/span>\r\n\r\n<span style=\"font-weight: 400;\">(defn tokens-&gt;map [tokens]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0(zipmap (keep-indexed #(if (even? %1) %2) tokens)<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(keep-indexed #(if (odd? %1) %2) tokens)))\r\n<\/span>\r\n\r\n<span style=\"font-weight: 400;\">(defn style-&gt;map [style]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0(tokens-&gt;map (string-&gt;tokens style)))\r\n<\/span>\r\n\r\n<span style=\"font-weight: 400;\">(defn convert-styles [i]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0(if (vector? i)<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0(let [[tag &amp; xs] i<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0fi (first xs)<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0new-fi (if (and (map? fi) (:style fi))<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(assoc fi :style (style-&gt;map (:style fi)))<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0fi)]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0(into [tag new-fi] (map convert-styles (rest xs))))<\/span>\r\n\r\n<span style=\"font-weight: 400;\"> \u00a0\u00a0i))<\/span><\/pre>\n<p><span style=\"font-weight: 400;\">This allowed us to merge custom styles into our component\u2019s default styles. Next, there were obvious speed issues with handling all of this on the client. The nice thing about the library we\u2019re using (and Clojure) is that it\u2019s written in <code><span style=\"color: red;\">.cljc<\/span><\/code> files, meaning the functions can be used in both ClojureScript and Clojure. As a result, we moved the generation of our hiccup from markdown into Clojure and added it as a step for building our code for deployment. While this sped things up significantly, there were still speed issues (more to come on this later).<\/span><\/p>\n<p><b>Making Use of Custom Componentry<\/b><\/p>\n<p><span style=\"font-weight: 400;\">At this point, we have successfully converted our markdown into reagent components with the ability to provide custom styling, but it\u2019s still limited to the basic markdown components and custom HTML. We want to make all of our custom components available for use. In exploring solutions for this, we were reminded of one of the fundamental (and amazing) concepts in Clojure &#8211; <\/span><i><span style=\"font-weight: 400;\">code is data, data is code.<\/span><\/i><span style=\"font-weight: 400;\"> Clojure is in the Lisp family of programming languages. Lisps are homoiconic, meaning all code written in these languages is encoded as data structures, and hiccup is no exception. Hiccup just uses vectors to denote elements and maps to represent an element\u2019s attributes. This makes it incredibly easy to modify via standard data transformation functions (since the code is just data). As a result, we were able to recursively loop over our markdown-converted hiccup and map custom elements to our known custom reagent component counterparts via the following simple function:<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">(defn hiccup-with-components [component-map comp]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0(if (vector? comp)<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0(let [[tag &amp; xs] comp<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0new-cmp (get component-map tag)]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0(into [(or new-cmp tag)] (map #(hiccup-with-components component-map %) xs)))<\/span>\r\n\r\n<span style=\"font-weight: 400;\"> \u00a0\u00a0comp))<\/span><\/pre>\n<p><span style=\"font-weight: 400;\">Where <code><span style=\"color: red;\">component-map<\/span><\/code> is just a map of custom element tag name (as a <\/span><a href=\"https:\/\/clojure.org\/reference\/data_structures#Keywords\"><span style=\"font-weight: 400;\">keyword<\/span><\/a><span style=\"font-weight: 400;\">) to reagent component definition, like:<\/span><\/p>\n<pre>\u00a0<span style=\"font-weight: 400;\">{:my-custom-cmp some.ns\/my-custom-cmp<\/span>\r\n\r\n<span style=\"font-weight: 400;\">...}<\/span><\/pre>\n<p><span style=\"font-weight: 400;\"><br \/>\n<\/span> <span style=\"font-weight: 400;\">and <code><span style=\"color: red;\">comp<\/span><\/code> is our markdown-converted hiccup. This means we can make the following transformation:<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">\/\/ markdown<\/span>\r\n<span style=\"font-weight: 400;\">&lt;my-custom-cmp data-title=\u201dTitle\u201d style=\u201dcolor:#545454\u201d&gt;&lt;\/my-custom-cmp&gt;<\/span><\/pre>\n<p><span style=\"font-weight: 400;\">into:<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">;; hiccup\r\n<\/span>\r\n<span style=\"font-weight: 400;\">[:my-custom-cmp {:data-title \u201cTitle\u201d :style {:color \u201c#545454\u201d}}]<\/span><\/pre>\n<p><span style=\"font-weight: 400;\">which gets mapped to something like:<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">;; reagent component<\/span>\r\n\r\n<span style=\"font-weight: 400;\">(defn my-custom-cmp [{:keys [data-title style]}]<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0[:div {:style\u00a0 \u00a0 (merge {:background-color \"#fff\"<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:color\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \"#000\"<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:display\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 :flex<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:align-items\u00a0 \u00a0 \u00a0 :center<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:justify-content\u00a0 :center<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:padding\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \"10px 20px\"}<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0style)<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0:on-click (fn [] ...)}<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0data-title])<\/span>\r\n\r\n<\/pre>\n<p><span style=\"font-weight: 400;\">Now all we have to do to allow a new component to be used in markdown is add it to our <code><span style=\"color: red;\">component-map<\/span><\/code> (components for generating an API key, creating an account, playing around with APIs, etc).<\/span><\/p>\n<p><b>Building a Visual Component Library<\/b><\/p>\n<p><span style=\"font-weight: 400;\">In order to provide visibility into available components to be used in our markdown files, we generated a visual component library via our <code><span style=\"color: red;\">component-map<\/span><\/code> that provides visuals for each component with default properties, as well as the code that can be used to generate that component in a markdown file. The components look like this:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-18884\" src=\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png\" alt=\"\" width=\"1598\" height=\"482\" srcset=\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png 1598w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM-300x90.png 300w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM-1024x309.png 1024w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM-768x232.png 768w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM-1536x463.png 1536w\" sizes=\"auto, (max-width: 1598px) 100vw, 1598px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">and clicking the <code><span style=\"color: red;\">&lt;&gt;<\/span><\/code> icon exposes the code to be copied and modified:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-18885\" src=\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.29-PM.png\" alt=\"\" width=\"1544\" height=\"378\" srcset=\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.29-PM.png 1544w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.29-PM-300x73.png 300w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.29-PM-1024x251.png 1024w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.29-PM-768x188.png 768w, https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.29-PM-1536x376.png 1536w\" sizes=\"auto, (max-width: 1544px) 100vw, 1544px\" \/><\/p>\n<p><b>Next Steps<\/b><\/p>\n<p><span style=\"font-weight: 400;\">At this point, we\u2019ve managed to build a framework for our API documentation that utilizes our existing component library, which means all of our components look and act the same across both our applications and our documentation. Additionally, it was built in such a way that it can be maintained by team members outside of engineering. This means that we have accomplished our initial set of goals, however, there\u2019s still plenty of room for enhancements.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">As mentioned before, one of the biggest areas needing improvement is speed. We currently load our hiccup via <\/span><a href=\"https:\/\/github.com\/edn-format\/edn\"><span style=\"font-weight: 400;\">Extensible Data Notation<\/span><\/a><span style=\"font-weight: 400;\"> (<code><span style=\"color: red;\">.edn<\/span><\/code>) files, but our end goal is to not have to load anything at all on the client. Therefore, we\u2019re seeing if we can make use of <\/span><a href=\"https:\/\/clojure.org\/reference\/macros\"><span style=\"font-weight: 400;\">Clojure macros<\/span><\/a><span style=\"font-weight: 400;\"> to generate all reagent components from markdown during code compilation (instead of having to load the hiccup and generate them on the client). This will speed our API documentation up quite a bit, and we look forward to seeing the results.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rewriting API Documentation with Markdown and ClojureScript We recently decided to explore rewriting the FullContact API documentation. One of the primary goals of this project was to see if we could accomplish this using our existing component library, which would allow us to incorporate any kind of functionality we want beyond the standard, static HTML [&hellip;]<\/p>\n","protected":false},"author":99,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_improvement_type_select":"improve_an_existing","_thumb_yes_seoaic":false,"_frame_yes_seoaic":false,"seoaic_generate_description":"","seoaic_improve_instructions_prompt":"","seoaic_rollback_content_improvement":"","seoaic_idea_thumbnail_generator":"","thumbnail_generated":false,"thumbnail_generate_prompt":"","seoaic_article_description":"","seoaic_article_subtitles":[],"footnotes":""},"categories":[656],"tags":[5839,5836,5837,281],"class_list":["post-18883","post","type-post","status-publish","format-standard","hentry","category-engineering","tag-markdown","tag-clojurescript","tag-reagent","tag-engineering"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.1 (Yoast SEO v27.1.1) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Code is Data, Data is Code | FullContact<\/title>\n<meta name=\"description\" content=\"Rewriting API Documentation with Markdown and ClojureScript We recently decided to explore rewriting the FullContact API documentation. One of the primary\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Code is Data, Data is Code: Rewriting API Documentation with Markdown and ClojureScript\" \/>\n<meta property=\"og:description\" content=\"Rewriting API Documentation with Markdown and ClojureScript We recently decided to explore rewriting the FullContact API documentation. One of the primary\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/\" \/>\n<meta property=\"og:site_name\" content=\"FullContact\" \/>\n<meta property=\"article:published_time\" content=\"2020-09-11T15:15:50+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-09-11T17:41:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Markdown-ClojureScript-blog-li.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Alex Porter\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Code is Data, Data is Code\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Markdown-ClojureScript-blog-tw.png\" \/>\n<meta name=\"twitter:creator\" content=\"@fullcontact\" \/>\n<meta name=\"twitter:site\" content=\"@fullcontact\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alex Porter\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/\"},\"author\":{\"name\":\"Alex Porter\",\"@id\":\"https:\/\/www.fullcontact.com\/#\/schema\/person\/8d40f3ed73ec64c3a912e947c6760184\"},\"headline\":\"Code is Data, Data is Code\",\"datePublished\":\"2020-09-11T15:15:50+00:00\",\"dateModified\":\"2020-09-11T17:41:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/\"},\"wordCount\":823,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.fullcontact.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png\",\"keywords\":[\"markdown\",\"ClojureScript\",\"reagent\",\"engineering\"],\"articleSection\":[\"Engineering\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/\",\"url\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/\",\"name\":\"Code is Data, Data is Code | FullContact\",\"isPartOf\":{\"@id\":\"https:\/\/www.fullcontact.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png\",\"datePublished\":\"2020-09-11T15:15:50+00:00\",\"dateModified\":\"2020-09-11T17:41:33+00:00\",\"description\":\"Rewriting API Documentation with Markdown and ClojureScript We recently decided to explore rewriting the FullContact API documentation. One of the primary\",\"breadcrumb\":{\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage\",\"url\":\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png\",\"contentUrl\":\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png\",\"width\":1598,\"height\":482},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.fullcontact.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Code is Data, Data is Code\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.fullcontact.com\/#website\",\"url\":\"https:\/\/www.fullcontact.com\/\",\"name\":\"FullContact\",\"description\":\"Relationships, reimagined.\",\"publisher\":{\"@id\":\"https:\/\/www.fullcontact.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.fullcontact.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.fullcontact.com\/#organization\",\"name\":\"FullContact\",\"url\":\"https:\/\/www.fullcontact.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.fullcontact.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2019\/11\/fc-logo@2x.png\",\"contentUrl\":\"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2019\/11\/fc-logo@2x.png\",\"width\":200,\"height\":38,\"caption\":\"FullContact\"},\"image\":{\"@id\":\"https:\/\/www.fullcontact.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/fullcontact\",\"https:\/\/www.linkedin.com\/company\/fullcontact-inc-\",\"https:\/\/www.youtube.com\/user\/FullContactAPI\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.fullcontact.com\/#\/schema\/person\/8d40f3ed73ec64c3a912e947c6760184\",\"name\":\"Alex Porter\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.fullcontact.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/7d835a7f9c40cf3b1f9dbd358802c687e08f6c70b82066eecaca40211a41b3f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/7d835a7f9c40cf3b1f9dbd358802c687e08f6c70b82066eecaca40211a41b3f4?s=96&d=mm&r=g\",\"caption\":\"Alex Porter\"},\"url\":\"https:\/\/www.fullcontact.com\/blog\/author\/alex-porterfullcontact-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Code is Data, Data is Code | FullContact","description":"Rewriting API Documentation with Markdown and ClojureScript We recently decided to explore rewriting the FullContact API documentation. One of the primary","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/","og_locale":"en_US","og_type":"article","og_title":"Code is Data, Data is Code: Rewriting API Documentation with Markdown and ClojureScript","og_description":"Rewriting API Documentation with Markdown and ClojureScript We recently decided to explore rewriting the FullContact API documentation. One of the primary","og_url":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/","og_site_name":"FullContact","article_published_time":"2020-09-11T15:15:50+00:00","article_modified_time":"2020-09-11T17:41:33+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Markdown-ClojureScript-blog-li.png","type":"image\/png"}],"author":"Alex Porter","twitter_card":"summary_large_image","twitter_title":"Code is Data, Data is Code","twitter_image":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Markdown-ClojureScript-blog-tw.png","twitter_creator":"@fullcontact","twitter_site":"@fullcontact","twitter_misc":{"Written by":"Alex Porter","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#article","isPartOf":{"@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/"},"author":{"name":"Alex Porter","@id":"https:\/\/www.fullcontact.com\/#\/schema\/person\/8d40f3ed73ec64c3a912e947c6760184"},"headline":"Code is Data, Data is Code","datePublished":"2020-09-11T15:15:50+00:00","dateModified":"2020-09-11T17:41:33+00:00","mainEntityOfPage":{"@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/"},"wordCount":823,"commentCount":0,"publisher":{"@id":"https:\/\/www.fullcontact.com\/#organization"},"image":{"@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage"},"thumbnailUrl":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png","keywords":["markdown","ClojureScript","reagent","engineering"],"articleSection":["Engineering"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/","url":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/","name":"Code is Data, Data is Code | FullContact","isPartOf":{"@id":"https:\/\/www.fullcontact.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage"},"image":{"@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage"},"thumbnailUrl":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png","datePublished":"2020-09-11T15:15:50+00:00","dateModified":"2020-09-11T17:41:33+00:00","description":"Rewriting API Documentation with Markdown and ClojureScript We recently decided to explore rewriting the FullContact API documentation. One of the primary","breadcrumb":{"@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#primaryimage","url":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png","contentUrl":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2020\/09\/Screen-Shot-2020-09-10-at-2.24.20-PM.png","width":1598,"height":482},{"@type":"BreadcrumbList","@id":"https:\/\/www.fullcontact.com\/blog\/engineering\/code-is-data-data-is-code\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.fullcontact.com\/"},{"@type":"ListItem","position":2,"name":"Code is Data, Data is Code"}]},{"@type":"WebSite","@id":"https:\/\/www.fullcontact.com\/#website","url":"https:\/\/www.fullcontact.com\/","name":"FullContact","description":"Relationships, reimagined.","publisher":{"@id":"https:\/\/www.fullcontact.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.fullcontact.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.fullcontact.com\/#organization","name":"FullContact","url":"https:\/\/www.fullcontact.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.fullcontact.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2019\/11\/fc-logo@2x.png","contentUrl":"https:\/\/www.fullcontact.com\/wp-content\/uploads\/2019\/11\/fc-logo@2x.png","width":200,"height":38,"caption":"FullContact"},"image":{"@id":"https:\/\/www.fullcontact.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/fullcontact","https:\/\/www.linkedin.com\/company\/fullcontact-inc-","https:\/\/www.youtube.com\/user\/FullContactAPI"]},{"@type":"Person","@id":"https:\/\/www.fullcontact.com\/#\/schema\/person\/8d40f3ed73ec64c3a912e947c6760184","name":"Alex Porter","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.fullcontact.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/7d835a7f9c40cf3b1f9dbd358802c687e08f6c70b82066eecaca40211a41b3f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7d835a7f9c40cf3b1f9dbd358802c687e08f6c70b82066eecaca40211a41b3f4?s=96&d=mm&r=g","caption":"Alex Porter"},"url":"https:\/\/www.fullcontact.com\/blog\/author\/alex-porterfullcontact-com\/"}]}},"_links":{"self":[{"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/posts\/18883","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/users\/99"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/comments?post=18883"}],"version-history":[{"count":0,"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/posts\/18883\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/media?parent=18883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/categories?post=18883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fullcontact.com\/wp-json\/wp\/v2\/tags?post=18883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}