wip
This commit is contained in:
parent
86f4e206f4
commit
1b6ac7888b
10 changed files with 68 additions and 51 deletions
|
@ -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'],
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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'>;
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -17,6 +17,6 @@ export const packedBlockingSchema = {
|
||||||
'id',
|
'id',
|
||||||
'createdAt',
|
'createdAt',
|
||||||
'blockeeId',
|
'blockeeId',
|
||||||
'blockee',
|
//'blockee',
|
||||||
],
|
],
|
||||||
} as const satisfies JSONSchema7Definition;
|
} as const satisfies JSONSchema7Definition;
|
||||||
|
|
34
packages/misskey-js/src/schemas/error.ts
Normal file
34
packages/misskey-js/src/schemas/error.ts
Normal 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;
|
|
@ -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'>;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue