aboutsummaryrefslogtreecommitdiff
path: root/packages/server/src/routes/api
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2021-08-18 17:29:55 +0200
committerHampusM <hampus@hampusmat.com>2021-08-18 17:29:55 +0200
commitd1a1b7dc947063aef5f8375a6a1e03246b272c84 (patch)
treef5cb9bd6d4b5463d9d022026ac6fea87cb6ebe02 /packages/server/src/routes/api
parent6ed078de30a7bf35deace728857d1d293d59eb15 (diff)
Implemented caching for certain API endpoints, Added documentation & made backend-fixes
Diffstat (limited to 'packages/server/src/routes/api')
-rw-r--r--packages/server/src/routes/api/v1/data.ts119
-rw-r--r--packages/server/src/routes/api/v1/index.ts81
-rw-r--r--packages/server/src/routes/api/v1/repo/branches.ts37
-rw-r--r--packages/server/src/routes/api/v1/repo/index.ts35
-rw-r--r--packages/server/src/routes/api/v1/repo/log.ts56
-rw-r--r--packages/server/src/routes/api/v1/repo/map.ts24
6 files changed, 198 insertions, 154 deletions
diff --git a/packages/server/src/routes/api/v1/data.ts b/packages/server/src/routes/api/v1/data.ts
new file mode 100644
index 0000000..97f07ff
--- /dev/null
+++ b/packages/server/src/routes/api/v1/data.ts
@@ -0,0 +1,119 @@
+import {
+ LogCommit,
+ Patch as APIPatch,
+ Commit as APICommit, Tag as APITag,
+ RepositorySummary as APIRepositorySummary,
+ Repository as APIRepository,
+ BranchSummary,
+ Branch as APIBranch
+} from "api";
+import { Branch, Commit, Patch, Repository, Tag } from "../../../git";
+
+export async function getLogCommits(commits: Commit[]): Promise<LogCommit[]> {
+ return Promise.all(commits.map(async(commit: Commit) => {
+ const stats = await commit.stats();
+
+ const is_signed = await commit.isSigned();
+
+ return <LogCommit>{
+ id: commit.id,
+ author: {
+ name: commit.author().name,
+ email: commit.author().email,
+ fingerprint: await commit.author().fingerprint().catch(() => null)
+ },
+ isSigned: is_signed,
+ signatureVerified: is_signed ? await commit.verifySignature().catch(() => false) : null,
+ message: commit.message,
+ date: commit.date,
+ insertions: stats.insertions,
+ deletions: stats.deletions,
+ files_changed: stats.files_changed
+ };
+ }));
+}
+
+export async function getCommit(commit: Commit): Promise<APICommit> {
+ const stats = await commit.stats();
+
+ const is_signed = await commit.isSigned();
+
+ const patches = await (await commit.diff()).patches().catch(() => null);
+
+ return {
+ message: commit.message,
+ author: {
+ name: commit.author().name,
+ email: commit.author().email,
+ fingerprint: await commit.author().fingerprint().catch(() => null)
+ },
+ isSigned: is_signed,
+ signatureVerified: is_signed ? await commit.verifySignature().catch(() => false) : null,
+ date: commit.date,
+ insertions: stats.insertions,
+ deletions: stats.deletions,
+ files_changed: stats.files_changed,
+ too_large: Boolean(!patches),
+ diff: patches
+ ? await Promise.all(patches.map(async(patch: Patch) => {
+ return <APIPatch>{
+ additions: patch.additions,
+ deletions: patch.deletions,
+ from: patch.from,
+ to: patch.to,
+ too_large: await patch.isTooLarge(),
+ hunks: await patch.getHunks().catch(() => null)
+ };
+ }))
+ : null
+ };
+}
+
+export function getTags(tags: Tag[]): Promise<APITag[]> {
+ return Promise.all(tags.map(async(tag: Tag) => {
+ const author = await tag.author();
+ return <APITag>{
+ name: tag.name,
+ author: {
+ name: author.name,
+ email: author.email
+ },
+ date: await tag.date()
+ };
+ }));
+}
+
+export function getRepositories(repositories: Repository[]): Promise<APIRepositorySummary[]> {
+ return Promise.all(repositories.map(async repository => {
+ return <APIRepositorySummary>{
+ name: repository.name.short,
+ description: await repository.description(),
+ last_updated: (await repository.head()).date
+ };
+ }));
+}
+
+export async function getRepository(repository: Repository): Promise<APIRepository> {
+ return <APIRepository>{
+ name: repository.name.short,
+ description: await repository.description(),
+ has_readme: await (await repository.tree()).findExists("README.md")
+ };
+}
+
+export function getBranches(branches: Branch[]): BranchSummary[] {
+ return branches.map(branch => {
+ return <BranchSummary>{
+ id: branch.id,
+ name: branch.name
+ };
+ });
+}
+
+export async function getBranch(branch: Branch): Promise<APIBranch> {
+ return {
+ id: branch.id,
+ name: branch.name,
+ latest_commit: await branch.latestCommit()
+ };
+} \ No newline at end of file
diff --git a/packages/server/src/routes/api/v1/index.ts b/packages/server/src/routes/api/v1/index.ts
index 4b63435..7997b4d 100644
--- a/packages/server/src/routes/api/v1/index.ts
+++ b/packages/server/src/routes/api/v1/index.ts
@@ -1,47 +1,24 @@
-import { FastifyInstance, FastifyPluginOptions } from "fastify";
+import { FastifyPluginCallback } from "fastify";
import { Repository } from "../../../git/repository";
-import { Route } from "../../../types/fastify";
+import { FastifyPluginOptions, Route } from "../../../types/fastify";
import repo from "./repo";
import { verifyRepoName } from "../util";
-import { Info as APIInfo, RepositorySummary as APIRepositorySummary, Repository as APIRepository } from "api";
+import { Info as APIInfo } from "api";
import { ServerError } from "../../../git/error";
+import { getRepositories, getRepository } from "./data";
+import { sources } from "../../../cache";
-function setHandlers(fastify: FastifyInstance): void {
- fastify.setErrorHandler((err, req, reply) => {
- if(err.validation) {
- reply.code(400).send({ error: `${err.validation[0].dataPath} ${err.validation[0].message}` });
- return;
- }
-
- console.log(err);
-
- reply.code(500).send({ error: "Internal server error!" });
- });
- fastify.setNotFoundHandler((req, reply) => {
- reply.code(404).send({ error: "Endpoint not found!" });
- });
-}
-
-function reposEndpoints(fastify: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error) => void): void {
+const reposEndpoints: FastifyPluginCallback<FastifyPluginOptions> = (fastify, opts, done) => {
fastify.route({
method: "GET",
url: "/repos",
handler: async(req, reply) => {
- const repos = await Repository.openAll(opts.config.settings.git_dir);
-
- if(!repos) {
- reply.send({ data: [] });
- return;
- }
+ const repositories = await Repository.openAll(opts.config.settings.git_dir);
reply.send({
- data: await Promise.all(repos.map(async repository => {
- return <APIRepositorySummary>{
- name: repository.name.short,
- description: await repository.description(),
- last_updated: (await repository.head()).date
- };
- }))
+ data: await (opts.config.cache
+ ? opts.config.cache.receive(sources.RepositoriesSource, repositories)
+ : getRepositories(repositories))
});
}
});
@@ -67,20 +44,30 @@ function reposEndpoints(fastify: FastifyInstance, opts: FastifyPluginOptions, do
return;
}
- const data: APIRepository = {
- name: repository.name.short,
- description: await repository.description(),
- has_readme: await (await repository.tree()).findExists("README.md")
- };
-
- reply.send({ data: data });
+ reply.send({
+ data: await (opts.config.cache
+ ? opts.config.cache.receive(sources.RepositorySource, repository)
+ : getRepository(repository))
+ });
}
});
done();
-}
+};
+
+const api: FastifyPluginCallback<FastifyPluginOptions> = (fastify, opts, done) => {
+ fastify.setErrorHandler((err, req, reply) => {
+ if(err.validation) {
+ reply.code(400).send({ error: `${err.validation[0].dataPath} ${err.validation[0].message}` });
+ return;
+ }
-export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error) => void): void {
- setHandlers(fastify);
+ console.log(err);
+
+ reply.code(500).send({ error: "Internal server error!" });
+ });
+ fastify.setNotFoundHandler((req, reply) => {
+ reply.code(404).send({ error: "Endpoint not found!" });
+ });
fastify.route({
method: "GET",
@@ -95,8 +82,10 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do
}
});
- fastify.register(reposEndpoints, { config: { settings: opts.config.settings } });
- fastify.register(repo, { prefix: "/repos/:repo", config: { settings: opts.config.settings } });
+ fastify.register(reposEndpoints, { config: opts.config });
+ fastify.register(repo, { prefix: "/repos/:repo", config: opts.config });
done();
-} \ No newline at end of file
+};
+
+export default api; \ No newline at end of file
diff --git a/packages/server/src/routes/api/v1/repo/branches.ts b/packages/server/src/routes/api/v1/repo/branches.ts
index 99f0327..f709f4d 100644
--- a/packages/server/src/routes/api/v1/repo/branches.ts
+++ b/packages/server/src/routes/api/v1/repo/branches.ts
@@ -1,9 +1,10 @@
-import { FastifyInstance, FastifyPluginOptions } from "fastify";
+import { FastifyPluginCallback } from "fastify";
+import { sources } from "../../../../cache";
import { Branch } from "../../../../git/branch";
-import { Route } from "../../../../types/fastify";
-import { BranchSummary as APIBranchSummary, Branch as APIBranch } from "api";
+import { FastifyPluginOptions, Route } from "../../../../types/fastify";
+import { getBranch, getBranches } from "../data";
-export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error) => void): void {
+const branches: FastifyPluginCallback<FastifyPluginOptions> = (fastify, opts, done) => {
fastify.route<Route>({
method: "GET",
url: "/branches",
@@ -11,12 +12,9 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do
const branches = await req.repository.branches();
reply.send({
- data: branches.map(branch => {
- return <APIBranchSummary>{
- id: branch.id,
- name: branch.name
- };
- })
+ data: opts.config.cache
+ ? await opts.config.cache.receive(sources.BranchesSource, req.repository, branches)
+ : getBranches(branches)
});
}
});
@@ -32,22 +30,15 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do
handler: async(req, reply) => {
const branch = await Branch.lookup(req.repository, req.params.branch);
- if(!branch) {
- reply.code(404).send({ error: "Branch not found!" });
- return;
- }
-
- const data: APIBranch = {
- id: branch.id,
- name: branch.name,
- latest_commit: await branch.latestCommit()
- };
-
reply.send({
- data: data
+ data: await (opts.config.cache
+ ? opts.config.cache.receive(sources.BranchSource, req.repository, branch)
+ : getBranch(branch))
});
}
});
done();
-} \ No newline at end of file
+};
+
+export default branches; \ No newline at end of file
diff --git a/packages/server/src/routes/api/v1/repo/index.ts b/packages/server/src/routes/api/v1/repo/index.ts
index 4cd6c51..f8e01d3 100644
--- a/packages/server/src/routes/api/v1/repo/index.ts
+++ b/packages/server/src/routes/api/v1/repo/index.ts
@@ -1,15 +1,15 @@
-import { CoolFastifyRequest, Route } from "../../../../types/fastify";
-import { FastifyInstance, FastifyPluginOptions } from "fastify";
+import { CoolFastifyRequest, Route, FastifyPluginOptions } from "../../../../types/fastify";
+import { FastifyInstance, FastifyPluginCallback } from "fastify";
import { Repository } from "../../../../git/repository";
-import { Tag } from "../../../../git/tag";
import { BaseTreeEntry, BlobTreeEntry, TreeEntry } from "../../../../git/tree_entry";
import { basename } from "path";
import branches from "./branches";
import log from "./log";
import { verifyRepoName } from "../../util";
-import { Tree as APITree, Tag as APITag, TreeEntry as APITreeEntry } from "api";
+import { Tree as APITree, TreeEntry as APITreeEntry } from "api";
import { ServerError } from "../../../../git/error";
-import { commitMap } from "./map";
+import { getLogCommits, getTags } from "../data";
+import { sources } from "../../../../cache";
declare module "fastify" {
interface FastifyRequest {
@@ -48,20 +48,11 @@ async function treeEntryMap(entry: BaseTreeEntry) {
};
}
-async function tagMap(tag: Tag) {
- const author = await tag.author();
- return <APITag>{
- name: tag.name,
- author: { name: author.name, email: author.email },
- date: await tag.date()
- };
-}
-
-export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error) => void): void {
+const repo: FastifyPluginCallback<FastifyPluginOptions> = (fastify, opts, done) => {
addHooks(fastify, opts);
- fastify.register(log);
- fastify.register(branches);
+ fastify.register(log, { config: opts.config });
+ fastify.register(branches, { config: opts.config });
fastify.route<Route>({
method: "GET",
@@ -127,7 +118,7 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do
const history = await tree_entry.history(Number(req.query.count));
- reply.send({ data: await Promise.all(history.map(commitMap)) });
+ reply.send({ data: await getLogCommits(history) });
}
});
@@ -137,10 +128,14 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do
handler: async(req, reply) => {
const tags = await req.repository.tags();
reply.send({
- data: await Promise.all(tags.map(tagMap))
+ data: await (opts.config.cache
+ ? opts.config.cache.receive(sources.TagsSource, req.repository, tags)
+ : getTags(tags))
});
}
});
done();
-} \ No newline at end of file
+};
+
+export default repo; \ No newline at end of file
diff --git a/packages/server/src/routes/api/v1/repo/log.ts b/packages/server/src/routes/api/v1/repo/log.ts
index 163cf80..7ad1e11 100644
--- a/packages/server/src/routes/api/v1/repo/log.ts
+++ b/packages/server/src/routes/api/v1/repo/log.ts
@@ -1,23 +1,11 @@
-import { FastifyInstance, FastifyPluginOptions } from "fastify";
+import { FastifyPluginCallback } from "fastify";
+import { sources } from "../../../../cache";
import { Commit } from "../../../../git/commit";
-import { Patch } from "../../../../git/patch";
-import { Route } from "../../../../types/fastify";
+import { Route, FastifyPluginOptions } from "../../../../types/fastify";
import { verifySHA } from "../../util";
-import { Patch as APIPatch, Commit as APICommit } from "api";
-import { commitMap } from "./map";
+import { getCommit, getLogCommits } from "../data";
-async function patchMap(patch: Patch) {
- return <APIPatch>{
- additions: patch.additions,
- deletions: patch.deletions,
- from: patch.from,
- to: patch.to,
- too_large: await patch.isTooLarge(),
- hunks: await patch.getHunks()
- };
-}
-
-export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error) => void): void {
+const log: FastifyPluginCallback<FastifyPluginOptions> = (fastify, opts, done) => {
fastify.route<Route>({
method: "GET",
url: "/log",
@@ -27,10 +15,12 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do
}
},
handler: async(req, reply) => {
- const commits = await req.repository.commits(Number(req.query.count));
+ const commits = await req.repository.commits(Number(req.query.count) || undefined);
reply.send({
- data: await Promise.all(commits.map(commitMap))
+ data: await (opts.config.cache
+ ? opts.config.cache.receive(sources.LogCommitsSource, req.repository, Number(req.query.count) || undefined)
+ : getLogCommits(commits))
});
}
});
@@ -51,31 +41,15 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do
const commit = await Commit.lookup(req.repository, req.params.commit);
- const stats = await commit.stats();
-
- const is_signed = await commit.isSigned();
-
- const data: APICommit = {
- message: commit.message,
- author: {
- name: commit.author().name,
- email: commit.author().email,
- fingerprint: await commit.author().fingerprint().catch(() => null)
- },
- isSigned: is_signed,
- signatureVerified: is_signed ? await commit.verifySignature().catch(() => false) : null,
- date: commit.date,
- insertions: stats.insertions,
- deletions: stats.deletions,
- files_changed: stats.files_changed,
- diff: await Promise.all((await (await commit.diff()).patches()).map(patchMap))
- };
-
reply.send({
- data: data
+ data: await (opts.config.cache
+ ? opts.config.cache.receive(sources.CommitSource, req.repository, commit)
+ : getCommit(commit))
});
}
});
done();
-} \ No newline at end of file
+};
+
+export default log; \ No newline at end of file
diff --git a/packages/server/src/routes/api/v1/repo/map.ts b/packages/server/src/routes/api/v1/repo/map.ts
deleted file mode 100644
index a544d1a..0000000
--- a/packages/server/src/routes/api/v1/repo/map.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Commit } from "../../../../git/commit";
-import { LogCommit } from "api";
-
-export async function commitMap(commit: Commit): Promise<LogCommit> {
- const stats = await commit.stats();
-
- const is_signed = await commit.isSigned();
-
- return <LogCommit>{
- id: commit.id,
- author: {
- name: commit.author().name,
- email: commit.author().email,
- fingerprint: await commit.author().fingerprint().catch(() => null)
- },
- isSigned: is_signed,
- signatureVerified: is_signed ? await commit.verifySignature().catch(() => false) : null,
- message: commit.message,
- date: commit.date,
- insertions: stats.insertions,
- deletions: stats.deletions,
- files_changed: stats.files_changed
- };
-} \ No newline at end of file