Это руководство для тех, кто хочет создать сервер GraphQL на Java. Требуются некоторые знания о разработке Spring Boot и Java, и хотя мы кратко рассмотрели GraphQL, основное внимание в этом руководстве уделяется разработке сервера GraphQL на Java.
Знакомство с GraphQL за 3 минуты
GraphQL — это язык запросов для получения данных с серверов. REST, SOAP и gRPC могут быть заменены в некоторых сценариях. Допустим, мы хотим получить информацию об определенной книге из бэкенда интернет-магазина.
Вы используете GraphQL для отправки следующего запроса на сервер, чтобы получить сведения о книге с идентификатором «123»:
{
bookById(id: "book-1"){
id
name
pageCount
author {
firstName
lastName
}
}
}
Это не кусок JSON (хотя выглядит очень похоже), а запрос GraphQL. В основном это означает:
- Запрос книги с определенным идентификатором
- Дайте мне идентификатор, имя, количество страниц, автора этой книги
- Для автора я хочу знать имя и фамилию
Ответ представляет собой обычный JSON:
{
"bookById":
{
"id":"book-1",
"name":"Harry Potter and the Philosopher's Stone",
"pageCount":223,
"author": {
"firstName":"Joanne",
"lastName":"Rowling"
}
}
}
Статическая типизация — одна из наиболее важных функций GraphQL: сервер точно знает, как выглядит каждый объект, который вы хотите запросить, и любой клиент может «самоанализировать» сервер и запросить «схему». Схема описывает, каким может быть запрос и какие поля вы можете вернуть. (Примечание: говоря о схеме, мы часто имеем в виду «схему GraphQL», а не что-то вроде «схемы JSON» или «схемы базы данных»)
Схема упомянутого выше запроса описывается следующим образом:
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
В этом руководстве основное внимание будет уделено тому, как реализовать сервер GraphQL с этой схемой на Java.
Мы коснулись лишь некоторых основных функций GraphQL. Для получения дополнительной информации, пожалуйста, посетите официальный сайтgraphql.github.io/learn/
Предварительная версия GraphQL Java
GraphQL Javaявляется Java (серверной) реализацией GraphQL. В организации GraphQL Java Github есть несколько репозиториев Git. Одним из наиболее важных являетсяJava-движок GraphQL, который является основой всего остального.
Сам движок GraphQL Java заботится только о выполнении запросов. Он не обрабатывает темы, связанные с HTTP или JSON. Поэтому мы будем использоватьGraphQL Java Spring Bootадаптер, который предоставляет API через HTTP через Spring Boot.
Основные шаги по созданию Java-сервера GraphQL следующие:
- Определите схему GraphQL.
- Решите, как получить фактические данные, которые необходимо запросить.
Наш пример API: получение сведений о книге
Наш пример приложения будет простым API для получения сведений о конкретной книге. Этот API не очень всеобъемлющий, но его достаточно для этого руководства.
Создайте приложение Spring Boot
Самый простой способ создать приложение Spring — использоватьstart.spring.io/"Весна Инициализ" на .
выберите:
- Gradle Project
- Java
- Spring Boot 2.1.x
Для метаданных проекта мы используем:
- Group:
com.graphql-java.tutorial
- Artifact:
book-details
Что касается зависимостей, мы выбираем только Web.
нажмитеGenerate Project
, вы готовы использовать свое приложение Spring Boot. Все файлы и пути, упомянутые ниже, относятся к этому проекту создания.
мы вbuild.gradle
изdependencies
section добавляет в наш проект три зависимости:
Первые два — это GraphQL Java и GraphQL Java Spring, затем мы также добавилиGoogle Guava. Гуава не обязательна, но она немного облегчит нам жизнь.
Зависимости выглядят так:
dependencies {
implementation 'com.graphql-java:graphql-java:11.0' // NEW
implementation 'com.graphql-java:graphql-java-spring-boot-starter-webmvc:1.0' // NEW
implementation 'com.google.guava:guava:26.0-jre' // NEW
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Schema
мыsrc/main/resources
создать новый файл подschema.graphqls
, который содержит следующее:
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
Эта схема определяет поле верхнего уровня (вQuery
тип):bookById
, который возвращает сведения о конкретной книге.
Он также определяет типBook
, который содержит:id
,name
,pageCount
иauthor
.author
принадлежатьAuthor
ВведитеBook
определены позже.
Предметно-ориентированный язык, показанный выше для описания схем, называется языком определения схемы или SDL. Более подробную информацию можно найти наздесьоказаться.
Когда у нас есть файл, нам нужно «оживить» его, прочитав файл и проанализировав его, а затем добавив код для получения данных для него.
мы вcom.graphqljava.tutorial.bookdetails
В пакете создается новыйGraphQLProvider
своего рода.init
метод создаст экземпляр GraphQL:
@Component
public class GraphQLProvider {
private GraphQL graphQL;
@Bean
public GraphQL graphQL() {
return graphQL;
}
@PostConstruct
public void init() throws IOException {
URL url = Resources.getResource("schema.graphqls");
String sdl = Resources.toString(url, Charsets.UTF_8);
GraphQLSchema graphQLSchema = buildSchema(sdl);
this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
}
private GraphQLSchema buildSchema(String sdl) {
// TODO: we will create the schema here later
}
}
Мы используемGuava
Ресурсы читают файлы из пути к классам, а затем создаютGraphQLSchema
иGraphQL
пример. этоGraphQL
экземпляр с использованием@Bean
аннотированныйGraphQL()
Методы выставляются как Spring Beans. Адаптер GraphQL Java Spring будет использоватьGraphQL
instance, чтобы наша схема могла передать URL-адрес по умолчанию/GraphQL
Сделайте HTTP-доступ.
Что нам еще нужно сделать, так это реализоватьbuildSchema
метод, который создаетGraphQLSchema
instance и подключите код для получения данных:
@Autowired
GraphQLDataFetchers graphQLDataFetchers;
private GraphQLSchema buildSchema(String sdl) {
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
RuntimeWiring runtimeWiring = buildWiring();
SchemaGenerator schemaGenerator = new SchemaGenerator();
return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
}
private RuntimeWiring buildWiring() {
return RuntimeWiring.newRuntimeWiring()
.type(newTypeWiring("Query")
.dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()))
.type(newTypeWiring("Book")
.dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()))
.build();
}
TypeDefinitionRegistry
— проанализированная версия файла схемы. SchemaGenerator будетTypeDefinitionRegistry
иRuntimeWiring
в сочетании для фактического созданияGraphQLSchema
.
buildRuntimeWiring
использоватьgraphQLDataFetchers
боб для регистрации двухDatafetcher
s:
- Одним из них является получение книг с определенным идентификатором.
- Во-первых, найти авторов для конкретных книг.
Следующий раздел объяснитDataFetcher
и как добитьсяGraphQLDataFetchers
бобы.
В общем, создайтеGraphQL
иGraphQLSchema
Процесс экземпляра выглядит следующим образом:
DataFetchers
Вероятно, наиболее важной концепцией Java-сервера GraphQL являетсяDatafetcher
: при выполнении запросаDatafetcher
Получить данные для поля.
Когда GraphQL Java выполняет запрос, он вызывает соответствующийDatafetcher
.DataFetcher
это интерфейс только с одним методом, с параметром типаDataFetcherEnvironment
:
public interface DataFetcher<T> {
T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception;
}
ВАЖНО: Каждое поле в схеме имеетDataFetcher
. Если для конкретного поля ничего не указаноDataFetcher
, используйте значение по умолчаниюPropertyDataFetcher
. Мы обсудим это более подробно позже.
Мы создаем новый классGraphQLDataFetchers
, который содержит примерный список книг и авторов.
Полная реализация выглядит так, скоро мы рассмотрим ее подробно:
@Component
public class GraphQLDataFetchers {
private static List<Map<String, String>> books = Arrays.asList(
ImmutableMap.of("id", "book-1",
"name", "Harry Potter and the Philosopher's Stone",
"pageCount", "223",
"authorId", "author-1"),
ImmutableMap.of("id", "book-2",
"name", "Moby Dick",
"pageCount", "635",
"authorId", "author-2"),
ImmutableMap.of("id", "book-3",
"name", "Interview with the vampire",
"pageCount", "371",
"authorId", "author-3")
);
private static List<Map<String, String>> authors = Arrays.asList(
ImmutableMap.of("id", "author-1",
"firstName", "Joanne",
"lastName", "Rowling"),
ImmutableMap.of("id", "author-2",
"firstName", "Herman",
"lastName", "Melville"),
ImmutableMap.of("id", "author-3",
"firstName", "Anne",
"lastName", "Rice")
);
public DataFetcher getBookByIdDataFetcher() {
return dataFetchingEnvironment -> {
String bookId = dataFetchingEnvironment.getArgument("id");
return books
.stream()
.filter(book -> book.get("id").equals(bookId))
.findFirst()
.orElse(null);
};
}
public DataFetcher getAuthorDataFetcher() {
return dataFetchingEnvironment -> {
Map<String,String> book = dataFetchingEnvironment.getSource();
String authorId = book.get("authorId");
return authors
.stream()
.filter(author -> author.get("id").equals(authorId))
.findFirst()
.orElse(null);
};
}
}
источник данных
Мы получаем книгу и автора из статического списка в классе. Это только для этого урока. Очень важно понимать, что GraphQL не указывает, откуда берутся данные. В этом сила GraphQL: он может исходить из статического списка в памяти, базы данных или внешней службы.
Book DataFetcher
Наш первый способgetBookByIdDataFetcher
вернутьDataFetcher
реализация, которая принимаетDataFetcherEnvironment
и возвращает книгу. В данном случае это означает, что нам нужно начатьbookById
поле принимает параметр id и находит книгу с этим конкретным идентификатором.
String bookId = dataFetchingEnvironment.getArgument("id");
«id» в схеме находится в схемеbookById
"id" в поле запроса:
type Query {
bookById(id: ID): Book
}
...
Author DataFetcher
второй способgetAuthorDataFetcher
вернутьDatafetcher
, чтобы получить автора конкретной книги. с ранее описанной книгойDataFetcher
Напротив, у нас нет параметров, а есть экземпляр книги. из родительского поляDataFetcher
Результат можно получить,getSource
получить. Это важная концепция для понимания: значение каждого поля в GraphQLDatafetcher
вызываются сверху вниз, результатом родительского поля является дочернееDatafetcherenvironment
изsource
Атрибуты.
Затем мы получаем authorId, используя ранее загруженную книгу, и ищем конкретного автора так же, как мы ищем конкретную книгу.
Default DataFetchers
Мы реализовали только дваDatafetcher
. Как и выше, если он не указан, используется значение по умолчанию.PropertyDataFetcher
. В нашем случае это относится кBook.id
,Book.name
,Book.pageCount
,Author.id
,Author.firstName
иAuthor.lastName
имеет значение по умолчаниюPropertyDataFetcher
связанные с ним.
PropertyDataFetcher
Попробуйте найти свойства объектов Java несколькими способами. отjava.util.Map
Например, он просто ищет свойства по ключу. Это отлично работает для нас, потому что ключи карты книги и автора совпадают с полями, указанными в схеме. Например, в схеме, которую мы определили для типа книги, полеpageCount
и книгаDataFetcher
возвращает ключ сpageCount
изMap
. потому что имя поля совпадает сMap
тот же ключ ("pageCount"),PropertyDateFetcher
нормальная работа.
Предположим, у нас есть несоответствие, книгаMap
Есть ключ, которыйtotalPages
вместоpageCount
. Это приведет кpageCount
значениеnull
,так какPropertyDataFetcher
Не удалось получить правильное значение. Чтобы решить эту проблему, вы должныBook.pageCount
зарегистрировать новыйDataFetcher
. Это выглядит так:
// In the GraphQLProvider class
private RuntimeWiring buildWiring() {
return RuntimeWiring.newRuntimeWiring()
.type(newTypeWiring("Query")
.dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()))
.type(newTypeWiring("Book")
.dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher())
// This line is new: we need to register the additional DataFetcher
.dataFetcher("pageCount", graphQLDataFetchers.getPageCountDataFetcher()))
.build();
}
// In the GraphQLDataFetchers class
// Implement the DataFetcher
public DataFetcher getPageCountDataFetcher() {
return dataFetchingEnvironment -> {
Map<String,String> book = dataFetchingEnvironment.getSource();
return book.get("totalPages");
};
}
...
этоDataFetcher
пройдет в книгеMap
Найдите правильный ключ, чтобы решить эту проблему. (опять же: в нашем примере это не нужно, так как у нас нет несоответствия имен)
Попробуйте API
Это все, что нужно для создания работающего API GraphQL. После запуска приложения Spring Boot вы можетеhttp://localhost:8080/graphql
использовать API.
Самый простой способ попробовать и изучить GraphQL API — использоватьGraphQL PlaygroundИнструмент. Загрузите и запустите его.
После запуска вам будет предложено ввести URL, введитеhttp://localhost:8080/graphql
.
После этого вы можете запросить наш пример API, и вы должны получить результаты, о которых мы упоминали в начале. Это должно выглядеть так:
Полный образец исходного кода и дополнительная информация
Полный проект и полный исходный код можно найти здесь:GitHub.com/graph up — просто ав…
Дополнительную информацию о GraphQL Java можно найти по адресуДокументациянайти в.
По любым вопросам у нас также естьspectrum chat Примите обсуждение.
Для прямой обратной связи вы также можетеGraphQL Java Twitter accountНайдите нас в своем аккаунте.
Оригинальная ссылка:Getting started with GraphQL Java and Spring Boot
Ссылка на перевод:Начало работы с GraphQL Java и Spring Boot
перевести:TomorJM