Servidor simple con GraphQL en lugar de REST, implementación en java


Me ofrecieron familiarizarme con GraphQL. Vea si puede postularse en el trabajo. Después de buscar, me di cuenta de que la mayoría de la información está en inglés y en parte antigua, hay 3 versiones de la biblioteca y ya hay 5. Quiero llenar este vacío En esta opción habrá un ejemplo de servlets, es decir. sin resorte y sin bota de resorte.

La parte teórica:
GraphQL: una nueva mirada a la API. Parte 1 de VladimirZaets
Comparación bevalorosa de REST y GraphQL

Le mostraré el código de inmediato, porque GraphQL es una abstracción. Y si discute la abstracción durante mucho tiempo, puede perderse. El original está aquí .

Cambié un poco el código porque Las versiones más nuevas no tienen algunas clases.

Crea un proyecto maven vacío. Agregar dependencias al picnic:

<dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java</artifactId> <version>8.0</version> </dependency> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java-tools</artifactId> <version>5.0.0</version> </dependency> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java-servlet</artifactId> <version>5.0.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> 

Para no pensar en el servidor, tome el embarcadero:

  <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.6.v20170531</version> </plugin> 

Diferencias del tutorial:

  1. La herencia de SimpleGraphQLServlet con una llamada al constructor ahora está "en desuso", debe usar el generador, que es imposible con la herencia, use la composición.
  2. En el servlet, puede crear un objeto SimpleGraphQLServlet.
  3. GraphQLRootResolver: no más, puede usar los específicos: GraphQLMutationResolver y GraphQLQueryResolver

La base está lista. Lo haremos de acuerdo con el tutorial, sin resorte o JAX-RS. En general, un servlet regular:

 @WebServlet(urlPatterns = "/graphql") public class GraphQLEndpoint extends HttpServlet { private SimpleGraphQLServlet graph; public GraphQLEndpoint() { graph = SimpleGraphQLServlet.builder(buildSchema()).build(); } private static GraphQLSchema buildSchema() { LinkRepository linkRepository = new LinkRepository(); return SchemaParser.newParser() .file("schema.graphqls") .resolvers(new Query(linkRepository), new Mutation(linkRepository)) .build() .makeExecutableSchema(); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { graph.service(req, resp); } } 

En él, el método de servicio pasa datos a SimpleGraphQLServlet. Todo en esto termina nuestro negocio.

Código regular (Link y LinkRepository)
 public class Link { private final String url; private final String description; public Link(String url, String description) { this.url = url; this.description = description; } public String getUrl() { return url; } public String getDescription() { return description; } } 

 public class LinkRepository { private final List<Link> links; public LinkRepository() { links = new ArrayList<>(); //add some links to start off with links.add(new Link("http://howtographql.com", "Your favorite GraphQL page")); links.add(new Link("http://graphql.org/learn/", "The official docks")); } public List<Link> getAllLinks() { return links; } public void saveLink(Link link) { links.add(link); } } 


Ahora el código de solicitud (solicitudes GET en REST) ​​y mutaciones (solicitudes de cambios)
 import com.coxautodev.graphql.tools.GraphQLQueryResolver; public class Query implements GraphQLQueryResolver { private final LinkRepository linkRepository; public Query(LinkRepository linkRepository) { this.linkRepository = linkRepository; } public List<Link> allLinks() { return linkRepository.getAllLinks(); } } 

 import com.coxautodev.graphql.tools.GraphQLMutationResolver; public class Mutation implements GraphQLMutationResolver { private final LinkRepository linkRepository; public Mutation(LinkRepository linkRepository) { this.linkRepository = linkRepository; } public Link createLink(String url, String description) { Link newLink = new Link(url, description); linkRepository.saveLink(newLink); return newLink; } } 


Comenzamos por el embarcadero: corre y lanzamos la solicitud:

 http://localhost:8080/graphql?query={allLinks{url}} 

Obtenemos la respuesta:

 {"data": {"allLinks": [ {"url":"http://howtographql.com"}, {"url":"http://graphql.org/learn/"} ] } } 

Y aquí está el primer punto principal: tenemos 2 campos, url y descripción, y recibimos solo url en respuesta. Y con razón, porque solo url y pedimos {allLinks {url}} en la solicitud. Si cambia la solicitud a:

 http://localhost:8080/graphql?query={allLinks{url,description}} 

la respuesta es:

 {"data": {"allLinks": [ { "url":"http://howtographql.com", "description":"Your favorite GraphQL page" }, { "url":"http://graphql.org/learn/", "description":"The official docks" } ] } } 

Ahora tenemos url y descripción. Y todo porque les preguntamos.

Solicitud de cambio de datos.

Es un poco más complicado y mucho más fácil usar la utilidad UI.

1. Vamos a la dirección
2. Copie todo el archivo index.html
3. Reemplace 2 líneas:

Estos son:

 <link rel="stylesheet" href="./node_modules/graphiql/graphiql.css" /> <script src="./node_modules/graphiql/graphiql.js"></script> 


En estos:

 <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphiql@0.11.2/graphiql.css" /> <script src="//cdn.jsdelivr.net/npm/graphiql@0.11.2/graphiql.js"></script> 


4. Reemplace index.html en el proyecto ... \ src \ main \ webapp \ index.html con el que se acaba de cancelar.

Reiniciamos el proyecto, vamos a localhost: 8080 y accedemos a dicha página.


Primer bono: a la izquierda está el botón Documentos, que oculta la documentación preparada para su proyecto. No mucho, campos que se pueden solicitar y métodos a los que se puede llamar y qué pasar en ellos.



También te da tus juegos de autos favoritos.



Ahora con él, enviaremos una solicitud de mutación. Tenemos una mutación, "agregar un enlace".



texto de consulta:
 mutation createLink{ createLink(url:"http://test.com", description:"test mutation"){ url description } } 

Un poco más tarde descubrí que la palabra mutación es suficiente (createLink después de que no es necesario escribir)

 mutation { createLink(url:"http://test.com", description:"test mutation"){ url description } } 



Es decir simplemente llamamos al método por su nombre y le pasamos parámetros. También puede traicionar qué información queremos recuperar.

Cómo ver una solicitud de mutación
1. Abra la pestaña de desarrollador F12 y abra la red, le enviamos la solicitud.



2. En la solicitud presentada, RMB -> copiar -> copiar como cURL (bash)



2.1. Para aquellos que usan curl, esto es suficiente, para aquellos que quieren ver al cartero ir más allá

3. Abra el cartero y haga clic en importar en la esquina superior izquierda.



4. En la ventana que se abre, seleccione Pegar texto sin formato y pegue allí la solicitud de rizo copiada.



Y podemos ver el cuerpo de la solicitud:

 {"query":"mutation createLink{\n createLink(url:\"http://test.com\", description:\"test mutation\"){\n\t\turl\n description\n }\n}","variables":null,"operationName":"createLink"}    “\n”. 


En esta etapa, ya hay un servidor simple, hay almacenamiento allí y configuramos la url para las solicitudes.

Me gustó la idea en sí. El frente mismo puede determinar qué información necesita actualmente, cómo ahorrar tráfico. Al agregar una nueva funcionalidad, la anterior continúa funcionando, el frente continúa recibiendo solo lo que necesita, ni más, ni menos.

Código de muestra de Github
2 ramas:

master - como se hace en el tutorial oficial

update_version es una versión actualizada, con nuevas versiones de dependencias.

Referencias

1. Muelles
2. tutorial oficial (para diferentes idiomas)
3. El video que dio la primera comprensión

Source: https://habr.com/ru/post/es418083/


All Articles