API 接口设计指南-RESTful - GraphQL 分风格含范例_第1页
API 接口设计指南-RESTful - GraphQL 分风格含范例_第2页
API 接口设计指南-RESTful - GraphQL 分风格含范例_第3页
API 接口设计指南-RESTful - GraphQL 分风格含范例_第4页
API 接口设计指南-RESTful - GraphQL 分风格含范例_第5页
已阅读5页,还剩71页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

API接口设计指南

RESTful·GraphQL分风格含范例

从设计原则到工程落地的完整实战手册

10大章节·80+代码示例·100+设计要点

API设计实战系列

目录

第一章API设计概述与设计哲学

第二章RESTfulAPI设计原则

第三章RESTfulAPI实战范例

第四章GraphQL设计原则

第五章GraphQL实战范例

第六章RESTfulvsGraphQL深度对比

第七章认证、授权与安全设计

第八章版本管理、错误处理与限流

第九章性能优化与缓存策略

第十章文档、测试与最佳实践速查

API接口设计指南·RESTful/GraphQL分风格含范例

第一章API设计概述与设计哲学

1.1API的本质与价值

API(ApplicationProgrammingInterface,应用程序编程接口)是软件系统之间交互的契约。它定义了"谁可以调

用、调用什么、传什么参数、返回什么结果"的完整规则。API设计质量直接决定了系统的可用性、可维护性和可扩

展性。

在微服务、移动应用、开放平台等场景下,API是系统对外的唯一入口。一个设计良好的API能让调用方快速

上手、减少沟通成本、降低集成难度;一个设计糟糕的API则会导致调用方频繁出错、需要大量文档、维护成本高

昂。API设计不是技术炫技,而是以使用者为中心的工程实践。

1.2API设计的三层目标

层次目标评判标准

可用性调用方能够正确使用接口语义清晰、参数直观、错误可理解

一致性所有接口遵循统一风格命名、结构、错误码、版本管理统一

演进性支持平滑升级和兼容版本策略、废弃机制、向后兼容

1.3主流API风格对比

风格核心思想代表适用场景

REST资源导向,使用HTTP动词操作资源GitHubAPI、TwitterAPI通用业务API

GraphQL查询语言,客户端声明需要什么数据GitHubGraphQL、Shopify复杂数据聚合、多端复用

gRPC基于Protobuf的高性能RPC微服务内部通信内部高性能场景

WebSocket双向实时通信聊天、实时推送实时交互

Webhook反向通知,服务端主动推送支付回调、事件通知异步事件通知

1.4优秀API的六个特征

特征一:语义清晰。从URL、方法、参数名就能理解接口的用途,无需看文档就能猜到大致功能。例如GET

/users/123一看就知道是获取ID为123的用户。

特征二:资源导向。把系统抽象为资源集合,URL是资源的标识,HTTP方法是对资源的操作。这是REST的

核心思想,也是好的API设计的通用原则。

特征三:状态无关。每个请求都包含处理所需的全部信息,服务端不存储客户端状态。这让系统易于水平扩

展、便于调试和测试。

特征四:错误友好。错误响应包含明确的错误码、可读的错误信息和修复建议,让调用方能够快速定位和解

决问题。

特征五:版本可控。支持平滑的版本升级,新版本上线后旧版本仍可正常工作,给调用方充分的迁移时间。

特征六:安全可靠。支持认证、授权、限流、加密,防止未授权访问和恶意攻击。有完善的监控、日志和审

计能力。

1.5API设计流程

API设计标准流程:

第1步:需求分析

-明确业务场景和使用者

-梳理数据模型和资源

-分析调用模式(读多写少、实时性要求)

第2步:资源建模

-识别核心资源

-定义资源之间的关系

-确定资源的唯一标识

第3步:接口设计

-定义URL结构

-定义HTTP方法和语义

-定义请求和响应结构

第4步:错误处理

-定义错误码规范

-定义错误响应结构

-定义重试和幂等策略

第5步:安全设计

-认证方案(JWT/OAuth2.0)

-授权模型(RBAC/ABAC)

-限流策略

-加密传输

第6步:版本管理

-版本策略(URL/Header/Content-Type)

-版本生命周期

-废弃策略

第7步:文档与测试

-OpenAPI/Swagger文档

-接口测试用例

-契约测试

第8步:评审与发布

-设计评审

-灰度发布

-监控与迭代

API设计的基本原则:第一,以使用者为中心——API是给别人用的,不是给自己看的;第二,保持一致性

——风格统一比单个接口的完美更重要;第三,面向未来——为扩展预留空间,避免破坏性变更;第四,简单

优先——能用简单方式解决的不引入复杂机制;第五,文档即契约——文档与代码同步,用工具自动化生成。

第二章RESTfulAPI设计原则

2.1REST的核心思想

REST(RepresentationalStateTransfer,表述性状态转移)是RoyFielding在2000年博士论文中提出的架构风

格。它的核心思想是把系统抽象为资源(Resource),通过统一的接口操作资源,使用标准的HTTP方法表达操作

语义。

REST不是标准,也不是协议,而是一种设计约束。满足这些约束的API称为RESTfulAPI。REST的核心约束包

括:客户端-服务器分离、无状态、可缓存、统一接口、分层系统、按需代码(可选)。

2.2资源命名规范

规范示例反例

使用名词,不用动词GET/usersGET/getUsers

使用复数形式GET/users/123GET/user/123

使用小写和连字符/user-profiles/userProfiles、/UserProfiles

层级关系用嵌套/users/123/orders/getUserOrders?userId=123

避免过深嵌套(≤3层)/users/123/orders/users/123/orders/456/items/789

使用查询参数过滤/users?status=active/users/active

2.3HTTP方法语义

方法语义幂等安全示例

GET获取资源是是GET/users/123

POST创建资源否否POST/users

PUT全量更新资源是否PUT/users/123

PATCH部分更新资源否否PATCH/users/123

DELETE删除资源是否DELETE/users/123

HEAD获取资源元数据是是HEAD/users/123

OPTIONS获取资源支持的方法是是OPTIONS/users

2.4HTTP状态码使用

状态码含义使用场景

200OK请求成功GET/PUT/PATCH成功

201Created资源创建成功POST创建资源成功

204NoContent成功但无返回内容DELETE成功

400BadRequest请求参数错误参数缺失、格式错误

401Unauthorized未认证缺少Token或Token无效

403Forbidden无权限已认证但无权访问

404NotFound资源不存在查询的资源不存在

409Conflict资源冲突唯一约束冲突

429TooManyRequests请求过于频繁触发限流

500InternalServerError服务器内部错误未预期的异常

503ServiceUnavailable服务不可用服务过载或维护

2.5请求与响应设计

#标准请求结构

GET/api/v1/users/123HTTP/1.1

Host:

Authorization:Bearer

Accept:application/json

X-Request-Id:req_abc123

#标准响应结构(成功)

HTTP/1.1200OK

Content-Type:application/json

X-Request-Id:req_abc123

{

"code":0,

"message":"success",

"data":{

"id":123,

"username":"alice",

"email":"alice@",

"created_at":"2026-09-19T10:30:00Z"

},

"request_id":"req_abc123"

}

#标准响应结构(错误)

HTTP/1.1400BadRequest

Content-Type:application/json

{

"code":10001,

"message":"参数校验失败",

"errors":[

{

"field":"email",

"message":"邮箱格式不正确"

}

],

"request_id":"req_abc123"

}

#分页响应结构

HTTP/1.1200OK

{

"code":0,

"message":"success",

"data":{

"items":[

{"id":1,"name":"Alice"},

{"id":2,"name":"Bob"}

],

"pagination":{

"page":1,

"page_size":20,

"total":100,

"total_pages":5

}

}

}

2.6RESTful设计原则速查

URL用名词,不用动词

使用复数形式表示资源集合

层级关系通过URL路径表达

过滤、排序、分页通过查询参数

HTTP方法表达操作语义

GET安全幂等、POST创建、PUT全量更新、PATCH部分更新、DELETE删除

使用标准HTTP状态码

响应结构统一,包含code、message、data

错误响应包含错误码和详细信息

支持分页、过滤、排序

版本号放在URL或Header

使用HTTPS加密传输

第三章RESTfulAPI实战范例

3.1电商订单API设计

#==========资源设计==========

#订单资源

GET/api/v1/orders#查询订单列表

POST/api/v1/orders#创建订单

GET/api/v1/orders/{id}#查询订单详情

PUT/api/v1/orders/{id}#全量更新订单

PATCH/api/v1/orders/{id}#部分更新订单

DELETE/api/v1/orders/{id}#删除订单

#订单子资源

GET/api/v1/orders/{id}/items#查询订单明细

POST/api/v1/orders/{id}/items#添加订单项

#订单操作

POST/api/v1/orders/{id}/cancel#取消订单

POST/api/v1/orders/{id}/pay#支付订单

POST/api/v1/orders/{id}/ship#发货

#用户订单

GET/api/v1/users/{userId}/orders#查询用户的订单

#==========请求示例==========

#查询订单列表(带分页、过滤、排序)

GET/api/v1/orders?status=paid&page=1&page_size=20&sort=-created_at

Authorization:Bearer

#创建订单

POST/api/v1/orders

Content-Type:application/json

Authorization:Bearer

{

"user_id":123,

"items":[

{

"product_id":456,

"quantity":2

},

{

"product_id":789,

"quantity":1

}

],

"receiver":{

"name":"张三",

"phone":,

"address":"北京市朝阳区某某路1号"

},

"remark":"请尽快发货"

}

#查询订单详情

GET/api/v1/orders/12345

Authorization:Bearer

#部分更新订单

PATCH/api/v1/orders/12345

Content-Type:application/json

Authorization:Bearer

{

"remark":"已修改备注",

"receiver":{

"phone":

}

}

#取消订单

POST/api/v1/orders/12345/cancel

Content-Type:application/json

{

"reason":"不想要了"

}

#==========响应示例==========

#订单列表响应

{

"code":0,

"message":"success",

"data":{

"items":[

{

"id":12345,

"order_no":"ORD20260919001",

"user_id":123,

"total_amount":299.00,

"status":"paid",

"created_at":"2026-09-19T10:30:00Z"

}

],

"pagination":{

"page":1,

"page_size":20,

"total":100,

"total_pages":5

}

}

}

#订单详情响应

{

"code":0,

"message":"success",

"data":{

"id":12345,

"order_no":"ORD20260919001",

"user_id":123,

"items":[

{

"id":1,

"product_id":456,

"product_name":"iPhone16",

"quantity":2,

"unit_price":100.00,

"total_price":200.00

}

],

"total_amount":299.00,

"discount_amount":0.00,

"pay_amount":299.00,

"status":"paid",

"receiver":{

"name":"张三",

"phone":"138****0000",

"address":"北京市朝阳区某某路1号"

},

"created_at":"2026-09-19T10:30:00Z",

"paid_at":"2026-09-19T10:32:00Z"

}

}

3.2用户管理API设计

#==========资源设计==========

#用户资源

GET/api/v1/users#用户列表

POST/api/v1/users#创建用户

GET/api/v1/users/{id}#用户详情

PUT/api/v1/users/{id}#全量更新

PATCH/api/v1/users/{id}#部分更新

DELETE/api/v1/users/{id}#删除用户

#用户子资源

GET/api/v1/users/{id}/profile#用户资料

GET/api/v1/users/{id}/orders#用户订单

GET/api/v1/users/{id}/addresses#用户地址列表

#认证相关

POST/api/v1/auth/login#登录

POST/api/v1/auth/logout#登出

POST/api/v1/auth/refresh#刷新Token

POST/api/v1/auth/register#注册

#==========认证示例==========

#登录

POST/api/v1/auth/login

Content-Type:application/json

{

"username":"alice",

"password":"********"

}

#登录响应

{

"code":0,

"message":"success",

"data":{

"access_token":"eyJhbGciOiJIUzI1NiIs...",

"refresh_token":"eyJhbGciOiJIUzI1NiIs...",

"token_type":"Bearer",

"expires_in":3600

}

}

#刷新Token

POST/api/v1/auth/refresh

Content-Type:application/json

{

"refresh_token":"eyJhbGciOiJIUzI1NiIs..."

}

#==========查询示例==========

#用户列表(带过滤、排序、分页)

GET/api/v1/users?status=active&sort=-created_at&page=1&page_size=20

Authorization:Bearer

#用户列表响应

{

"code":0,

"message":"success",

"data":{

"items":[

{

"id":123,

"username":"alice",

"email":"alice@",

"status":"active",

"created_at":"2026-01-01T00:00:00Z"

}

],

"pagination":{

"page":1,

"page_size":20,

"total":1000,

"total_pages":50

}

}

}

#搜索用户

GET/api/v1/users?keyword=alice

#多条件过滤

GET/api/v1/users?status=active&city=beijing&age_min=18&age_max=60

#字段选择

GET/api/v1/users?fields=id,username,email

#排序

GET/api/v1/users?sort=-created_at,+username

3.3文件上传API设计

#==========资源设计==========

#文件资源

POST/api/v1/files#上传文件

GET/api/v1/files/{id}#获取文件信息

DELETE/api/v1/files/{id}#删除文件

#==========上传示例==========

#方式一:直接上传(小文件)

POST/api/v1/files

Content-Type:multipart/form-data

Authorization:Bearer

WebKitFormBoundary

Content-Disposition:form-data;name="file";filename="image.jpg"

Content-Type:image/jpeg

WebKitFormBoundary--

#上传响应

{

"code":0,

"message":"success",

"data":{

"id":"f_abc123",

"filename":"image.jpg",

"size":102400,

"mime_type":"image/jpeg",

"url":"/f_abc123.jpg",

"created_at":"2026-09-19T10:30:00Z"

}

}

#方式二:分片上传(大文件)

#1.初始化上传

POST/api/v1/files/multipart/init

{

"filename":"video.mp4",

"size":104857600,

"chunk_size":5242880,

"total_chunks":20

}

#响应

{

"upload_id":"upload_abc123",

"chunks":[

{"chunk_index":0,"url":"..."},

...

]

}

#2.上传分片

PUT/api/v1/files/multipart/{upload_id}/chunks/{index}

Content-Type:application/octet-stream

#3.完成上传

POST/api/v1/files/multipart/{upload_id}/complete

{

"parts":[

{"chunk_index":0,"etag":"etag0"},

...

]

}

3.4RESTfulAPI完整示例

#使用SpringBoot实现RESTfulAPI

@RestController

@RequestMapping("/api/v1/orders")

publicclassOrderController{

@Autowired

privateOrderServiceorderService;

//查询订单列表

@GetMapping

publicApiResponse>listOrders(

@RequestParam(required=false)Stringstatus,

@RequestParam(required=false)LonguserId,

@RequestParam(defaultValue="1")Integerpage,

@RequestParam(defaultValue="20")@Max(100)IntegerpageSize,

@RequestParam(defaultValue="-created_at")Stringsort){

OrderQueryquery=OrderQuery.builder()

.status(status)

.userId(userId)

.page(page)

.pageSize(pageSize)

.sort(sort)

.build();

PageResultresult=orderService.queryOrders(query);

returnApiResponse.success(result);

}

//查询订单详情

@GetMapping("/{id}")

publicApiResponsegetOrder(@PathVariableLongid){

OrderDetailVOorder=orderService.getOrderDetail(id);

returnApiResponse.success(order);

}

//创建订单

@PostMapping

@ResponseStatus(HttpStatus.CREATED)

publicApiResponsecreateOrder(

@Valid@RequestBodyCreateOrderRequestrequest){

OrderVOorder=orderService.createOrder(request);

returnApiResponse.success(order);

}

//全量更新订单

@PutMapping("/{id}")

publicApiResponseupdateOrder(

@PathVariableLongid,

@Valid@RequestBodyUpdateOrderRequestrequest){

OrderVOorder=orderService.updateOrder(id,request);

returnApiResponse.success(order);

}

//部分更新订单

@PatchMapping("/{id}")

publicApiResponsepatchOrder(

@PathVariableLongid,

@RequestBodyPatchOrderRequestrequest){

OrderVOorder=orderService.patchOrder(id,request);

returnApiResponse.success(order);

}

//删除订单

@DeleteMapping("/{id}")

@ResponseStatus(HttpStatus.NO_CONTENT)

publicvoiddeleteOrder(@PathVariableLongid){

orderService.deleteOrder(id);

}

//取消订单

@PostMapping("/{id}/cancel")

publicApiResponsecancelOrder(

@PathVariableLongid,

@RequestBodyCancelOrderRequestrequest){

orderService.cancelOrder(id,request.getReason());

returnApiResponse.success();

}

}

//统一响应包装

@Data

publicclassApiResponse{

privateintcode;

privateStringmessage;

privateTdata;

privateStringrequestId;

publicstaticApiResponsesuccess(Tdata){

ApiResponseresponse=newApiResponse<>();

response.setCode(0);

response.setMessage("success");

response.setData(data);

response.setRequestId(MDC.get("requestId"));

returnresponse;

}

publicstaticApiResponseerror(intcode,Stringmessage){

ApiResponseresponse=newApiResponse<>();

response.setCode(code);

response.setMessage(message);

response.setRequestId(MDC.get("requestId"));

returnresponse;

}

}

//全局异常处理

@RestControllerAdvice

publicclassGlobalExceptionHandler{

@ExceptionHandler(BusinessException.class)

publicResponseEntity>handleBusiness(

BusinessExceptione){

returnResponseEntity

.status(HttpStatus.BAD_REQUEST)

.body(ApiResponse.error(e.getCode(),e.getMessage()));

}

@ExceptionHandler(MethodArgumentNotValidException.class)

publicResponseEntity>>

handleValidation(MethodArgumentNotValidExceptione){

Listerrors=e.getBindingResult()

.getFieldErrors()

.stream()

.map(fe->newFieldError(fe.getField(),fe.getDefaultMessage()))

.collect(Collectors.toList());

ApiResponse>response=

ApiResponse.error(10001,"参数校验失败");

response.setErrors(errors);

returnResponseEntity.badRequest().body(response);

}

@ExceptionHandler(Exception.class)

publicResponseEntity>handleUnknown(Exceptione){

log.error("未预期的异常",e);

returnResponseEntity

.status(HttpStatus.INTERNAL_SERVER_ERROR)

.body(ApiResponse.error(50000,"服务器内部错误"));

}

}

第四章GraphQL设计原则

4.1GraphQL的核心思想

GraphQL是Facebook于2015年开源的API查询语言。它允许客户端精确声明需要的数据结构,服务端返回客

户端所需的数据,不多也不少。这解决了REST中的两个核心问题:过度获取(返回不需要的字段)和获取不足

(需要多个请求才能拿到完整数据)。

GraphQL的核心概念包括:Schema(模式)、Query(查询)、Mutation(变更)、Subscription(订阅)、

Resolver(解析器)。Schema定义了API的能力边界,Query用于读取数据,Mutation用于修改数据,Subscription

用于实时数据推送,Resolver定义了每个字段如何获取数据。

4.2GraphQLvsREST核心差异

维度RESTGraphQL

端点多个端点,每个资源一个单一端点/graphql

数据获取服务端决定返回什么客户端声明需要什么

过度获取常见问题不存在

请求次数可能需要多次一次请求获取所有数据

类型系统可选(OpenAPI)强制(Schema)

缓存HTTP缓存成熟需要客户端缓存

学习曲线低中等

适用场景简单CRUD复杂数据聚合

4.3Schema设计规范

#GraphQLSchema定义示例

#标量类型

scalarDateTime

scalarURL

scalarJSON

#枚举类型

enumOrderStatus{

PENDING

PAID

SHIPPED

DELIVERED

CANCELLED

}

#对象类型

typeUser{

id:ID!

username:String!

email:String!

phone:String

avatar:URL

status:UserStatus!

createdAt:DateTime!

updatedAt:DateTime!

orders(first:Int=20,after:String):OrderConnection!

}

typeOrder{

id:ID!

orderNo:String!

user:User!

items:[OrderItem!]!

totalAmount:Float!

status:OrderStatus!

receiver:Receiver!

createdAt:DateTime!

paidAt:DateTime

}

typeOrderItem{

id:ID!

product:Product!

quantity:Int!

unitPrice:Float!

totalPrice:Float!

}

typeReceiver{

name:String!

phone:String!

address:String!

}

#连接类型(分页)

typeOrderConnection{

edges:[OrderEdge!]!

pageInfo:PageInfo!

totalCount:Int!

}

typeOrderEdge{

node:Order!

cursor:String!

}

typePageInfo{

hasNextPage:Boolean!

hasPreviousPage:Boolean!

startCursor:String

endCursor:String

}

#输入类型

inputCreateOrderInput{

userId:ID!

items:[OrderItemInput!]!

receiver:ReceiverInput!

remark:String

}

inputOrderItemInput{

productId:ID!

quantity:Int!

}

inputReceiverInput{

name:String!

phone:String!

address:String!

}

#查询类型

typeQuery{

#用户查询

user(id:ID!):User

users(

first:Int=20,

after:String,

filter:UserFilter,

orderBy:UserOrderBy

):UserConnection!

#订单查询

order(id:ID!):Order

orders(

first:Int=20,

after:String,

filter:OrderFilter

):OrderConnection!

#当前用户

me:User

}

#变更类型

typeMutation{

#用户操作

createUser(input:CreateUserInput!):UserPayload!

updateUser(id:ID!,input:UpdateUserInput!):UserPayload!

deleteUser(id:ID!):DeletePayload!

#订单操作

createOrder(input:CreateOrderInput!):OrderPayload!

cancelOrder(id:ID!,reason:String):OrderPayload!

payOrder(id:ID!,payMethod:PayMethod!):OrderPayload!

}

#订阅类型

typeSubscription{

orderCreated(userId:ID!):Order!

orderStatusChanged(orderId:ID!):Order!

}

#输入过滤类型

inputUserFilter{

keyword:String

status:UserStatus

createdAfter:DateTime

createdBefore:DateTime

}

inputUserOrderBy{

field:UserOrderField!

direction:SortDirection!

}

enumUserOrderField{

CREATED_AT

USERNAME

ID

}

enumSortDirection{

ASC

DESC

}

#响应Payload类型

typeUserPayload{

user:User

errors:[Error!]

}

typeOrderPayload{

order:Order

errors:[Error!]

}

typeDeletePayload{

success:Boolean!

errors:[Error!]

}

typeError{

code:String!

message:String!

field:String

}

4.4GraphQL设计原则

原则一:Schema优先。先设计Schema,再实现Resolver。Schema是API的契约,应该由前后端共同设计,

作为协作的基础。

原则二:字段命名清晰。使用小驼峰命名法(camelCase),字段名要表达明确的语义,避免缩写和歧义。

原则三:避免深层嵌套。嵌套层级过深会导致查询复杂、性能问题。一般不超过4-5层。

原则四:使用连接类型分页。遵循Relay规范,使用Connection类型实现分页,支持游标分页。

原则五:输入和输出分离。使用Input类型定义输入,使用Payload类型定义输出。

原则六:错误处理规范化。业务错误放在Payload的errors字段中,系统错误通过GraphQL的标准错误机

制返回。

4.5GraphQL查询示例

#基础查询

query{

user(id:"123"){

id

username

email

createdAt

}

}

#嵌套查询

query{

user(id:"123"){

id

username

orders(first:10){

edges{

node{

id

orderNo

totalAmount

status

items{

product{

name

price

}

quantity

}

}

}

}

}

}

#带变量的查询

queryGetUserWithOrders($userId:ID!,$orderCount:Int!){

user(id:$userId){

id

username

orders(first:$orderCount){

edges{

node{

orderNo

totalAmount

}

}

}

}

}

#变量

{

"userId":"123",

"orderCount":5

}

#带别名的查询(同一字段多次查询)

query{

firstUser:user(id:"123"){

username

}

secondUser:user(id:"456"){

username

}

}

#片段复用

fragmentUserBasiconUser{

id

username

email

}

query{

user(id:"123"){

...UserBasic

orders(first:5){

edges{

node{

orderNo

}

}

}

}

}

#变更

mutationCreateOrder($input:CreateOrderInput!){

createOrder(input:$input){

order{

id

orderNo

totalAmount

status

}

errors{

code

message

field

}

}

}

#变量

{

"input":{

"userId":"123",

"items":[

{"productId":"456","quantity":2}

],

"receiver":{

"name":"张三",

"phone":,

"address":"北京市朝阳区某某路1号"

}

}

}

#订阅

subscription{

orderStatusChanged(orderId:"12345"){

id

orderNo

status

updatedAt

}

}

第五章GraphQL实战范例

5.1GraphQL服务端实现(Node.js)

//使用ApolloServer实现GraphQL服务

const{ApolloServer,gql}=require('apollo-server-express');

constexpress=require('express');

//1.定义Schema

consttypeDefs=gql`

scalarDateTime

typeUser{

id:ID!

username:String!

email:String!

orders(first:Int=20,after:String):OrderConnection!

}

typeOrder{

id:ID!

orderNo:String!

user:User!

totalAmount:Float!

status:OrderStatus!

createdAt:DateTime!

}

enumOrderStatus{

PENDING

PAID

SHIPPED

DELIVERED

CANCELLED

}

typeOrderConnection{

edges:[OrderEdge!]!

pageInfo:PageInfo!

totalCount:Int!

}

typeOrderEdge{

node:Order!

cursor:String!

}

typePageInfo{

hasNextPage:Boolean!

endCursor:String

}

typeQuery{

user(id:ID!):User

users(first:Int=20,after:String):UserConnection!

me:User

}

typeMutation{

createOrder(input:CreateOrderInput!):OrderPayload!

}

inputCreateOrderInput{

items:[OrderItemInput!]!

}

inputOrderItemInput{

productId:ID!

quantity:Int!

}

typeOrderPayload{

order:Order

errors:[Error!]

}

typeError{

code:String!

message:String!

}

typeUserConnection{

edges:[UserEdge!]!

pageInfo:PageInfo!

totalCount:Int!

}

typeUserEdge{

node:User!

cursor:String!

}

`;

//2.实现Resolver

constresolvers={

Query:{

user:async(_,{id},{dataSources,user})=>{

if(!user)thrownewAuthenticationError('未登录');

returndataSources.userAPI.getUser(id);

},

users:async(_,{first,after},{dataSources})=>{

constusers=awaitdataSources.userAPI.getUsers({

first,

after

});

return{

edges:users.map(u=>({

node:u,

cursor:Buffer.from(`user:${u.id}`).toString('base64')

})),

pageInfo:{

hasNextPage:users.length===first,

endCursor:users.length>0

?Buffer.from(`user:${users[users.length-1].id}`)

.toString('base64')

:null

},

totalCount:awaitdataSources.userAPI.countUsers()

};

},

me:async(_,__,{user})=>{

if(!user)returnnull;

returnuser;

}

},

Mutation:{

createOrder:async(_,{input},{dataSources,user})=>{

if(!user){

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论