{"id":25070,"date":"2020-02-26T12:15:42","date_gmt":"2020-02-26T10:15:42","guid":{"rendered":"http:\/\/www.webcodegeeks.com\/?p=25070"},"modified":"2020-02-26T10:30:24","modified_gmt":"2020-02-26T08:30:24","slug":"microprofile-graphql-introduction","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/","title":{"rendered":"MicroProfile GraphQL introduction"},"content":{"rendered":"\n<p><a href=\"https:\/\/github.com\/eclipse\/microprofile-graphql\">MicroProfile GraphQL<\/a>&nbsp;has just released it\u2019s first version (1.0). In this blog post we will explore some of the functionalities available in this release.<\/p>\n\n\n\n<p>We will reference an example application, where we use&nbsp;<a href=\"https:\/\/thorntail.io\/\">Thorntail<\/a>&nbsp;as a runtime, manually adding the&nbsp;<a href=\"https:\/\/github.com\/smallrye\/smallrye-graphql\">SmallRye GraphQL Implementation<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-is-graphql\">What is GraphQL?<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u201cGraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. GraphQL interprets strings from the client, and returns data in an understandable, predictable, pre-defined manner. GraphQL is an alternative, though not necessarily a replacement for REST.\u201d<\/p><\/blockquote>\n\n\n\n<p>Read the full&nbsp;<a href=\"http:\/\/spec.graphql.org\/draft\/\">GraphQL Specification<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-is-microprofile-graphql\">What is MicroProfile GraphQL?<\/h2>\n\n\n\n<p>\u201cThe intent of the MicroProfile GraphQL specification is to provide a \u201ccode-first\u201d set of APIs that will enable users to quickly develop portable GraphQL-based applications in Java. There are 2 main requirements for all implementations of this specification, namely:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Generate and make the GraphQL Schema available. This is done by looking at the annotations in the users code, and must include all GraphQL Queries and Mutations as well as all entities as defined implicitly via the response type or argument(s) of Queries and Mutations.<\/li><li>Execute GraphQL requests. This will be in the form of either a Query or a Mutation. As a minimum the specification must support executing these requests via HTTP.\u201d<\/li><\/ul>\n\n\n\n<p>Read the full&nbsp;<a href=\"https:\/\/download.eclipse.org\/microprofile\/microprofile-graphql-1.0\/microprofile-graphql.html\">MicroProfile GraphQL Specification<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-example\">The Example<\/h2>\n\n\n\n<p>We will reference an example throughout this post where we have a system that score people based on some activities they do.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>How fit they are, example how often they go to the gym<\/li><li>How safe they drive, not exceeding the speed limit etc.<\/li><li>How many steps they give a day, etc.<\/li><\/ul>\n\n\n\n<p>We have a Person object that contains all the details about the person (name, surname, address, phone, social media etc.) and we have a score object that contains the score for a certain action.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"query-data\">Query data<\/h2>\n\n\n\n<p>In GraphQL,&nbsp;<code>Query<\/code>&nbsp;is similar to REST\u2019s&nbsp;<code>GET<\/code>. A Query does not change data, it only receives data. The difference is that with GraphQL you can actually ask what you want.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"using-jax-rs\">Using JAX-RS<\/h3>\n\n\n\n<p>Let\u2019s say you want some information about a person, in JAX-RS we would create something like this:<\/p>\n\n\n\n<pre class=\"brush:java\">@Path(\"\/person\")\n@Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)\n@Tag(name = \"Person service\",description = \"Person Services\")\npublic class PersonRestApi {\n\n    @Inject \n    private PersonDB personDB;\n\n    @GET \n    @Path(\"\/{id}\")\n    @Operation(description = \"Get a person using the person's Id\")\n    public Response getPerson(@PathParam(\"id\") int id){\n        return Response.ok(personDB.getPerson(id)).build();\n    }\n}\n<\/pre>\n\n\n\n<p>NOTE: To document the endpoint, you also need&nbsp;<a href=\"https:\/\/github.com\/eclipse\/microprofile-open-api\">MicroProfile OpenAPI<\/a>&nbsp;(<code>@Tag<\/code>&nbsp;and&nbsp;<code>@Operation<\/code>).<\/p>\n\n\n\n<p>You can get the schema at&nbsp;<code>\/openapi<\/code>, that will describe the services and models available.<\/p>\n\n\n\n<p>Doing a GET on&nbsp;<code>\/person\/1<\/code>&nbsp;will return the Person in json format.<\/p>\n\n\n\n<p>Depending on the size of Person, this can be a big file:<\/p>\n\n\n\n<pre class=\"brush:js\">{\n  \"addresses\": [\n    {\n      \"code\": \"49512-5971\",\n      \"lines\": [\n        \"212 Neomi Ridges\",\n        \"Lake Winfordview\",\n        \"Wisconsin\",\n        \"Myanmar\"\n      ]\n    },\n    {\n      \"code\": \"09444-8413\",\n      \"lines\": [\n        \"1443 Bogan Harbor\",\n        \"East Jacinto\",\n        \"New York\",\n        \"Timor-Leste\"\n      ]\n    }\n  ],\n  \"biography\": \"Perferendis asperiores non. Cumque voluptas et nisi rerum tenetur quaerat. Doloribus nihil et. Autem autem sapiente et ut inventore ipsum sint. Aut error pariatur quidem itaque deserunt. Dolorum aspernatur exercitationem. In tenetur quia iste qui quia officiis.\",\n  \"birthDate\": \"25\/01\/1967\",\n  \"coverphotos\": [\n    \"http:\/\/lorempixel.com\/g\/1920\/1200\/city\/\"\n  ],\n  \"creditCards\": [\n    {\n      \"expiry\": \"2013-9-12\",\n      \"number\": \"1234-2121-1221-1211\",\n      \"type\": \"solo\"\n    }\n  ],\n  \"emailAddresses\": [\n    \"leo.lesch@gmail.com\",\n    \"laurie.ankunding@gmail.com\"\n  ],\n  \"favColor\": \"lime\",\n  \"gender\": \"Female\",\n  \"id\": 1,\n  \"idNumber\": \"334-58-1049\",\n  \"imClients\": [\n    {\n      \"identifier\": \"Slack\",\n      \"im\": \"cory.langworth\"\n    },\n    {\n      \"identifier\": \"ICQ\",\n      \"im\": \"booker.boyle\"\n    }\n  ],\n  \"interests\": [\n    \"PUBG\",\n    \"meditation\"\n  ],\n  \"joinDate\": \"14\/09\/2019\",\n  \"locale\": \"en-ZA\",\n  \"maritalStatus\": \"Divorced\",\n  \"names\": [\n    \"Nicholas\",\n    \"Edwin\"\n  ],\n  \"nicknames\": [\n    \"Oscar Ruitt\"\n  ],\n  \"occupation\": \"Officer\",\n  \"organization\": \"Hodkiewicz Group\",\n  \"phoneNumbers\": [\n    {\n      \"number\": \"1-852-821-3630\",\n      \"type\": \"Cell\"\n    },\n    {\n      \"number\": \"783.874.6411\",\n      \"type\": \"Home\"\n    },\n    {\n      \"number\": \"(489) 031-5336 x8428\",\n      \"type\": \"Work\"\n    }\n  ],\n  \"profilePictures\": [\n    \"https:\/\/s3.amazonaws.com\/uifaces\/faces\/twitter\/stan\/128.jpg\"\n  ],\n  \"relations\": [\n    {\n      \"personURI\": \"\/rest\/person\/46\",\n      \"relationType\": \"Spouse\"\n    }\n  ],\n  \"skills\": [\n    \"Communication\",\n    \"Confidence\"\n  ],\n  \"socialMedias\": [\n    {\n      \"name\": \"@jordan.hane\",\n      \"username\": \"Twitter\"\n    },\n    {\n      \"name\": \"annamarie.casper\",\n      \"username\": \"Facebook\"\n    }\n  ],\n  \"surname\": \"Zulauf\",\n  \"taglines\": [\n    \"You will find only what you bring in.\",\n    \"Chuck Norris' keyboard doesn't have a F1 key, the computer asks him for help.\"\n  ],\n  \"title\": \"Dr.\",\n  \"userAgent\": \"Mozilla\/5.0 (iPhone; CPU iPhone OS 12_0_1 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/12.0 Mobile\/15E148 Safari\/604.1\",\n  \"username\": \"trent.kub\",\n  \"website\": \"http:\/\/www.kasey-nikolaus.io\"\n}\n<\/pre>\n\n\n\n<p>Now if you are building a mobile app, or even if you consume this from another service, you might only care about the&nbsp;<code>name<\/code>,&nbsp;<code>surname<\/code>&nbsp;and&nbsp;<code>idNumber<\/code>&nbsp;as an example, but you are getting a lot of data back. You now need to filter out all the irrelevant (for you) information.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"using-microprofile-graphql\">Using MicroProfile GraphQL<\/h3>\n\n\n\n<p>Now let\u2019s add MicroProfile GraphQL to this and see how we can query the data:<\/p>\n\n\n\n<p>First add this to your pom.xml (at least until the runtime supports this as out of the box functionality):<\/p>\n\n\n\n<pre class=\"brush:xml\">&lt;dependency&gt;\n    &lt;groupId&gt;io.smallrye&lt;\/groupId&gt;\n    &lt;artifactId&gt;smallrye-graphql-servlet&lt;\/artifactId&gt;\n    &lt;version&gt;1.0.0&lt;\/version&gt;\n&lt;\/dependency&gt;\n<\/pre>\n\n\n\n<p> Now we can add a GraphQL Endpoint (similar to our REST service above) <\/p>\n\n\n\n<pre class=\"brush:java\">@GraphQLApi\npublic class ProfileGraphQLApi {\n    \n    @Inject \n    private PersonDB personDB;\n\n    @Query\n    @Description(\"Get a person using the person's Id\")\n    public Person getPerson(@Name(\"personId\") int personId){\n        return personDB.getPerson(personId);\n    }\n}\n<\/pre>\n\n\n\n<p>As you can see the code is exactly the same as the REST service, but we have some new annotations:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>@GraphQLApi<\/code>&nbsp;this tells the runtime this is a GraphQL Endpoint, and all methods annotated with&nbsp;<code>@Query<\/code>&nbsp;and&nbsp;<code>@Mutation<\/code>&nbsp;will be exposed.<\/li><li><code>@Query<\/code>&nbsp;this is a queryable method.<\/li><\/ul>\n\n\n\n<p>You can now&nbsp;<code>POST<\/code>&nbsp;a query to&nbsp;<code>\/graphql<\/code>. Let\u2019s use the same example above, you want to get the&nbsp;<code>name<\/code>,&nbsp;<code>surname<\/code>&nbsp;and&nbsp;<code>idNumber<\/code>&nbsp;of the person:<\/p>\n\n\n\n<pre class=\"brush:bash\">{\n  person(personId:1){\n    names\n    surname\n    idNumber\n  }\n}\n<\/pre>\n\n\n\n<p> This will return exactly what you asked for: <\/p>\n\n\n\n<pre class=\"brush:js\">{\n  \"data\": {\n    \"person\": {\n      \"names\": [\n        \"Nicholas\",\n        \"Edwin\"\n      ],\n      \"surname\": \"Zulauf\",\n      \"idNumber\": \"334-58-1049\"\n    }\n  }\n}\n<\/pre>\n\n\n\n<p>and as you can see the payload is much less that the REST example.<\/p>\n\n\n\n<p>We just solved the over-fetching problem:<\/p>\n\n\n\n<p><strong>\u201cOver-fetching is fetching too much data, so there is data in the response you don\u2019t use.\u201d<\/strong><\/p>\n\n\n\n<p>Now let\u2019s say we also want to get the scores for this person. In the REST example we need to get the&nbsp;<code>idNumber<\/code>&nbsp;from our original huge json, and then make a subsequent call to the score service:<\/p>\n\n\n\n<pre class=\"brush:java\">{@ApplicationScoped\n@Path(\"\/score\")\n@Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)\n@Tag(name = \"Score service\",description = \"Score Services\")\npublic class ScoreRestApi {\n    \n    @Inject \n    private ScoreDB scoreDB;\n    \n    @GET \n    @Path(\"\/{idNumber}\")\n    @Operation(description = \"Get a person's scores using the person's Id Number\")\n    public Response getScores(@PathParam(\"idNumber\") String idNumber){\n        return Response.ok(scoreDB.getScores(idNumber)).build();\n    }\n}\n<\/pre>\n\n\n\n<p>Now make the call:&nbsp;<code>curl -X GET \"http:\/\/localhost:8080\/rest\/score\/334-58-1049\"<\/code><\/p>\n\n\n\n<p>This will return:<\/p>\n\n\n\n<pre class=\"brush:js\">[\n  {\n    \"id\": \"4873aa28-cc7e-49b0-841f-ea4df4db0fa2\",\n    \"name\": \"Driving\",\n    \"value\": 31\n  },\n  {\n    \"id\": \"8645363d-fa46-4cb9-8bca-e14435dd5d17\",\n    \"name\": \"Fitness\",\n    \"value\": 85\n  },\n  {\n    \"id\": \"4b2af0b2-2d8b-4210-96e9-2692769c5ef7\",\n    \"name\": \"Activity\",\n    \"value\": 91\n  },\n  {\n    \"id\": \"36d4585f-7061-4ad4-b5cc-5561eba983e7\",\n    \"name\": \"Financial\",\n    \"value\": 22\n  }\n]\n<\/pre>\n\n\n\n<p>(and we might not care about the&nbsp;<code>id<\/code>)<\/p>\n\n\n\n<p>In MicroProfile GraphQL, we are going to add a special query that allows you to add fields in graphQL, even though they are not in your Java POJO model. This is possible because every field in GraphQL is just another&nbsp;<code>Query<\/code>. For the normal case, we just fetch properties from an object, but you can also fetch fields using another query. To add a scores field to person, we can add the following method to our existing Endpoint:<\/p>\n\n\n\n<pre class=\"brush:java\">public List&lt;Score&gt; getScores(@Source Person person) {\n    return scoreDB.getScores(person.getIdNumber());\n}\n<\/pre>\n\n\n\n<p> Now you can add that field in your original&nbsp;<code>query<\/code>, also specifying which sub-fields you are interested in: <\/p>\n\n\n\n<pre class=\"brush:bash\">{\n  person(personId:1){\n    names\n    surname\n    idNumber\n    scores {\n      name\n      value\n    }\n  }\n}\n<\/pre>\n\n\n\n<p> The functionality above will now include the scores, with the score name and score value in your original query: <\/p>\n\n\n\n<pre class=\"brush:js\">{\n  \"data\": {\n    \"person\": {\n      \"names\": [\n        \"Nicholas\",\n        \"Edwin\"\n      ],\n      \"surname\": \"Zulauf\",\n      \"idNumber\": \"334-58-1049\",\n      \"scores\": [\n        {\n          \"name\": \"Driving\",\n          \"value\": 27\n        },\n        {\n          \"name\": \"Fitness\",\n          \"value\": 36\n        },\n        {\n          \"name\": \"Activity\",\n          \"value\": 88\n        },\n        {\n          \"name\": \"Financial\",\n          \"value\": 88\n        }\n      ]\n    }\n  }\n}\n<\/pre>\n\n\n\n<p>Now we solved the under-fetching problem:<\/p>\n\n\n\n<p><strong>\u201cUnder-fetching is not having enough data with a call to an endpoint, leading you to call a second endpoint.\u201d<\/strong><\/p>\n\n\n\n<p>So in REST we had to make a call, that returned too much data and we had to filter the data to get what we wanted (over-fetching) and then we had to make another call to another service to get the rest of the data we needed (under-fetching)<\/p>\n\n\n\n<p>In GraphQL we could make one call to return all the data we need.<\/p>\n\n\n\n<p>And when you don\u2019t need need the score data, that method will never be called, making the back-end more efficient.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mutations\">Mutations<\/h2>\n\n\n\n<p>In GraphQL, everything other that fetching data (GET) is called a&nbsp;<code>mutation<\/code>&nbsp;(PUT, POST, DELETE).<\/p>\n\n\n\n<p>Every mutation changes the data, and then returns the result.<\/p>\n\n\n\n<p>Let\u2019s say we need to create \/ update a person, we can add the following method to our existing Endpoint:<\/p>\n\n\n\n<pre class=\"brush:java\">@Mutation\npublic Person updatePerson(Person person){\n    return personDB.updatePerson(person);    \n}\n<\/pre>\n\n\n\n<p> And to delete a person: <\/p>\n\n\n\n<pre class=\"brush:java\">@Mutation\npublic Person deletePerson(int id){\n    return personDB.deletePerson(id);    \n}\n<\/pre>\n\n\n\n<p> We can now add a person using this mutation (note there is no id field): <\/p>\n\n\n\n<pre class=\"brush:bash\">mutation CreatePerson{\n  updatePerson(person : \n    {\n      names: \"Phillip\"\n    }\n  ){\n    id\n    names\n    surname\n    profilePictures\n    website\n  }\n}\n<\/pre>\n\n\n\n<p> this will return the newly created person: <\/p>\n\n\n\n<pre class=\"brush:js\">{\n  \"data\": {\n    \"updatePerson\": {\n      \"id\": 101,\n      \"names\": [\n        \"Phillip\"\n      ],\n      \"surname\": null,\n      \"profilePictures\": null,\n      \"website\": null\n    }\n  }\n}\n<\/pre>\n\n\n\n<p> Now update the missing fields using a mutation (note the inclusion of the id): <\/p>\n\n\n\n<pre class=\"brush:bash\">mutation UpdatePerson{\n  updatePerson(person : \n    {\n      id: 101, \n      names:\"Phillip\",\n      surname: \"Kruger\", \n      profilePictures: [\n        \"https:\/\/pbs.twimg.com\/profile_images\/1170690050524405762\/I8KJ_hF4_400x400.jpg\"\n      ],\n      website: \"http:\/\/www.phillip-kruger.com\"\n    }){\n    id\n    names\n    surname\n    profilePictures\n    website\n  }\n}\n<\/pre>\n\n\n\n<p> this will return the updated person: <\/p>\n\n\n\n<pre class=\"brush:js\">{\n  \"data\": {\n    \"updatePerson\": {\n      \"id\": 101,\n      \"names\": [\n        \"Phillip\"\n      ],\n      \"surname\": \"Kruger\",\n      \"profilePictures\": [\n        \"https:\/\/pbs.twimg.com\/profile_images\/1170690050524405762\/I8KJ_hF4_400x400.jpg\"\n      ],\n      \"website\": \"http:\/\/www.phillip-kruger.com\"\n    }\n  }\n}\n<\/pre>\n\n\n\n<p> Lastly we can delete that person: <\/p>\n\n\n\n<pre class=\"brush:bash\">mutation DeletePerson{\n  deletePerson(id :101){\n    id\n    names\n    surname\n    profilePictures\n    website\n  }\n}\n<\/pre>\n\n\n\n<p> The above functionality will return the data as it was just before we removed it: <\/p>\n\n\n\n<pre class=\"brush:js\">{\n  \"data\": {\n    \"deletePerson\": {\n      \"id\": 101,\n      \"names\": [\n        \"Phillip\"\n      ],\n      \"surname\": \"Kruger\",\n      \"profilePictures\": [\n        \"https:\/\/pbs.twimg.com\/profile_images\/1170690050524405762\/I8KJ_hF4_400x400.jpg\"\n      ],\n      \"website\": \"http:\/\/www.phillip-kruger.com\"\n    }\n  }\n}\n<\/pre>\n\n\n\n<p> If you now do a&nbsp;<code>query<\/code>&nbsp;for person 101: <\/p>\n\n\n\n<pre class=\"brush:bash\">{\n  person(personId:101){\n    id\n    names\n    surname\n  }\n}\n<\/pre>\n\n\n\n<p> you will not receive any person, as we deleted that person: <\/p>\n\n\n\n<pre class=\"brush:js\"> \"data\": {\n    \"person\": null\n  }\n}\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"partial-results\">Partial results<\/h2>\n\n\n\n<p>Because you can \u2018stitch\u2019 fields together like we showed above with the&nbsp;<code>@Source<\/code>&nbsp;annotation, there is a possibility that some of the queries will fail. Let\u2019s say the score data is in a totally separate system than the person data, and that score system is down, however a query came in that requests person data and the scores. Rather than failing the whole query, we can return partial results, so still return all the person data you asked for, but include the error for the scores. So this query:<\/p>\n\n\n\n<pre class=\"brush:bash\"> {\n  person(personId:1){\n    names\n    surname\n    idNumber\n    scores {\n      name\n      value\n    }\n  }\n}\n<\/pre>\n\n\n\n<p> Will now return something like this: <\/p>\n\n\n\n<pre class=\"brush:js\"> {\n  \"data\": {\n    \"person\": {\n      \"names\": [\n        \"Nicholas\",\n        \"Edwin\"\n      ],\n      \"surname\": \"Zulauf\",\n      \"idNumber\": \"334-58-1049\",\n      \"scores\": null\n    }\n  },\n  \"errors\": [\n    {\n      \"message\": \"Scores for person [334-58-1049] is not available\",\n      \"locations\": [\n        {\n          \"line\": 6,\n          \"column\": 5\n        }\n      ],\n      \"path\": [\n        \"person\",\n        \"scores\"\n      ]\n    }\n  ]\n}\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"interfaces\">Interfaces<\/h2>\n\n\n\n<p>Let\u2019s say that the score is one way that a person can be measured, but there are other things that can also be used to measure a person (age, weight etc.)<\/p>\n\n\n\n<p>We can define an interface that Score (and Age and Weight) implements, and this model with the interface will be available in the schema of our endpoint:<\/p>\n\n\n\n<pre class=\"brush:bash\"> interface Measurable {\n  value: BigInteger\n}\n\ntype Age implements Measurable {\n  value: BigInteger\n}\n\ntype Weight implements Measurable {\n  value: BigInteger\n}\n\ntype Score implements Measurable {\n  events: [Event]\n  id: String\n  name: ScoreType\n  value: BigInteger\n}\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"introspection\">Introspection<\/h2>\n\n\n\n<p>Because GraphQL has a type system built in, we can define our model as part of our schema. With REST (JAX-RS) you need to add something like MicroProfile OpenAPI to describe the endpoint.<\/p>\n\n\n\n<p>In MicroProfile GraphQL you can get the schema that has been generated by doing a GET on&nbsp;<code>\/graphql\/schema.graphql<\/code><\/p>\n\n\n\n<p>You can also use GraphQL Query to inspect the schema. This is called introspection. Example, if you want to get all the types that are available:<\/p>\n\n\n\n<pre class=\"brush:bash\"> {\n  __schema{\n    types {\n      name\n      kind\n    }\n  }\n}\n<\/pre>\n\n\n\n<p> This will return: <\/p>\n\n\n\n<pre class=\"brush:js\"> {\n  \"data\": {\n    \"__schema\": {\n      \"types\": [\n        {\n          \"name\": \"Action\",\n          \"kind\": \"ENUM\"\n        },\n        {\n          \"name\": \"Address\",\n          \"kind\": \"OBJECT\"\n        },\n        {\n          \"name\": \"AddressInput\",\n          \"kind\": \"INPUT_OBJECT\"\n        },\n        {\n          \"name\": \"BigDecimal\",\n          \"kind\": \"SCALAR\"\n        },\n        ... abbreviated\n      ]\n    }\n  }\n}\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"other-annotations\">Other annotations<\/h2>\n\n\n\n<p>You can define the model metadata using annotations. GraphQL has built in annotations for all options, but also support JsonB annotations. Most annotations can be used on a field or a method and the following will apply:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>If the annotation is on the field, it applies to both output type (result of a query\/mutation) and the input type (input parameter to a query\/mutation)<\/li><li>If the annotation is only on a getter method, it applies only to the output type (result of a query\/mutation)<\/li><li>If the annotation is only on a setter method, it applies only to the input type (input parameter to a query\/mutation)<\/li><\/ul>\n\n\n\n<p>Here are some of the options available:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>@Name<\/code>&nbsp;(or&nbsp;<code>@JsonbProperty<\/code>) will name the field. If the annotation is not present, the field name (or method name without the get\/set\/is) will be used.<\/li><li><code>@Description<\/code>&nbsp;can be used to provide a description in the generated schema for entity types and fields.<\/li><li><code>@DefaultValue<\/code>&nbsp;annotation may be used to specify a value in an input type to be used if the client did not specify a value.<\/li><li><code>@Ignore<\/code>&nbsp;(or&nbsp;<code>@JsonbTransient<\/code>) will omit a field when creating the schema.<\/li><li><code>@NonNull<\/code>&nbsp;will mark a field as not null in the schema.<\/li><\/ul>\n\n\n\n<p>You can also define the format for Numbers and Dates:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>@NumberFormat<\/code>&nbsp;(or&nbsp;<code>@JsonbNumberFormat<\/code>) allows you to define the format of a number type.<\/li><li><code>@DateFormat<\/code>&nbsp;(or&nbsp;<code>@JsonbDateFormat<\/code>) allows you to define the format of a date \/ time type.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"in-the-pipeline\">In the pipeline<\/h2>\n\n\n\n<p>So what is next for MicroProfile GraphQL? There are a few features that are listed in the plan for the next release, i.e.:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Context<\/strong>&nbsp;&#8211; A request scoped object that has information of the request. This will allow developers to optimize their code further downstream. An example would be to create better SQL based on the fields being requested.<\/li><li><strong>Pagination<\/strong>&nbsp;&#8211; Even though you can technically add pagination by manually adding&nbsp;<code>first<\/code>&nbsp;and&nbsp;<code>offset<\/code>&nbsp;parameters, this feature will allow developers to just annotate a method with&nbsp;<code>@Paginate<\/code>&nbsp;and then the pagination fields will be available. This makes your code cleaner.<\/li><li><strong>Support for other MicroProfile APIs<\/strong>&nbsp;&#8211; define how other MicroProfile APIs can be used in conjunction with GraphQL. An example would be to make sure GraphQL requests can report metrics using MicroProfile Metrics.<\/li><li><strong>Custom Scalar<\/strong>&nbsp;&#8211; At the moment, there is a set of pre-defined Scalars that developers can use. We will investigate how to allow developers to create and define their own scalars.<\/li><\/ul>\n\n\n\n<p>See the full&nbsp;<a href=\"https:\/\/github.com\/eclipse\/microprofile-graphql\/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.1\">current list<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"links\">Links<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>The application we referenced in this blog post can be found at&nbsp;<a href=\"https:\/\/github.com\/phillip-kruger\/graphql-example\">https:\/\/github.com\/phillip-kruger\/graphql-example<\/a><\/li><li>Read the full specification&nbsp;<a href=\"https:\/\/download.eclipse.org\/microprofile\/microprofile-graphql-1.0\/microprofile-graphql.html\">https:\/\/download.eclipse.org\/microprofile\/microprofile-graphql-1.0\/microprofile-graphql.html<\/a><\/li><li>We used the SmallRye Implementation that you can find at&nbsp;<a href=\"https:\/\/github.com\/smallrye\/smallrye-graphql\">https:\/\/github.com\/smallrye\/smallrye-graphql<\/a><\/li><\/ul>\n\n\n\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td>\n<p>Published on Web Code Geeks with permission by Phillip Kr\u00fcger, partner at our <a href=\"\/\/www.webcodegeeks.com\/join-us\/wcg\/\" target=\"_blank\" rel=\"noopener noreferrer\">WCG program<\/a>. See the original article here: <a href=\"https:\/\/www.phillip-kruger.com\/post\/microprofile_graphql_introduction\/\" target=\"_blank\" rel=\"noopener noreferrer\">MicroProfile GraphQL introduction<\/a><\/p>\n<p>Opinions expressed by Web Code Geeks contributors are their own.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>MicroProfile GraphQL&nbsp;has just released it\u2019s first version (1.0). In this blog post we will explore some of the functionalities available in this release. We will reference an example application, where we use&nbsp;Thorntail&nbsp;as a runtime, manually adding the&nbsp;SmallRye GraphQL Implementation. What is GraphQL? \u201cGraphQL is an open-source data query and manipulation language for APIs, and a &hellip;<\/p>\n","protected":false},"author":16771,"featured_media":927,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[450],"class_list":["post-25070","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-development","tag-graphql"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>MicroProfile GraphQL introduction - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Interested to learn about MicroProfile GraphQL? Check our article exploring some of the functionalities available in the latest release\" \/>\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.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"MicroProfile GraphQL introduction - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about MicroProfile GraphQL? Check our article exploring some of the functionalities available in the latest release\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2020-02-26T10:15:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Phillip Kr\u00fcger\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Phillip Kr\u00fcger\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/\"},\"author\":{\"name\":\"Phillip Kr\u00fcger\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/003a8b8109057f8ed1cba6116c508e26\"},\"headline\":\"MicroProfile GraphQL introduction\",\"datePublished\":\"2020-02-26T10:15:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/\"},\"wordCount\":1816,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"keywords\":[\"GraphQL\"],\"articleSection\":[\"Web Dev\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/\",\"name\":\"MicroProfile GraphQL introduction - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"datePublished\":\"2020-02-26T10:15:42+00:00\",\"description\":\"Interested to learn about MicroProfile GraphQL? Check our article exploring some of the functionalities available in the latest release\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Web Dev\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/web-development\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"MicroProfile GraphQL introduction\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/003a8b8109057f8ed1cba6116c508e26\",\"name\":\"Phillip Kr\u00fcger\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/38e989af8597679e556461deb73f4044c27d0228a28f9971d2ac37794b1b8603?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/38e989af8597679e556461deb73f4044c27d0228a28f9971d2ac37794b1b8603?s=96&d=mm&r=g\",\"caption\":\"Phillip Kr\u00fcger\"},\"description\":\"Phillip is a software developer and a systems architect who knacks for solving problems. He has a passion for clean code and evolutionary architecture. He blogs about all technical things.\",\"sameAs\":[\"https:\/\/www.phillip-kruger.com\/\",\"https:\/\/www.linkedin.com\/in\/phillipkruger\/\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/phillip-kruger\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"MicroProfile GraphQL introduction - Web Code Geeks - 2026","description":"Interested to learn about MicroProfile GraphQL? Check our article exploring some of the functionalities available in the latest release","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.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/","og_locale":"en_US","og_type":"article","og_title":"MicroProfile GraphQL introduction - Web Code Geeks - 2026","og_description":"Interested to learn about MicroProfile GraphQL? Check our article exploring some of the functionalities available in the latest release","og_url":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2020-02-26T10:15:42+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","type":"image\/jpeg"}],"author":"Phillip Kr\u00fcger","twitter_card":"summary_large_image","twitter_creator":"@webcodegeeks","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Phillip Kr\u00fcger","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/"},"author":{"name":"Phillip Kr\u00fcger","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/003a8b8109057f8ed1cba6116c508e26"},"headline":"MicroProfile GraphQL introduction","datePublished":"2020-02-26T10:15:42+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/"},"wordCount":1816,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","keywords":["GraphQL"],"articleSection":["Web Dev"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/","url":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/","name":"MicroProfile GraphQL introduction - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","datePublished":"2020-02-26T10:15:42+00:00","description":"Interested to learn about MicroProfile GraphQL? Check our article exploring some of the functionalities available in the latest release","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/web-dev-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/web-development\/microprofile-graphql-introduction\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Web Dev","item":"https:\/\/www.webcodegeeks.com\/category\/web-development\/"},{"@type":"ListItem","position":3,"name":"MicroProfile GraphQL introduction"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/003a8b8109057f8ed1cba6116c508e26","name":"Phillip Kr\u00fcger","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/38e989af8597679e556461deb73f4044c27d0228a28f9971d2ac37794b1b8603?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/38e989af8597679e556461deb73f4044c27d0228a28f9971d2ac37794b1b8603?s=96&d=mm&r=g","caption":"Phillip Kr\u00fcger"},"description":"Phillip is a software developer and a systems architect who knacks for solving problems. He has a passion for clean code and evolutionary architecture. He blogs about all technical things.","sameAs":["https:\/\/www.phillip-kruger.com\/","https:\/\/www.linkedin.com\/in\/phillipkruger\/"],"url":"https:\/\/www.webcodegeeks.com\/author\/phillip-kruger\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/25070","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/16771"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=25070"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/25070\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/927"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=25070"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=25070"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=25070"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}