資源服務(wù)器是一個(gè)基于 Spring Boot 的 Web 應(yīng)用程序,它通過(guò) Spring for GraphQL 提供 GraphQL API。該 API 使用 Spring Data Neo4j 查詢 Neo4j 數(shù)據(jù)庫(kù)中的公司及其相關(guān)人員和屬性信息。
通過(guò) Spring Initializr 和 HTTPie 創(chuàng)建項(xiàng)目:
https start.spring.io/starter.zip
bootVersion==3.2.1
language==java
packaging==jar
javaVersion==17
type==gradle-project
dependencies==data-neo4j,graphql,docker-compose,web
groupId==com.okta.developer
artifactId==spring-graphql
name=="Spring Boot API"
description=="Demo project of a Spring Boot GraphQL API"
packageName==com.okta.developer.demo > spring-graphql-api.zip
解壓項(xiàng)目文件后,開始編輯項(xiàng)目。在 src/main/resources/graphql 目錄下創(chuàng)建名為 [schema](http://www.dlbhg.com/blog/ua-what-is-schema-in-database/).graphqls 的文件,定義 GraphQL API 的架構(gòu):
type Query {
companyList(page: Int): [Company!]!
companyCount: Int
}
type Company {
id: ID
SIC: String
category: String
companyNumber: String
countryOfOrigin: String
incorporationDate: String
mortgagesOutstanding: Int
name: String
status: String
controlledBy: [Person!]!
owners: [Property!]!
}type Person {
id: ID
birthMonth: String
birthYear: String
nationality: String
name: String
countryOfResidence: String
}type Property {
id: ID
address: String
county: String
district: String
titleNumber: String
}
在 src/main/java 下創(chuàng)建包 com.okta.developer.demo.domain,并添加以下類:
package com.okta.developer.demo.domain;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;@Node
public class Person {
@Id
@GeneratedValue
private Long id;
private String birthMonth;
private String birthYear;
private String countryOfResidence;
private String name;
private String nationality; // 構(gòu)造函數(shù)、getter 和 setter 方法
}
package com.okta.developer.demo.domain;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;@Node
public class Property {
@Id
@GeneratedValue
private Long id;
private String address;
private String county;
private String district;
private String titleNumber; // 構(gòu)造函數(shù)、getter 和 setter 方法
}
package com.okta.developer.demo.domain;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;@Node
public class Company {
@Id
@GeneratedValue
private Long id;
private String SIC;
private String category;
private String companyNumber;
private String countryOfOrigin;
private LocalDate incorporationDate;
private Integer mortgagesOutstanding;
private String name;
private String status; @Relationship(type = "HAS_CONTROL", direction = Relationship.Direction.INCOMING)
private List controlledBy = new ArrayList(); private List owns = new ArrayList(); // 構(gòu)造函數(shù)、getter 和 setter 方法
}
package com.okta.developer.demo.repository;
import com.okta.developer.demo.domain.Company;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;public interface CompanyRepository extends ReactiveNeo4jRepository {
}
package com.okta.developer.demo.controller;
import com.okta.developer.demo.domain.Company;
import com.okta.developer.demo.repository.CompanyRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;@Controller
public class CompanyController {
@Autowired
private CompanyRepository companyRepository; @QueryMapping
public Flux companyList(@Argument Long page) {
return companyRepository.findAll().skip(page * 10).take(10);
} @QueryMapping
public Mono companyCount() {
return companyRepository.count();
}
}
在 Spring Boot 項(xiàng)目的父目錄下運(yùn)行以下命令:
npx create-next-app@latest react-graphql
根據(jù)提示配置項(xiàng)目,并安裝必要的依賴項(xiàng):
cd react-graphql
npm install @mui/x-data-grid @mui/material @emotion/react @emotion/styled axios
在 src/services 目錄下創(chuàng)建 base.tsx 文件:
import axios from 'axios';
export const backendAPI = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_SERVER_URL,
});export default backendAPI;
添加 companies.tsx 文件:
import { backendAPI } from './base';
export const CompanyApi = {
getCompanyList: async (page: number) => {
const response = await backendAPI.post('/graphql', {
query: { companyList(page: ${page}) { id name category } },
});
return response.data.data.companyList;
},
};
在 src/components/company 目錄下創(chuàng)建 CompanyTable.tsx:
import { DataGrid } from '@mui/x-data-grid';
const CompanyTable = ({ rows, columns }) => {
return ;
};export default CompanyTable;
在 Auth0 中創(chuàng)建一個(gè)應(yīng)用程序,并獲取客戶端 ID 和域名。將這些信息添加到 .env.local 文件中:
NEXT_PUBLIC_AUTH0_DOMAIN=
NEXT_PUBLIC_AUTH0_CLIENT_ID=
安裝 Auth0 React SDK:
npm install @auth0/auth0-react
在 src/components/authentication 目錄下創(chuàng)建 Auth0ProviderWithNavigate.tsx:
import { Auth0Provider } from '@auth0/auth0-react';
const Auth0ProviderWithNavigate = ({ children }) => {
const domain = process.env.NEXT_PUBLIC_AUTH0_DOMAIN;
const clientId = process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID; return (
{children}
);
};export default Auth0ProviderWithNavigate;
通過(guò)本教程,您學(xué)會(huì)了如何使用 Spring Boot 構(gòu)建 GraphQL API,并通過(guò) React 客戶端消費(fèi)該 API。此外,您還了解了如何使用 Auth0 為應(yīng)用程序添加身份驗(yàn)證功能。GraphQL 的靈活性使得客戶端可以快速調(diào)整查詢以滿足需求,而 Auth0 提供了安全且便捷的身份驗(yàn)證解決方案。
原文鏈接: https://auth0.com/blog/how-to-build-a-graphql-api-with-spring-boot/