Add language endpoint to developer APIs (#41)

* Added languages endpoint and its tests
This commit is contained in:
David
2021-08-30 21:35:22 +02:00
committed by GitHub
parent 1b6c324560
commit 870ec2db64
11 changed files with 360 additions and 74 deletions

View File

@@ -1,21 +1,31 @@
import { ApolloServer, gql, IResolvers } from "apollo-server-micro";
import { ApolloServer, gql, IResolvers, ApolloError, UserInputError } from "apollo-server-micro";
import { NextApiHandler } from "next";
import NextCors from "nextjs-cors";
import { googleScrape, textToSpeechScrape } from "@utils/translate";
import { retrieveFromType, getName } from "@utils/language";
export const typeDefs = gql`
enum LangType {
SOURCE,
TARGET
}
type Query {
translation(source: String="auto" target: String="en" query: String!): Translation!
audio(lang: String! query: String!): Entry!
languages(type: LangType): [Language]!
}
type Translation {
source: Entry!
target: Entry!
}
type Entry {
lang: String!
text: String
audio: [Int]
lang: Language!
text: String!
audio: [Int]!
}
type Language {
code: String!
name: String!
}
`;
@@ -25,35 +35,65 @@ export const resolvers: IResolvers = {
const { source, target, query } = args;
return {
source: {
lang: source,
lang: {
code: source
},
text: query
},
target: {
lang: target
lang: {
code: target
}
}
};
},
audio(_, args) {
const { lang, query } = args;
return {
lang: args.lang,
text: args.query
lang: {
code: lang
},
text: query
};
},
languages(_, args) {
const { type } = args;
const langEntries = retrieveFromType(type?.toLocaleLowerCase());
return langEntries.map(([code, name]) => ({ code, name }));
}
},
Translation: {
async target(parent) {
const { source, target } = parent;
const { translationRes } = await googleScrape(source.lang, target.lang, source.text);
const textScrape = await googleScrape(source.lang.code, target.lang.code, source.text);
if ("errorMsg" in textScrape)
throw new ApolloError(textScrape.errorMsg);
return {
lang: target.lang,
text: translationRes
text: textScrape.translationRes
};
}
},
Entry: {
async audio(parent) {
const { lang, text } = parent;
return await textToSpeechScrape(lang, text);
const audio = await textToSpeechScrape(lang.code, text);
if (!audio)
throw new ApolloError("An error occurred while retrieving the audio");
return audio;
}
},
Language: {
name(parent) {
const { code, name } = parent;
if (name)
return name;
const newName = getName(code);
if (!newName)
throw new UserInputError("Invalid language code");
return newName;
}
}
};

View File

@@ -3,9 +3,11 @@ import NextCors from "nextjs-cors";
import { googleScrape, textToSpeechScrape } from "@utils/translate";
type Data = {
translation?: string,
audio?: number[],
error?: string
translation: string,
} | {
audio: number[]
} | {
error: string
};
const methods = ["GET"];
@@ -39,11 +41,11 @@ const handler: NextApiHandler<Data> = async (req, res) => {
: res.status(500).json({ error: "An error occurred while retrieving the audio" });
}
const { translationRes, errorMsg } = await googleScrape(source, target, query);
const textScrape = await googleScrape(source, target, query);
if (errorMsg)
return res.status(500).json({ error: errorMsg });
res.status(200).json({ translation: translationRes });
if ("errorMsg" in textScrape)
return res.status(500).json({ error: textScrape.errorMsg });
res.status(200).json({ translation: textScrape.translationRes });
}
export default handler;

View File

@@ -0,0 +1,47 @@
import { NextApiHandler } from "next";
import NextCors from "nextjs-cors";
import { retrieveFromType } from "@utils/language";
type Data = {
languages: {
code: string,
name: string
}[]
} | {
error: string
};
const methods = ["GET"];
const handler: NextApiHandler<Data> = async (req, res) => {
await NextCors(req, res, {
methods,
origin: "*",
preflightContinue: true
});
const {
query: { slug },
method
} = req;
if (slug && Array.isArray(slug) && slug.length > 1)
return res.status(404).json({ error: "Not Found" });
if (!method || !methods.includes(method)) {
res.setHeader("Allow", methods);
return res.status(405).json({ error: "Method Not Allowed" });
}
const type = slug?.[0];
if (type !== undefined && type !== "source" && type !== "target")
return res.status(400).json({ error: "Type should be 'source', 'target' or empty" });
const langEntries = retrieveFromType(type);
const languages = langEntries.map(([code, name]) => ({ code, name }));
res.status(200).json({ languages });
}
export default handler;