mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
refactor(server): server errors (#5741)
standardize the error raising in both GraphQL Resolvers and Controllers.
Now, All user aware errors should be throwed with `HttpException`'s variants, for example `NotFoundException`.
> Directly throwing `GraphQLError` are forbidden.
The GraphQL errorFormatter will handle it automatically and set `code`, `status` in error extensions.
At the same time, the frontend `GraphQLError` should be imported from `@affine/graphql`, which introduce a better error extensions type.
----
controller example:
```js
@Get('/docs/${id}')
doc() {
// ...
// imported from '@nestjs/common'
throw new NotFoundException('Doc is not found.');
// ...
}
```
the above will response as:
```
status: 404 Not Found
{
"message": "Doc is not found.",
"statusCode": 404,
"error": "Not Found"
}
```
resolver example:
```js
@Mutation()
invite() {
// ...
throw new PayloadTooLargeException('Workspace seats is full.')
// ...
}
```
the above will response as:
```
status: 200 Ok
{
"data": null,
"errors": [
{
"message": "Workspace seats is full.",
"extensions": {
"code": 404,
"status": "Not Found"
}
}
]
}
```
for frontend GraphQLError user-friend, a helper function introduced:
```js
import { findGraphQLError } from '@affine/graphql'
fetch(query)
.catch(errOrArr => {
const e = findGraphQLError(errOrArr, e => e.extensions.code === 404)
if (e) {
// handle
}
})
```
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import { HttpStatus } from '@nestjs/common';
|
||||
import {
|
||||
BadGatewayException,
|
||||
ForbiddenException,
|
||||
InternalServerErrorException,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
Args,
|
||||
Context,
|
||||
@@ -13,7 +17,6 @@ import {
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
import type { User, UserInvoice, UserSubscription } from '@prisma/client';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import { groupBy } from 'lodash-es';
|
||||
|
||||
import { Auth, CurrentUser, Public } from '../../core/auth';
|
||||
@@ -164,12 +167,9 @@ export class SubscriptionResolver {
|
||||
);
|
||||
|
||||
if (!yearly || !monthly) {
|
||||
throw new GraphQLError('The prices are not configured correctly', {
|
||||
extensions: {
|
||||
status: HttpStatus[HttpStatus.BAD_GATEWAY],
|
||||
code: HttpStatus.BAD_GATEWAY,
|
||||
},
|
||||
});
|
||||
throw new InternalServerErrorException(
|
||||
'The prices are not configured correctly.'
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -199,12 +199,7 @@ export class SubscriptionResolver {
|
||||
});
|
||||
|
||||
if (!session.url) {
|
||||
throw new GraphQLError('Failed to create checkout session', {
|
||||
extensions: {
|
||||
status: HttpStatus[HttpStatus.BAD_GATEWAY],
|
||||
code: HttpStatus.BAD_GATEWAY,
|
||||
},
|
||||
});
|
||||
throw new BadGatewayException('Failed to create checkout session.');
|
||||
}
|
||||
|
||||
return session.url;
|
||||
@@ -263,14 +258,8 @@ export class UserSubscriptionResolver {
|
||||
) {
|
||||
// allow admin to query other user's subscription
|
||||
if (!ctx.isAdminQuery && me.id !== user.id) {
|
||||
throw new GraphQLError(
|
||||
'You are not allowed to access this subscription',
|
||||
{
|
||||
extensions: {
|
||||
status: HttpStatus[HttpStatus.FORBIDDEN],
|
||||
code: HttpStatus.FORBIDDEN,
|
||||
},
|
||||
}
|
||||
throw new ForbiddenException(
|
||||
'You are not allowed to access this subscription.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -310,12 +299,9 @@ export class UserSubscriptionResolver {
|
||||
@Args('skip', { type: () => Int, nullable: true }) skip?: number
|
||||
) {
|
||||
if (me.id !== user.id) {
|
||||
throw new GraphQLError('You are not allowed to access this invoices', {
|
||||
extensions: {
|
||||
status: HttpStatus[HttpStatus.FORBIDDEN],
|
||||
code: HttpStatus.FORBIDDEN,
|
||||
},
|
||||
});
|
||||
throw new ForbiddenException(
|
||||
'You are not allowed to access this invoices'
|
||||
);
|
||||
}
|
||||
|
||||
return this.db.userInvoice.findMany({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createAdapter } from '@socket.io/redis-adapter';
|
||||
import { Redis } from 'ioredis';
|
||||
import { Server, ServerOptions } from 'socket.io';
|
||||
|
||||
import { SocketIoAdapter } from '../../fundamentals';
|
||||
import { SocketIoAdapter } from '../../fundamentals/websocket';
|
||||
|
||||
export function createSockerIoAdapterImpl(
|
||||
redis: Redis
|
||||
|
||||
Reference in New Issue
Block a user