10月8日至10日加入我们,在纽约市学习关于GraphQL联邦和API平台工程的最新技巧、趋势和新闻。加入我们于2024年在纽约市举行的GraphQL峰会
文档
免费开始

9. 编写你的第一个变异操作


在本节中,你将编写第一个以登录后端。

变异操作用于更改服务器上的数据。在这里,登录变异操作将根据您的电子邮件地址创建一个会话。

注意:您登录此特定服务器的方式可能不同于您登录自建服务器的方式。登录通常是由中间件或与GraphQL完全分离的层来处理的,例如OAuth。另外请注意,一个典型的身份验证流程可能需要密码,但在这个教程中,任何人都可以使用有效的电子邮件地址预订航班!

在Sandbox探查器中原型化您的变异操作

打开 您的沙盒资源管理器,然后点击加号添加新选项卡。接下来,点击模式图标返回查看您的模式,并选择 """" 以查看您的突变字段列表:

The list of available mutations

向下滚动查看登录

The definition of login in the schema

点击右侧的播放按钮在资源管理器标签页中打开该 字段。打开后,点击加号将该字段添加到您的

The login mutation after initially being added

注意红色错误指示 - 这是因为该字段的返回类型是 字段,这并不是一个 类型:您需要选择该突变将返回的用户哪些 字段。为了我们的目的,我们只需要 token 字段,所以通过点击它旁边的加号来添加它。

您还会注意到,虽然 email 好像没有默认值,但并没有自动将其作为 添加。这是因为 email 的类型是 String - 请记住,在 GraphQL 中,这意味着它 是必需的(尽管很明显,没有它您不会走得太远)。

点击 email 参数旁边的加号以将该参数添加:

The operation with the email argument

您还会注意到,沙盒资源管理器已将一个 添加到“变量”部分以匹配登录电子邮件地址。

点击“提交 ””按钮以执行您的 突变。您会看到,由于您为电子邮件地址发送 null,所以登录返回 null

Results of passing a null email

现在,将 null ”部分替换为实际的电子邮件地址:

(沙盒探索器)
{ "email": "[email protected]" }

按提交操作按钮,这次你会得到实际响应:

Results of passing an actual email

接下来,复制操作,无论是手动操作还是使用省略号菜单中的“复制操作”选项。

将突变添加到项目

现在您的突变已工作,将其添加到您的项目。创建一个命名为Login.graphql的文件,放在schema.graphqls以及其他GraphQL文件旁边,并粘贴突变的内容:

app/src/main/graphql/Login.graphql
mutation Login($email: String!) {
login(email: $email) {
token
}
}

注意:我们还将email变量标识为非空,通过在类型末尾添加!实现,因为我们始终希望传递对其的值。

构建项目生成 LoginMutation 类。

将提交按钮连接到你的突变

在登录后导航回上一屏幕,将一个 navigateBack 锋值参数添加到 Login 可组合组件:

app/src/main/java/com/example/rocketreserver/Login.kt
@Composable
fun Login(navigateBack: () -> Unit) {

再次,它应该在 MainActivity 中初始化:

app/src/main/java/com/example/rocketreserver/MainActivity.kt
composable(route = NavigationDestinations.LOGIN) {
Login(
navigateBack = {
navController.popBackStack()
}
)
}

返回到 Login.kt 并创建一个执行登录突变的函数:

app/src/main/java/com/example/rocketreserver/Login.kt
private suspend fun login(email: String): Boolean {
val response = apolloClient.mutation(LoginMutation(email = email)).execute()
return when {
response.exception != null -> {
Log.w("Login", "Failed to login", response.exception)
false
}
response.hasErrors() -> {
Log.w("Login", "Failed to login: ${response.errors?.get(0)?.message}")
false
}
response.data?.login?.token == null -> {
Log.w("Login", "Failed to login: no token returned by the backend")
false
}
else -> {
TokenRepository.setToken(response.data!!.login!!.token!!)
true
}
}
}

处理了可能的错误情况,并返回一个布尔值来指示登录是否成功。如果是,则在 TokenRepository 中保存令牌。

请注意,此函数标记为 suspend,所以需要从协程中调用。为了做到这一点,在 Login 中声明一个作用域:

app/src/main/java/com/example/rocketreserver/Login.kt
// Submit button
val scope = rememberCoroutineScope()

然后,在 onClick 锋值中,将 TODO 替换为一个对 login() 的调用,并处理结果:

app/src/main/java/com/example/rocketreserver/Login.kt
Button(
modifier = Modifier
.padding(top = 32.dp)
.fillMaxWidth(),
onClick = {
scope.launch {
val ok = login(email)
if (ok) navigateBack()
}
}
) {
Text(text = "Submit")
}

为了提高用户体验,在登录过程中显示加载指示器(同时也禁用按钮以避免多次点击)

app/src/main/java/com/example/rocketreserver/Login.kt
// Submit button
var loading by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
Button(
modifier = Modifier
.padding(top = 32.dp)
.fillMaxWidth(),
enabled = !loading,
onClick = {
loading = true
scope.launch {
val ok = login(email)
loading = false
if (ok) navigateBack()
}
}
) {
if (loading) {
Loading()
} else {
Text(text = "Submit")
}
}

测试登录

转到详情页面,点击 预订,在登录页面,输入您的电子邮件并点击 提交。现在您有一个令牌,允许您进行

The login screen

在下一节中,您将 使用受信任的操作来预订航班

上一页
8. 添加详细视图
下一页
10. 身份验证操作
评分文章评分在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.,即Apollo GraphQL。

隐私政策

公司