{"id":16012,"date":"2018-09-11T11:52:27","date_gmt":"2018-09-11T10:52:27","guid":{"rendered":"https:\/\/marvel7077.wpengine.com\/?p=16012"},"modified":"2020-11-12T12:23:44","modified_gmt":"2020-11-12T12:23:44","slug":"why-marvel-uses-graphql","status":"publish","type":"post","link":"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/","title":{"rendered":"Why we used GraphQL for our API"},"content":{"rendered":"<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Recently at Marvel we launched our <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/marvelapp.com\/developers\/\">Platform API<\/a>. We wanted to harness the power of integrations and place it directly into the hands of the creative community of people that use Marvel every day, so that we can work more seamlessly -work- with the other tools that serve them on a daily basis.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Here I'll write about some of the thought processes we went through when we set out to build it, explain some of the problems with other APIs and their potential solutions, and cover why we made the choice to use GraphQL over REST despite the team being vastly less experienced with GraphQL.<\/p>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">What makes a good API?<\/h2>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">If we were ever to make a great API of our own, we would need to think about what makes a great API in the first place, so we identified some good practices for designing any API, whether that\u2019s on the web or not<\/p>\n<ul class=\"pageWrap pageWrap--s list list--unordered marginBottom-l lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">\n<li><strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Great documentation.<\/strong> Even the most life-changing tools are useless to me if I can\u2019t figure out how to get them to work.<\/li>\n<li><strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">No needless complexity.<\/strong> Needless complexity is for bureaucrats. We should prefer simplicity always.<\/li>\n<li><strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">A lack of surprises.<\/strong> Getting caught out because something works in ways you didn\u2019t expect, or because it has an unexpected side-effect is no fun. Things should be as straightforward as they can be.<\/li>\n<\/ul>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">We can think of achieving these points as ways of nailing the developer experience. This should make sense to us - when we design our app and web interfaces we try to keep the user\u2019s experience front of mind; an API is a user interface with a specific developer audience, and it requires we do the same.<\/p>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">Where are other APIs lacking?<\/h2>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">No standardisation<\/h3>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Most web APIs of the last 5+ years have been REST(ish) and talking json, rather than the slightly older fashioned SOAP, RPC or custom XML endpoints. Generally this is seen to be a good thing, and we\u2019ve seen a proliferation of APIs as devices become smart and services have begun to work tightly together.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">The problem is that whilst json has become the standard way to send data between web APIs, each API is unique in its structure and its capabilities, and there has been no standard way of describing itself. When every API is different to the last it isn't possible to build tooling that works for them all.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">So whilst the API you\u2019re using today may be perfectly well supported with good documentation and even some handy tools like editor integrations or client libraries, those tools you\u2019re used to probably won\u2019t work on the API you\u2019re working with the next week, or will be too generic to help you with the unique parts of it if they do. In reality it usually means you don\u2019t have any tooling at all.<\/p>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">Mobile networks & devices<\/h3>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Another problem has emerged as more and more web traffic has transitioned to mobile devices, which are often on unreliable networks with high-latency and low bandwidth.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">A REST API will commonly require the client to hit multiple endpoints to gather data for the many resources need to render a certain view (say, fetching the user\u2019s profile as well as their favourite recipes in two separate calls).<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Because mobile networks are so much more unreliable than other networks, the chances of failure are much higher when multiple requests must be made. This makes it much more likely that you\u2019ll end up with partial data, which leaves you unable to render or having to render placeholders whilst you retry the request.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">As bad as that is, latency is the big performance killer when working with the network. Latency is the time it takes for data to be transferred between two devices - such as your phone and Marvel's servers. When the latency between a device and the server is 50ms, it means it takes 50ms for data to be sent between the device and the server, and the RTT (round trip time) would be 100ms. 100ms doesn\u2019t sound like a lot, but you have to consider that it takes much more than 1 round trip to send a single HTTP request. There\u2019s DNS lookups, TLS encryption handshake, as well as the three-way TCP handshake required before you can actually send or receive any data, all of which require one or more round trips. The TCP protocol we use to move bits around on the web also requires constant acknowledgement of received data so that any lost packets can be retransmitted. Sadly these acknowledgements obey the laws of physics and so they incur the cost of the round trip too, which puts a cap on the network throughout which is directly tied to network latency.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">On a high latency network, it might take up to a second or more for a packet to make a round trip. Network latency is largely out of our control as application developers, so we need to instead try to reduce its impact by reducing the number of requests we make.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Another issue disproportionately impacting mobile devices is over fetching. An endpoint will generally return a full representation of a resource, but chances are the client doesn\u2019t necessarily need or want all of that data, most of the time they\u2019re interested in a subset. Nonetheless, the server will still send this extraneous data and the client has no say in the matter.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">When fetching data from an API endpoint, chances are the client doesn\u2019t want or need all of the data that it returns, yet it still has to pay the cost of transferring and processing it which is a waste of bandwidth and CPU cycles, causing longer response times for no benefit.<\/p>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">What solutions exist for these issues?<\/h2>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">There are a few open source projects attempting to solve some of these issues for REST APIs. Namely, <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/marvelapp.com\/developers\/\">swagger<\/a> (OpenAPI) and <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/apiblueprint.org\/\">API Blueprint<\/a>. We already had a little in house experience with swagger (and not a particularly happy one, yaml can be hell) and tried out API Blueprint when adding new endpoints to our existing API, but found that small errors in the <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/github.com\/apiaryio\/mson\">MSON<\/a> documents could be difficult to track down (not much better than yaml then).<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">The promise of these tools is good though, and there\u2019s one thing they get right: they force you to define a schema for your API. A schema acts as documentation for your system\u2019s boundaries, and system boundaries are often where integration pain is going to be felt most. Once you\u2019ve got a schema, you can use it to do all sorts of cool stuff: generate documentation pages, spin up mock servers for development, even generating code for API clients if you are so inclined. Also, because the schema is specified in a standardised way, tooling built for one API is portable between any API using the same standard. Importantly, because everything is defined up front, consumers of your API know exactly what is expected of them and what they can expect from you in return.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">This is something that GraphQL gets right too. The GraphQL server defines a schema containing all the data types, mutations and queries available to the clients. This way everybody knows where they stand. I can immediately see exactly which operations are available to me, which types they accept as inputs and which types they return as an output.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Whilst swagger and API Blueprint bring a schema to the request and response bodies, there\u2019s nothing they can do for the over-fetching and multiple request problems. If you were to solve those issues in your API, it would be something custom and non-standardised, unique to an individual API. Typically you\u2019d end up writing an endpoint for a specific view. For the example mentioned earlier, this means you\u2019d have an endpoint that returns the user and their recipes all at once. That\u2019s for a single view though, how many unique views are in your application? This could get messy.<\/p>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">So why GraphQL?<\/h2>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Unlike REST, one of the core ideas of GraphQL is related to solving these issues. Every call returns only the data that is specified in the request. This has a few benefits. Firstly it completely solves the over-fetching problem by putting it entirely in the client\u2019s hands. Secondly, it removes the need for multiple requests by allowing the client to ask for everything they need all at once. The third advantage of this approach is that it allows us as the operators of the API to see exactly who is requesting each field, something which makes it a lot easier for us to deprecate fields as time moves on. We\u2019re now able to mark a field as deprecated, which lets new integrators know not to use it, and then grab a list of all the existing integrations and get in touch with them to offer an upgrade path.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">As I alluded to earlier, tooling was also a factor in our decision. All the solutions discussed above have some similar tooling available and relatively healthy communities around them, but GraphQL seems to go above and beyond the other two. Coming out of Facebook, GraphQL has mostly been adopted within the react community, which is very large and very active. This means there\u2019s loads of great tools available to make the developer experience as good as it can be.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">For example, it\u2019s possible to hook up your editor to your schema and have it lint your queries, flagging any errors before you get a chance to execute them. Integrate it with autocomplete and you can have it make suggestions as you type.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\"><a class=\"link link--blue fontWeight-4\"href=\"https:\/\/marvel7077.wpengine.com\/wp-content\/uploads\/2018\/09\/example.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/marvel7077.wpengine.com\/wp-content\/uploads\/2018\/09\/example.png\" alt=\"\" width=\"1298\" height=\"876\" class=\"alignnone size-full wp-image-16015\" srcset=\"https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/example.png 1298w, https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/example-600x405.png 600w, https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/example-768x518.png 768w\" sizes=\"auto, (max-width: 1298px) 100vw, 1298px\" \/><\/a><\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">One of my favourite tools is GraphiQL, which is an IDE built for GraphQL APIs that runs in a browser. As you can see below, GraphiQL gives you somewhere to write your queries (with features you\u2019d expect like syntax highlighting and autocompletion), somewhere to see the results, and somewhere to reference the documentation.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\"><a class=\"link link--blue fontWeight-4\"href=\"https:\/\/marvel7077.wpengine.com\/wp-content\/uploads\/2018\/09\/Image.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/marvel7077.wpengine.com\/wp-content\/uploads\/2018\/09\/Image.png\" alt=\"\" width=\"2560\" height=\"1216\" class=\"alignnone size-full wp-image-16016\" srcset=\"https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/Image.png 2560w, https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/Image-600x285.png 600w, https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/Image-768x365.png 768w, https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/Image-1500x713.png 1500w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">It being browser based means we can throw it up somewhere public (<a class=\"link link--blue fontWeight-4\"href=\"https:\/\/marvelapp.com\/developers\/documentation\/getting-started\/#exploring-the-api\">as Marvel does<\/a>) and allow somebody to get hands on experience with our API in a developer friendly environment immediately. It turns out to be a really effective way of getting to grips with GraphQl itself as well as the specifics of an API, and really helps people to hit the ground running. <\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Alongside the other benefits it brings, this is the primary reason we chose to use GraphQl. It simply allows us to provide a better developer experience than any of the alternatives.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently at Marvel we launched our Platform API. We wanted to harness the power of integrations and place it directly into the hands of the creative community of people that use Marvel every day, so that we can work more seamlessly -work- with the other tools that serve them on a daily basis. Here I&#8217;ll write about some of the&#8230; <a class=\"link link--blue fontWeight-4\" href=\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/\">Read More &#65515;<\/a><\/p>\n","protected":false},"author":249,"featured_media":16017,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[453],"tags":[],"class_list":["post-16012","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-integrations-api"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v15.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<meta name=\"description\" content=\"I&#039;ll cover our thought process behind build the Marvel API, explain some problems with other APIs, and why we made the choice to use GraphQl over REST\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Why we used GraphQL for our API | Marvel Blog\" \/>\n<meta property=\"og:description\" content=\"I&#039;ll cover our thought process behind build the Marvel API, explain some problems with other APIs, and why we made the choice to use GraphQl over REST\" \/>\n<meta property=\"og:url\" content=\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/\" \/>\n<meta property=\"og:site_name\" content=\"Marvel Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/marvelapp\" \/>\n<meta property=\"article:published_time\" content=\"2018-09-11T10:52:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-11-12T12:23:44+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/Thumbnail_01@2x.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"898\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@marvelapp\" \/>\n<meta name=\"twitter:site\" content=\"@marvelapp\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\">\n\t<meta name=\"twitter:data1\" content=\"7 minutes\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#organization\",\"name\":\"Marvel\",\"url\":\"https:\/\/marvelapp.com\/blog\/\",\"sameAs\":[\"https:\/\/www.facebook.com\/marvelapp\",\"https:\/\/www.instagram.com\/marvelapp\/\",\"https:\/\/www.linkedin.com\/company\/marvel-app\/\",\"https:\/\/twitter.com\/marvelapp\"],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#logo\",\"inLanguage\":\"en-GB\",\"url\":\"https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/06\/Logo-Light.png\",\"width\":1605,\"height\":1130,\"caption\":\"Marvel\"},\"image\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#website\",\"url\":\"https:\/\/marvelapp.com\/blog\/\",\"name\":\"Marvel Blog\",\"description\":\"Ideas and words on user experience, design, collaboration and more\",\"publisher\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/marvelapp.com\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-GB\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#primaryimage\",\"inLanguage\":\"en-GB\",\"url\":\"https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/09\/Thumbnail_01@2x.png\",\"width\":\"1200\",\"height\":\"898\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#webpage\",\"url\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/\",\"name\":\"Why we used GraphQL for our API | Marvel Blog\",\"isPartOf\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#primaryimage\"},\"datePublished\":\"2018-09-11T10:52:27+00:00\",\"dateModified\":\"2020-11-12T12:23:44+00:00\",\"description\":\"I'll cover our thought process behind build the Marvel API, explain some problems with other APIs, and why we made the choice to use GraphQl over REST\",\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/\"]}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#webpage\"},\"author\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#\/schema\/person\/19d00648fa90fc5fcf23b5134721985f\"},\"headline\":\"Why we used GraphQL for our API\",\"datePublished\":\"2018-09-11T10:52:27+00:00\",\"dateModified\":\"2020-11-12T12:23:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#webpage\"},\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#primaryimage\"},\"articleSection\":\"Integrations &amp; API\",\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/marvelapp.com\/blog\/why-marvel-uses-graphql\/#respond\"]}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#\/schema\/person\/19d00648fa90fc5fcf23b5134721985f\",\"name\":\"Joe Alcorn\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#personlogo\",\"inLanguage\":\"en-GB\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/46fcfb87bad7e000e72340f12081ae695964bd5f21f2ece1e9b868bda6e6e18e?s=96&d=mm&r=g\",\"caption\":\"Joe Alcorn\"},\"description\":\"Developer @ Marvel\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","_links":{"self":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/posts\/16012","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/users\/249"}],"replies":[{"embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/comments?post=16012"}],"version-history":[{"count":0,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/posts\/16012\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/media\/16017"}],"wp:attachment":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/media?parent=16012"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/categories?post=16012"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/tags?post=16012"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}