{"id":3657160,"date":"2023-10-23T08:00:46","date_gmt":"2023-10-23T12:00:46","guid":{"rendered":"https:\/\/spin.atomicobject.com\/?p=3657160"},"modified":"2023-10-20T15:04:44","modified_gmt":"2023-10-20T19:04:44","slug":"migrate-graph-database","status":"publish","type":"post","link":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/","title":{"rendered":"Translate a Graph Database Schema to a Prisma Schema"},"content":{"rendered":"<p>When working on software projects, we have many options for a database structure. Although relational databases remain the standard choice, the graph database structure has been gaining steam. This is partly due to its flexible schema definition, which gives it an advantage in representing deep relationships with its node\/edge structure. Graph databases also provide the querying power to produce real-time recommendations based on the connections between users and products or other content.<\/p>\n<h2>Our Project<\/h2>\n<p>On a recent project, we chose to migrate data from an <a href=\"https:\/\/aws.amazon.com\/neptune\/\">Amazon Neptune<\/a> graph database to an <a href=\"https:\/\/aws.amazon.com\/rds\/postgresql\/\">Amazon RDS PostgreSQL<\/a> relational database. We valued the flexibility of the graph database and the ability to build our own recommendation engine on top of it. However, we no longer wanted this database as the source of truth for the project. Migrating to <a href=\"https:\/\/www.postgresql.org\/\">Postgres<\/a> was a natural choice. This is because relational databases strongly support the enforcement of data consistency, integrity, and transaction management, making them suitable for applications where data accuracy and reliability are crucial.<\/p>\n<p>In this project, we used <a href=\"https:\/\/www.prisma.io\/\">Prisma ORM<\/a> to work with our Postgres database. To migrate data from Amazon Neptune to PostgreSQL, my job was to translate our schema from a graph database to a relational database. Though I found many resources online about translation from a relational database to a graph structure, a discussion of the opposite translation was practically nonexistent. So here it is! I will outline an example of translating from a node\/edge schema to a Prisma schema representing a relational database.<\/p>\n<h2>A Hypothetical Example<\/h2>\n<p>For our example, let\u2019s consider a model for a streaming service where users buy and view episodes of television shows. They can also follow shows to receive notifications when new episodes are released. Users, episodes, and shows are represented as nodes in the graph. Meanwhile, purchases, views, follow events, and episode\/show relationships are represented as edges.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3657161\" src=\"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/Screenshot-2023-09-21-at-3.46.13-PM-590x628.png\" alt=\"\" width=\"322\" height=\"343\" srcset=\"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/Screenshot-2023-09-21-at-3.46.13-PM-590x628.png 590w, https:\/\/spin.atomicobject.com\/wp-content\/uploads\/Screenshot-2023-09-21-at-3.46.13-PM-141x150.png 141w, https:\/\/spin.atomicobject.com\/wp-content\/uploads\/Screenshot-2023-09-21-at-3.46.13-PM-600x638.png 600w, https:\/\/spin.atomicobject.com\/wp-content\/uploads\/Screenshot-2023-09-21-at-3.46.13-PM.png 628w\" sizes=\"auto, (max-width: 322px) 100vw, 322px\" \/><\/p>\n<p>Imagine the nodes and edges have the following properties:<\/p>\n<p>User<br \/>\n&#8211; ID<br \/>\n&#8211; username<br \/>\n&#8211; email<\/p>\n<p>Show<br \/>\n&#8211; ID<br \/>\n&#8211; name<br \/>\n&#8211; description<br \/>\n&#8211; genre<\/p>\n<p>Episode<br \/>\n&#8211; ID<br \/>\n&#8211; title<br \/>\n&#8211; description<br \/>\n&#8211; premiere date<br \/>\n&#8211; price<\/p>\n<p>Views<br \/>\n&#8211; status<br \/>\n&#8211; start date<br \/>\n&#8211; completed date<\/p>\n<p>Owns<br \/>\n&#8211; purchase date<br \/>\n&#8211; transaction ID<\/p>\n<p>Follows (no properties)<\/p>\n<p>Belongs to (no properties)<\/p>\n<p>We&#8217;ll map this graph schema to a Prisma schema. But, let\u2019s first discuss how Prisma models data. Prisma typically describes the database structure with models defined in a Prisma schema file, using Prisma&#8217;s DSL (Domain Specific Language). These models describe tables in the database with their respective fields and relationships. My initial considerations when translating a similar graph schema to Prisma were the following.<\/p>\n<p>1) What tables should exist in our relational database?<br \/>\n2) What relationships must exist between these tables?<\/p>\n<h3>Step 1<\/h3>\n<p>To start, we will need a table for each node type in the graph, and for edges, we will need to create relations. Relations in Prisma are one-to-one, one-to-many, and many-to-many. Taking the nodes and edges defined above, we can begin to map to Prisma models. For Users, it will be important to preserve the user properties as well as the \u201clikes\u201d, \u201cowns\u201d and \u201cviews\u201d edges. Here is what I came up with.<\/p>\n<pre><code class=\"language-ts\">model User {\n    id                String @id @default(uuid())\n    username          String?\n    email             String\n    purchases         Purchase[]\n    views             View[]\n    followedEpisodes  Follow[]\n}<\/code><\/pre>\n<p>The ID, username, and email properties are represented as fields on the User model. This is quite straightforward. But, it&#8217;s a bit more complicated to define the edge relationships. For \u201cowns,\u201d \u201cviews,\u201d and \u201cfollows\u201d edges, we need to create one-to-many relationships. This is because a user can interact with multiple episodes, and episodes can have interactions with multiple users. To represent \u201cowns,\u201d \u201cviews,\u201d and \u201cfollows\u201d edges, we want to create many-to-many relationships, using relation tables we&#8217;ll define below.<\/p>\n<h3>Step 2<\/h3>\n<p>Next, we create similar models of the other node types.<\/p>\n<pre><code class=\"language-ts\">model Show {\n    id            String @id @default(uuid())\n    name          String\n    description   String\n    genre         Genre\n    episodes      Episodes[]\n    follows       Follows[]\n}<\/code><\/pre>\n<pre><code class=\"language-ts\">model Episode {\n    id            String @id @default(uuid())\n    title         String\n    description   String\n    premiereDate  DateTime\n    price         Int\n    show          Show @relation(fields: [showId], references: [id])\n    showId        String\n    purchases     Purchase[]\n    views         View[]\n}<\/code><\/pre>\n<p>For the Show and Episode model, we maintain the \u201cbelongsTo\u201d relationship with a one-to-many relation where one show can have multiple episodes. We represent this in the Prisma schema with a relation attribute (noted as @relation on the Show model). In turn, this attribute references a scalar field called showId (the foreign key that connects Episode and Show in the database), along with a corresponding relation field on the Show model called Episodes.<\/p>\n<h3>Step 3<\/h3>\n<p>Finally, we create the relation tables (a.k.a. JOIN, link, or pivot tables) to maintain the many-to-many relations. These tables each have two relation fields (noted with the @relation attribute) and scalar fields for the corresponding IDs referenced by the relation fields.<\/p>\n<pre><code class=\"language-ts\">model View {\n    startDate.     DateTime\n    completedDate  DateTime\n    episode        Episode @relation(fields: [episodeId], references: [id])\n    episodeId      String\n    user           User @relation(fields: [userId], references: [id])\n    userId         String\n\n    @@id([episodeId, userId])\n}<\/code><\/pre>\n<pre><code class=\"language-ts\">model Purchase {\n    transactionID  String\n    purchaseDate   DateTime\n    episode        Episode @relation(fields: [episodeId], references: [id])\n    episodeId      String\n    user           User @relation(fields: [userId], references: [id])\n    userId         String\n\n    @@id([episodeId, userId])\n}<\/code><\/pre>\n<pre><code class=\"language-ts\">model Follow {\n    show      Show @relation(fields: [showId], references: [id])\n    showId    String\n    user      User @relation(fields: [userId], references: [id])\n    userId    String\n\n    @@id([showId, userId])\n}<\/code><\/pre>\n<p>Now we have our complete Prisma schema! With this schema, we&#8217;ll preserve all data from the graph database when we migrate to the new relational database.<\/p>\n<h2>Graph Database to Relational Database<\/h2>\n<p>I hope this exercise helped put you in the right head space if you&#8217;re trying to translate a graph structure into a relational database structure. If so, I\u2019d love to hear more about your experience in the comments!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When working on software projects, we have many options for a database structure. Although relational databases remain the standard choice, the graph database structure has been gaining steam. This is partly due to its flexible schema definition, which gives it an advantage in representing deep relationships with its node\/edge structure. Graph databases also provide the [&hellip;]<\/p>\n","protected":false},"author":604,"featured_media":3657701,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[23354],"tags":[1188,22894,23351,23427],"series":[],"class_list":["post-3657160","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-prisma-platforms-languages","tag-database","tag-graph","tag-database-migration","tag-schema"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Translate a Graph Database Schema to a Prisma Schema<\/title>\n<meta name=\"description\" content=\"On a recent project, we chose to migrate data from an existing Amazon Neptune graph database to an Amazon RDS PostgreSQL relational database.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/spin.atomicobject.com\/migrate-graph-database\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Translate a Graph Database Schema to a Prisma Schema\" \/>\n<meta property=\"og:description\" content=\"On a recent project, we chose to migrate data from an existing Amazon Neptune graph database to an Amazon RDS PostgreSQL relational database.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/spin.atomicobject.com\/migrate-graph-database\/\" \/>\n<meta property=\"og:site_name\" content=\"Atomic Spin\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/atomicobject\" \/>\n<meta property=\"article:published_time\" content=\"2023-10-23T12:00:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/JDP-AO2023-91-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1707\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Kendra Haan\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@atomicobject\" \/>\n<meta name=\"twitter:site\" content=\"@atomicobject\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kendra Haan\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/\"},\"author\":{\"name\":\"Kendra Haan\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/person\\\/d370b9897287fd937dfe3533ac659adc\"},\"headline\":\"Translate a Graph Database Schema to a Prisma Schema\",\"datePublished\":\"2023-10-23T12:00:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/\"},\"wordCount\":819,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/atomicobject.com\\\/\"},\"image\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/JDP-AO2023-91-scaled.jpg\",\"keywords\":[\"database\",\"graph\",\"database migration\",\"schema\"],\"articleSection\":[\"Prisma\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/\",\"name\":\"Translate a Graph Database Schema to a Prisma Schema\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/JDP-AO2023-91-scaled.jpg\",\"datePublished\":\"2023-10-23T12:00:46+00:00\",\"description\":\"On a recent project, we chose to migrate data from an existing Amazon Neptune graph database to an Amazon RDS PostgreSQL relational database.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/migrate-graph-database\\\/#primaryimage\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/JDP-AO2023-91-scaled.jpg\",\"contentUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/JDP-AO2023-91-scaled.jpg\",\"width\":2560,\"height\":1707,\"caption\":\"Translate a Graph Database Schema to a Prisma Schema\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#website\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/\",\"name\":\"Atomic Spin\",\"description\":\"Atomic Object\u2019s blog on everything we find fascinating.\",\"publisher\":{\"@id\":\"https:\\\/\\\/atomicobject.com\\\/\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/spin.atomicobject.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#organization\",\"name\":\"Atomic Object\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/AO-Logo-Emblem-Color.png\",\"contentUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/AO-Logo-Emblem-Color.png\",\"width\":258,\"height\":244,\"caption\":\"Atomic Object\"},\"image\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/atomicobject\",\"https:\\\/\\\/x.com\\\/atomicobject\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/person\\\/d370b9897287fd937dfe3533ac659adc\",\"name\":\"Kendra Haan\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1d2c7bc740320bb5a04dc29954434345a990463458d248ee60c5c441a8b2fdb3?s=96&d=blank&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1d2c7bc740320bb5a04dc29954434345a990463458d248ee60c5c441a8b2fdb3?s=96&d=blank&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1d2c7bc740320bb5a04dc29954434345a990463458d248ee60c5c441a8b2fdb3?s=96&d=blank&r=pg\",\"caption\":\"Kendra Haan\"},\"description\":\"Software Consultant and Developer, Grand Rapids Accelerator, crafter of kombucha and beer.\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/author\\\/kendra-haan\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Translate a Graph Database Schema to a Prisma Schema","description":"On a recent project, we chose to migrate data from an existing Amazon Neptune graph database to an Amazon RDS PostgreSQL relational database.","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:\/\/spin.atomicobject.com\/migrate-graph-database\/","og_locale":"en_US","og_type":"article","og_title":"Translate a Graph Database Schema to a Prisma Schema","og_description":"On a recent project, we chose to migrate data from an existing Amazon Neptune graph database to an Amazon RDS PostgreSQL relational database.","og_url":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/","og_site_name":"Atomic Spin","article_publisher":"https:\/\/www.facebook.com\/atomicobject","article_published_time":"2023-10-23T12:00:46+00:00","og_image":[{"width":2560,"height":1707,"url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/JDP-AO2023-91-scaled.jpg","type":"image\/jpeg"}],"author":"Kendra Haan","twitter_card":"summary_large_image","twitter_creator":"@atomicobject","twitter_site":"@atomicobject","twitter_misc":{"Written by":"Kendra Haan","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/#article","isPartOf":{"@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/"},"author":{"name":"Kendra Haan","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/person\/d370b9897287fd937dfe3533ac659adc"},"headline":"Translate a Graph Database Schema to a Prisma Schema","datePublished":"2023-10-23T12:00:46+00:00","mainEntityOfPage":{"@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/"},"wordCount":819,"commentCount":0,"publisher":{"@id":"https:\/\/atomicobject.com\/"},"image":{"@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/#primaryimage"},"thumbnailUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/JDP-AO2023-91-scaled.jpg","keywords":["database","graph","database migration","schema"],"articleSection":["Prisma"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/spin.atomicobject.com\/migrate-graph-database\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/","url":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/","name":"Translate a Graph Database Schema to a Prisma Schema","isPartOf":{"@id":"https:\/\/spin.atomicobject.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/#primaryimage"},"image":{"@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/#primaryimage"},"thumbnailUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/JDP-AO2023-91-scaled.jpg","datePublished":"2023-10-23T12:00:46+00:00","description":"On a recent project, we chose to migrate data from an existing Amazon Neptune graph database to an Amazon RDS PostgreSQL relational database.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/spin.atomicobject.com\/migrate-graph-database\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/spin.atomicobject.com\/migrate-graph-database\/#primaryimage","url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/JDP-AO2023-91-scaled.jpg","contentUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/JDP-AO2023-91-scaled.jpg","width":2560,"height":1707,"caption":"Translate a Graph Database Schema to a Prisma Schema"},{"@type":"WebSite","@id":"https:\/\/spin.atomicobject.com\/#website","url":"https:\/\/spin.atomicobject.com\/","name":"Atomic Spin","description":"Atomic Object\u2019s blog on everything we find fascinating.","publisher":{"@id":"https:\/\/atomicobject.com\/"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/spin.atomicobject.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/spin.atomicobject.com\/#organization","name":"Atomic Object","url":"https:\/\/spin.atomicobject.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/logo\/image\/","url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/AO-Logo-Emblem-Color.png","contentUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/AO-Logo-Emblem-Color.png","width":258,"height":244,"caption":"Atomic Object"},"image":{"@id":"https:\/\/spin.atomicobject.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/atomicobject","https:\/\/x.com\/atomicobject"]},{"@type":"Person","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/person\/d370b9897287fd937dfe3533ac659adc","name":"Kendra Haan","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/1d2c7bc740320bb5a04dc29954434345a990463458d248ee60c5c441a8b2fdb3?s=96&d=blank&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/1d2c7bc740320bb5a04dc29954434345a990463458d248ee60c5c441a8b2fdb3?s=96&d=blank&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1d2c7bc740320bb5a04dc29954434345a990463458d248ee60c5c441a8b2fdb3?s=96&d=blank&r=pg","caption":"Kendra Haan"},"description":"Software Consultant and Developer, Grand Rapids Accelerator, crafter of kombucha and beer.","url":"https:\/\/spin.atomicobject.com\/author\/kendra-haan\/"}]}},"_links":{"self":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts\/3657160","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/users\/604"}],"replies":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/comments?post=3657160"}],"version-history":[{"count":0,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts\/3657160\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/media\/3657701"}],"wp:attachment":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/media?parent=3657160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/categories?post=3657160"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/tags?post=3657160"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/series?post=3657160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}