Add website api graphql endpoint
This commit is contained in:
parent
2e4357f7f8
commit
3e1f7e01f0
13 changed files with 918 additions and 33 deletions
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/backend/backend.iml" filepath="$PROJECT_DIR$/backend/backend.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
9
backend/backend.iml
Normal file
9
backend/backend.iml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
811
backend/package-lock.json
generated
811
backend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,7 @@
|
||||||
"@types/express": "^4.17.10",
|
"@types/express": "^4.17.10",
|
||||||
"@types/lodash": "^4.14.167",
|
"@types/lodash": "^4.14.167",
|
||||||
"@types/node": "^14.14.21",
|
"@types/node": "^14.14.21",
|
||||||
|
"apollo-server-fastify": "^2.19.2",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"fastify": "^3.10.1",
|
"fastify": "^3.10.1",
|
||||||
"fastify-cookie": "^5.1.0",
|
"fastify-cookie": "^5.1.0",
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
"pino-pretty": "^4.3.0",
|
"pino-pretty": "^4.3.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
|
"type-graphql": "^1.1.1",
|
||||||
"typeorm": "^0.2.30",
|
"typeorm": "^0.2.30",
|
||||||
"typescript": "^4.1.3"
|
"typescript": "^4.1.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import {
|
import {
|
||||||
|
BaseEntity,
|
||||||
Column, Entity, ObjectID, ObjectIdColumn,
|
Column, Entity, ObjectID, ObjectIdColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export default class Application {
|
export default class Application extends BaseEntity {
|
||||||
@ObjectIdColumn()
|
@ObjectIdColumn()
|
||||||
public _id!: ObjectID;
|
public _id!: ObjectID;
|
||||||
|
|
||||||
|
@ -23,9 +24,6 @@ export default class Application {
|
||||||
@Column()
|
@Column()
|
||||||
public redirectUris!: string[];
|
public redirectUris!: string[];
|
||||||
|
|
||||||
@Column()
|
|
||||||
public public!: string[];
|
|
||||||
|
|
||||||
public static generateClientId(): string {
|
public static generateClientId(): string {
|
||||||
return nanoid(12);
|
return nanoid(12);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import FastifySensible from 'fastify-sensible';
|
||||||
import FastifySession from 'fastify-session';
|
import FastifySession from 'fastify-session';
|
||||||
import database from './database/database';
|
import database from './database/database';
|
||||||
import registerOAuth from './routes/oauth2';
|
import registerOAuth from './routes/oauth2';
|
||||||
|
import registerWebsiteApi from './routes/website-api';
|
||||||
import { parseIntStrict, requireEnv } from './utils';
|
import { parseIntStrict, requireEnv } from './utils';
|
||||||
|
|
||||||
const server = Fastify({
|
const server = Fastify({
|
||||||
|
@ -28,6 +29,7 @@ async function start() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await server.register(registerOAuth, { prefix: '/api/oauth', logLevel: 'info' });
|
await server.register(registerOAuth, { prefix: '/api/oauth', logLevel: 'info' });
|
||||||
|
await server.register(registerWebsiteApi, { prefix: '/api/website', logLevel: 'info' });
|
||||||
|
|
||||||
await database.connect();
|
await database.connect();
|
||||||
server.log.info('Connected to database');
|
server.log.info('Connected to database');
|
||||||
|
|
|
@ -13,12 +13,10 @@ export default function registerAuthorize(server: MyFastifyInstance): void {
|
||||||
request,
|
request,
|
||||||
reply,
|
reply,
|
||||||
) => {
|
) => {
|
||||||
console.log(request.query);
|
|
||||||
if (!isObject(request.query)) {
|
if (!isObject(request.query)) {
|
||||||
server.log.warn('Request query is not an object');
|
server.log.warn('Request query is not an object');
|
||||||
throw server.httpErrors.badRequest();
|
throw server.httpErrors.badRequest();
|
||||||
}
|
}
|
||||||
server.log.info(JSON.stringify(request.body));
|
|
||||||
try {
|
try {
|
||||||
validateParam('client_id', request.query.client_id);
|
validateParam('client_id', request.query.client_id);
|
||||||
validateParam('redirect_uri', request.query.redirect_uri);
|
validateParam('redirect_uri', request.query.redirect_uri);
|
||||||
|
@ -63,7 +61,7 @@ export default function registerAuthorize(server: MyFastifyInstance): void {
|
||||||
sessionData.prompts.set(promptId, {
|
sessionData.prompts.set(promptId, {
|
||||||
clientId: request.query.client_id,
|
clientId: request.query.client_id,
|
||||||
redirectUri: request.query.redirect_uri,
|
redirectUri: request.query.redirect_uri,
|
||||||
scopes,
|
scopes: requestedScopes,
|
||||||
state: request.query.state,
|
state: request.query.state,
|
||||||
codeChallenge: request.query.code_challenge === undefined ? undefined : {
|
codeChallenge: request.query.code_challenge === undefined ? undefined : {
|
||||||
method: codeChallengeMethod,
|
method: codeChallengeMethod,
|
||||||
|
|
26
backend/src/routes/website-api/index.ts
Normal file
26
backend/src/routes/website-api/index.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { ApolloServer } from 'apollo-server-fastify';
|
||||||
|
import { buildSchema } from 'type-graphql';
|
||||||
|
import { ApolloContext, MyFastifyInstance } from '../../types';
|
||||||
|
import { getSessionData } from '../../utils';
|
||||||
|
import PromptInfoResolver from './resolvers/prompt-info-resolver';
|
||||||
|
import { WebsiteAPIContext } from './types';
|
||||||
|
|
||||||
|
export default async function registerWebsiteApi(server: MyFastifyInstance): Promise<void> {
|
||||||
|
const schema = await buildSchema({
|
||||||
|
authMode: 'error',
|
||||||
|
resolvers: [PromptInfoResolver],
|
||||||
|
});
|
||||||
|
const apolloServer = new ApolloServer({
|
||||||
|
schema,
|
||||||
|
context: ((context: ApolloContext): WebsiteAPIContext => ({
|
||||||
|
...context,
|
||||||
|
sessionData: getSessionData(context.request.session),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
await server.register(apolloServer.createHandler({
|
||||||
|
cors: {
|
||||||
|
origin: 'https://google.com',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
console.log(apolloServer.graphqlPath);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Field, ObjectType } from 'type-graphql';
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export default class PromptInfoApplication {
|
||||||
|
@Field(() => String)
|
||||||
|
public name!: string;
|
||||||
|
|
||||||
|
@Field(() => String, {
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public iconUrl!: string | null;
|
||||||
|
|
||||||
|
@Field(() => Boolean)
|
||||||
|
public verified!: boolean;
|
||||||
|
}
|
17
backend/src/routes/website-api/models/prompt-info.ts
Normal file
17
backend/src/routes/website-api/models/prompt-info.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { Field, ObjectType } from 'type-graphql';
|
||||||
|
import PromptInfoApplication from './prompt-info-application';
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export default class PromptInfo {
|
||||||
|
@Field(() => String)
|
||||||
|
public id!: string;
|
||||||
|
|
||||||
|
@Field(() => [String])
|
||||||
|
public scopes!: string[];
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
public clientId!: string;
|
||||||
|
|
||||||
|
@Field(() => PromptInfoApplication)
|
||||||
|
public application!: PromptInfoApplication;
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* eslint-disable class-methods-use-this */
|
||||||
|
import {
|
||||||
|
Arg, Ctx, FieldResolver, Query, Resolver, ResolverInterface, Root,
|
||||||
|
} from 'type-graphql';
|
||||||
|
import database from '../../../database/database';
|
||||||
|
import PromptInfo from '../models/prompt-info';
|
||||||
|
import PromptInfoApplication from '../models/prompt-info-application';
|
||||||
|
import { WebsiteAPIContext } from '../types';
|
||||||
|
|
||||||
|
@Resolver(PromptInfo)
|
||||||
|
export default class PromptInfoResolver implements ResolverInterface<PromptInfo> {
|
||||||
|
@Query(() => PromptInfo)
|
||||||
|
public promptInfo(
|
||||||
|
@Arg('id') id: string,
|
||||||
|
@Ctx() { sessionData }: WebsiteAPIContext,
|
||||||
|
): Partial<PromptInfo> {
|
||||||
|
const prompt = sessionData.prompts.get(id);
|
||||||
|
if (!prompt) throw new Error('Prompt data not found');
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
clientId: prompt.clientId,
|
||||||
|
scopes: prompt.scopes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver()
|
||||||
|
public async application(@Root() prompt: PromptInfo): Promise<PromptInfoApplication> {
|
||||||
|
const application = await database.applicationRepo.findOne({
|
||||||
|
where: {
|
||||||
|
clientId: prompt.clientId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!application) throw new Error('Prompt data not found');
|
||||||
|
return {
|
||||||
|
name: application.name,
|
||||||
|
iconUrl: application.iconUrl,
|
||||||
|
verified: application.verified,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
5
backend/src/routes/website-api/types.ts
Normal file
5
backend/src/routes/website-api/types.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { ApolloContext, SessionData } from '../../types';
|
||||||
|
|
||||||
|
export interface WebsiteAPIContext extends ApolloContext {
|
||||||
|
sessionData: SessionData;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import {
|
import {
|
||||||
FastifyInstance, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault,
|
FastifyInstance, FastifyRequest, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault,
|
||||||
} from 'fastify';
|
} from 'fastify';
|
||||||
|
|
||||||
export interface Prompt {
|
export interface Prompt {
|
||||||
|
@ -26,3 +26,7 @@ export interface Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MyFastifyInstance = FastifyInstance<RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>>;
|
export type MyFastifyInstance = FastifyInstance<RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>>;
|
||||||
|
|
||||||
|
export interface ApolloContext {
|
||||||
|
request: FastifyRequest;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue