This commit is contained in:
tamaina 2023-05-22 05:20:19 +00:00
parent 86f4e206f4
commit 1b6ac7888b
10 changed files with 68 additions and 51 deletions

View file

@ -38,7 +38,7 @@ export function genOpenapiSpec(config: Config) {
}, },
}; };
for (const [name, endpoint] of Object.entries(endpoints).filter(([name, ep]) => !ep.secure)) { for (const [name, endpoint] of Object.entries(endpoints).filter(([name, ep]) => !('secure' in ep) || !ep.secure)) {
const errors = {} as any; const errors = {} as any;
if ('errors' in endpoint && endpoint.errors) { if ('errors' in endpoint && endpoint.errors) {
@ -107,7 +107,7 @@ export function genOpenapiSpec(config: Config) {
content: { content: {
'application/json': { 'application/json': {
schema: { schema: {
$ref: '#/components/schemas/Error', $ref: '#/components/schemas/ApiError',
}, },
examples: { ...errors, ...basicErrors['400'] }, examples: { ...errors, ...basicErrors['400'] },
}, },
@ -118,7 +118,7 @@ export function genOpenapiSpec(config: Config) {
content: { content: {
'application/json': { 'application/json': {
schema: { schema: {
$ref: '#/components/schemas/Error', $ref: '#/components/schemas/ApiError',
}, },
examples: basicErrors['401'], examples: basicErrors['401'],
}, },
@ -129,7 +129,7 @@ export function genOpenapiSpec(config: Config) {
content: { content: {
'application/json': { 'application/json': {
schema: { schema: {
$ref: '#/components/schemas/Error', $ref: '#/components/schemas/ApiError',
}, },
examples: basicErrors['403'], examples: basicErrors['403'],
}, },
@ -140,7 +140,7 @@ export function genOpenapiSpec(config: Config) {
content: { content: {
'application/json': { 'application/json': {
schema: { schema: {
$ref: '#/components/schemas/Error', $ref: '#/components/schemas/ApiError',
}, },
examples: basicErrors['418'], examples: basicErrors['418'],
}, },
@ -152,7 +152,7 @@ export function genOpenapiSpec(config: Config) {
content: { content: {
'application/json': { 'application/json': {
schema: { schema: {
$ref: '#/components/schemas/Error', $ref: '#/components/schemas/ApiError',
}, },
examples: basicErrors['429'], examples: basicErrors['429'],
}, },
@ -164,7 +164,7 @@ export function genOpenapiSpec(config: Config) {
content: { content: {
'application/json': { 'application/json': {
schema: { schema: {
$ref: '#/components/schemas/Error', $ref: '#/components/schemas/ApiError',
}, },
examples: basicErrors['500'], examples: basicErrors['500'],
}, },

View file

@ -1,32 +1,5 @@
import { refs } from 'misskey-js/built/schemas.js'; import { refs } from 'misskey-js/built/schemas.js';
export const schemas = { export const schemas = {
Error: {
type: 'object',
properties: {
error: {
type: 'object',
description: 'An error object.',
properties: {
code: {
type: 'string',
description: 'An error code. Unique within the endpoint.',
},
message: {
type: 'string',
description: 'An error message.',
},
id: {
type: 'string',
format: 'uuid',
description: 'An error ID. This ID is static.',
},
},
required: ['code', 'id', 'message'],
},
},
required: ['error'],
},
...refs, ...refs,
}; };

View file

@ -3,7 +3,6 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert'; import * as assert from 'assert';
import { inspect } from 'node:util'; import { inspect } from 'node:util';
import { DEFAULT_POLICIES } from '@/core/RoleService.js'; import { DEFAULT_POLICIES } from '@/core/RoleService.js';
import type { Packed } from '@/misc/json-schema.js';
import { import {
signup, signup,
post, post,
@ -19,6 +18,7 @@ import {
} from '../utils.js'; } from '../utils.js';
import type * as misskey from 'misskey-js'; import type * as misskey from 'misskey-js';
import type { INestApplicationContext } from '@nestjs/common'; import type { INestApplicationContext } from '@nestjs/common';
import { WeakSerialized } from 'schema-type';
const compareBy = <T extends { id: string }>(selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => { const compareBy = <T extends { id: string }>(selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => {
return selector(a).localeCompare(selector(b)); return selector(a).localeCompare(selector(b));
@ -28,12 +28,9 @@ describe('アンテナ', () => {
// エンティティとしてのアンテナを主眼においたテストを記述する // エンティティとしてのアンテナを主眼においたテストを記述する
// (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからートを取得するエンドポイントをテストする) // (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからートを取得するエンドポイントをテストする)
// BUG misskey-jsとjson-schemaが一致していない。 type Antenna = WeakSerialized<misskey.entities.Antenna>;
// - srcのenumにgroupが残っている type User = WeakSerialized<misskey.entities.MeDetailed & { token: string }>;
// - userGroupIdが残っている, isActiveがない type Note = WeakSerialized<misskey.entities.Note>;
type Antenna = misskey.entities.Antenna | Packed<'Antenna'>;
type User = misskey.entities.MeDetailed & { token: string };
type Note = misskey.entities.Note;
// アンテナを作成できる最小のパラメタ // アンテナを作成できる最小のパラメタ
const defaultParam = { const defaultParam = {

View file

@ -10,6 +10,7 @@ import { DEFAULT_POLICIES } from '@/core/RoleService.js';
import { entities } from '../src/postgres.js'; import { entities } from '../src/postgres.js';
import { loadConfig } from '../src/config.js'; import { loadConfig } from '../src/config.js';
import type * as misskey from 'misskey-js'; import type * as misskey from 'misskey-js';
import { SchemaOrUndefined } from 'misskey-js/built/endpoints.types.js';
export { server as startServer } from '@/boot/common.js'; export { server as startServer } from '@/boot/common.js';
@ -25,15 +26,18 @@ export const api = async (endpoint: string, params: any, me?: any) => {
return await request(`api/${normalized}`, params, me); return await request(`api/${normalized}`, params, me);
}; };
export type ApiRequest = { export type ApiRequest<X extends keyof misskey.Endpoints = keyof misskey.Endpoints, D extends misskey.Endpoints[X]['defines'][number] = misskey.Endpoints[X]['defines'][number], P extends D['req'] = D['req']> = {
endpoint: string, endpoint: X,
parameters: object, parameters: SchemaOrUndefined<P>,
user: object | undefined, user: object | undefined,
}; };
export const successfulApiCall = async <T, >(request: ApiRequest, assertion: { export const successfulApiCall = async <X extends keyof misskey.Endpoints, D extends misskey.Endpoints[X]['defines'][number] = misskey.Endpoints[X]['defines'][number]>(
request: ApiRequest<X, D>,
assertion: {
status?: number, status?: number,
} = {}): Promise<T> => { } = {}
): Promise<SchemaOrUndefined<D['res']>> => {
const { endpoint, parameters, user } = request; const { endpoint, parameters, user } = request;
const res = await api(endpoint, parameters, user); const res = await api(endpoint, parameters, user);
const status = assertion.status ?? (res.body == null ? 204 : 200); const status = assertion.status ?? (res.body == null ? 204 : 200);
@ -41,11 +45,11 @@ export const successfulApiCall = async <T, >(request: ApiRequest, assertion: {
return res.body; return res.body;
}; };
export const failedApiCall = async <T, >(request: ApiRequest, assertion: { export const failedApiCall = async <X extends keyof misskey.Endpoints>(request: ApiRequest<X>, assertion: {
status: number, status: number,
code: string, code: string,
id: string id: string
}): Promise<T> => { }): Promise<misskey.Packed<'Error#/$defs/Error'>> => {
const { endpoint, parameters, user } = request; const { endpoint, parameters, user } = request;
const { status, code, id } = assertion; const { status, code, id } = assertion;
const res = await api(endpoint, parameters, user); const res = await api(endpoint, parameters, user);

View file

@ -7,6 +7,7 @@ type TODO = Record<string, any>;
// NOTE: 極力この型を使うのは避け、UserLite か UserDetailed か明示するように // NOTE: 極力この型を使うのは避け、UserLite か UserDetailed か明示するように
export type User = Packed<'User'>; export type User = Packed<'User'>;
export type UserLite = Packed<'UserLite'>; export type UserLite = Packed<'UserLite'>;
export type UserDetailed = Packed<'UserDetailed'>; export type UserDetailed = Packed<'UserDetailed'>;
export type UserList = Packed<'UserList'>; export type UserList = Packed<'UserList'>;

View file

@ -35,6 +35,7 @@ import { packedEmojiDetailedSchema, packedEmojiSimpleSchema } from './schemas/em
import { packedFlashSchema } from './schemas/flash.js'; import { packedFlashSchema } from './schemas/flash.js';
import { packedAdSchema } from './schemas/ad.js'; import { packedAdSchema } from './schemas/ad.js';
import { packedAnnouncementSchema } from './schemas/announcement.js'; import { packedAnnouncementSchema } from './schemas/announcement.js';
import { Error, ApiError } from './schemas/error.js';
import type { JSONSchema7, JSONSchema7Definition, GetDef, GetRefs, GetKeys, UnionToArray } from 'schema-type'; import type { JSONSchema7, JSONSchema7Definition, GetDef, GetRefs, GetKeys, UnionToArray } from 'schema-type';
export const refs = { export const refs = {
@ -74,6 +75,9 @@ export const refs = {
Flash: packedFlashSchema, Flash: packedFlashSchema,
Ad: packedAdSchema, Ad: packedAdSchema,
Announcement: packedAnnouncementSchema, Announcement: packedAnnouncementSchema,
Error: Error,
ApiError: ApiError,
} as const satisfies { [x: string]: JSONSchema7Definition }; } as const satisfies { [x: string]: JSONSchema7Definition };
export type References = GetRefs<typeof refs>; export type References = GetRefs<typeof refs>;

View file

@ -17,6 +17,6 @@ export const packedBlockingSchema = {
'id', 'id',
'createdAt', 'createdAt',
'blockeeId', 'blockeeId',
'blockee', //'blockee',
], ],
} as const satisfies JSONSchema7Definition; } as const satisfies JSONSchema7Definition;

View file

@ -0,0 +1,34 @@
import type { JSONSchema7Definition } from 'schema-type';
export const Error = {
$id: 'https://misskey-hub.net/api/schemas/Error',
type: 'object',
description: 'An error object.',
properties: {
code: {
type: 'string',
description: 'An error code. Unique within the endpoint.',
},
message: {
type: 'string',
description: 'An error message.',
},
id: {
type: 'string',
format: 'uuid',
description: 'An error ID. This ID is static.',
},
},
required: ['code', 'id', 'message'],
} as const satisfies JSONSchema7Definition;
export const ApiError = {
$id: 'https://misskey-hub.net/api/schemas/ApiError',
type: 'object',
properties: {
error: { $ref: 'https://misskey-hub.net/api/schemas/Error' },
},
required: ['error'],
} as const satisfies JSONSchema7Definition;

View file

@ -97,4 +97,8 @@ describe('schemas', () => {
test('ad', () => { test('ad', () => {
type Ad = Packed<'Ad'>; type Ad = Packed<'Ad'>;
}); });
test('error', () => {
type Error = Packed<'Error'>;
type ApiError = Packed<'ApiError'>;
});
}); });

View file

@ -20,7 +20,7 @@ describe('schemas', () => {
} }
}); });
test('jointed schema (oneOf)', () => { test('jointed schema', () => {
const req = getEndpointSchema('req', key as keyof Endpoints); const req = getEndpointSchema('req', key as keyof Endpoints);
if (req) ajv.compile(req); if (req) ajv.compile(req);
}); });