Skip to content

Commit

Permalink
Refactor to make it easy to add new api endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
wenbinf committed Jun 14, 2023
1 parent 66d45de commit 894b06f
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 109 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
# cloudflare-pages-react-tailwind-tmpl
# Listen Notes ChatGPT Plugin

## Environment Variables

* LISTEN_API_KEY
* CHATGPT_SECRET
* NODE_VERSION
* CHATGPT_VERIFICATION_TOKEN

## How to add a new API endpoint

1. For a new endpoint, implement a new Def file in `edge-src/api-definitions`, like JustListenDef.js
2. Create a new function file under `functions/api/v2`, like just_listen.js
3. Add the new Def object to params.paths in `chatgpt-plugin/openapi.json/index.js`, like `...new JustListenDef().openApiPathSpec()`
16 changes: 16 additions & 0 deletions edge-src/api-definitions/BaseDef.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export default class BaseDef {
constructor() {
}

transformResultFunc(result) {
return {}
}

apiFunctionName() {
return ''
}

openApiPathSpec() {
return {}
}
}
116 changes: 116 additions & 0 deletions edge-src/api-definitions/JustListenDef.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import BaseDef from "./BaseDef";

export default class JustListenDef extends BaseDef {
apiFunctionName() {
return 'justListen'
}

transformResultFunc(result) {
return ({
title: result.title,
description: result.description,
image: result.image,
audio: result.audio,
audio_length_sec: result.audio_length_sec,
pub_date_ms: result.pub_date_ms,
listennotes_url: result.listennotes_url,
podcast: {
title: result.podcast.title,
publisher: result.podcast.publisher,
image: result.podcast.image,
listen_score: result.podcast.listen_score,
listen_score_global_rank: result.podcast.listen_score_global_rank,
listennotes_url: result.podcast.listennotes_url,
}
})
}

openApiPathSpec() {
const justListenEndpoint = {
get: {
operationId: 'justListen',
description: 'Get a random podcast episode, ' +
'with all necessary metadata to describe this episode and stream the audio.' +
'Recently published episodes are more likely to be fetched.',
parameters: [],
responses: {
'200': {
description: 'Returns a json object with the podcast episode data',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'title of the podcast episode',
},
description: {
type: 'string',
description: 'description of the podcast episode in html',
},
image: {
type: 'string',
description: 'image url of the podcast episode',
},
audio: {
type: 'string',
description: 'audio url of the podcast episode, used for playing the audio',
},
audio_length_sec: {
type: 'integer',
description: 'audio length of the podcast episode in seconds',
},
pub_date_ms: {
type: 'integer',
description: 'published date of the podcast episode in milliseconds of the Unix epoch',
},
listennotes_url: {
type: 'string',
description: 'the canonical url of the podcast episode on Listen Notes, ' +
'which can be used to manually share this episode',
},
podcast: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'title of the podcast that this episode belongs to',
},
publisher: {
type: 'string',
description: 'publisher of the podcast that this episode belongs to',
},
image: {
type: 'string',
description: 'image url of the podcast that this episode belongs to',
},
listen_score: {
type: 'integer',
description: 'Listen Score of the podcast that this episode belongs to, ' +
'which indicates the estimated popularity of the podcast (similar to nielsen ratings)',
},
listen_score_global_rank: {
type: 'string',
description: 'the global rank of the podcast according to Listen Score',
},
listennotes_url: {
type: 'string',
description: 'the canonical url of the podcast on Listen Notes, ' +
'which can be used to manually share this podcast',
},
},
},
},
},
},
},
},
},
},
}
return {
'/just_listen': justListenEndpoint,
}
}
}
11 changes: 6 additions & 5 deletions edge-src/common/ListenApiManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ import ResponseBuilder from "./ResponseBuilder";
const { ClientForWorkers } = require('podcast-api');

export default class ListenApiManager {
constructor(context) {
constructor(context, EndpointDef) {
const {env} = context
this.client = ClientForWorkers({
apiKey: env.LISTEN_API_KEY || null,
})

this.endpointDef = new EndpointDef()
this.responseBuilder = new ResponseBuilder(context)
}

async justListen(transformResultFunc) {
const res = await this.client.justListen()
return this.responseBuilder.getJsonResponse(transformResultFunc(res.data))
async getResponse() {
const res = await this.client[this.endpointDef.apiFunctionName()]()
return this.responseBuilder.getJsonResponse(
this.endpointDef.transformResultFunc(res.data))
}
}
21 changes: 3 additions & 18 deletions functions/api/v2/just_listen.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
import ListenApiManager from '../../../edge-src/common/ListenApiManager.js'
import JustListenDef from "../../../edge-src/api-definitions/JustListenDef";

export async function onRequestGet(context) {
const mgr = new ListenApiManager(context)
return await mgr.justListen((result) => ({
title: result.title,
description: result.description,
image: result.image,
audio: result.audio,
audio_length_sec: result.audio_length_sec,
pub_date_ms: result.pub_date_ms,
listennotes_url: result.listennotes_url,
podcast: {
title: result.podcast.title,
publisher: result.podcast.publisher,
image: result.podcast.image,
listen_score: result.podcast.listen_score,
listen_score_global_rank: result.podcast.listen_score_global_rank,
listennotes_url: result.podcast.listennotes_url,
},
}))
const mgr = new ListenApiManager(context, JustListenDef)
return await mgr.getResponse()
}
90 changes: 5 additions & 85 deletions functions/chatgpt-plugin/openapi.json/index.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,5 @@
import ResponseBuilder from "../../../edge-src/common/ResponseBuilder";

const justListenEndpoint = {
get: {
operationId: 'justListen',
description: 'Get a random podcast episode, ' +
'with all necessary metadata to describe this episode and stream the audio.' +
'Recently published episodes are more likely to be fetched.',
parameters: [],
responses: {
'200': {
description: 'Returns a json object with the podcast episode data',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'title of the podcast episode',
},
description: {
type: 'string',
description: 'description of the podcast episode in html',
},
image: {
type: 'string',
description: 'image url of the podcast episode',
},
audio: {
type: 'string',
description: 'audio url of the podcast episode, used for playing the audio',
},
audio_length_sec: {
type: 'integer',
description: 'audio length of the podcast episode in seconds',
},
pub_date_ms: {
type: 'integer',
description: 'published date of the podcast episode in milliseconds of the Unix epoch',
},
listennotes_url: {
type: 'string',
description: 'the canonical url of the podcast episode on Listen Notes, ' +
'which can be used to manually share this episode',
},
podcast: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'title of the podcast that this episode belongs to',
},
publisher: {
type: 'string',
description: 'publisher of the podcast that this episode belongs to',
},
image: {
type: 'string',
description: 'image url of the podcast that this episode belongs to',
},
listen_score: {
type: 'integer',
description: 'Listen Score of the podcast that this episode belongs to, ' +
'which indicates the estimated popularity of the podcast (similar to nielsen ratings)',
},
listen_score_global_rank: {
type: 'string',
description: 'the global rank of the podcast according to Listen Score',
},
listennotes_url: {
type: 'string',
description: 'the canonical url of the podcast on Listen Notes, ' +
'which can be used to manually share this podcast',
},
},
},
},
},
},
},
},
},
},
}
import JustListenDef from "../../../edge-src/api-definitions/JustListenDef";

// Example spec: https://platform.openai.com/docs/plugins/getting-started/openapi-definition
// - 200 characters max for each API endpoint description/summary field in API specification
Expand All @@ -100,7 +17,7 @@ const openapiSpec = (params) => ({
},
],
paths: {
'/just_listen': justListenEndpoint,
...params.paths,
},
})

Expand All @@ -109,6 +26,9 @@ export async function onRequestGet(context) {
const responseBuilder = new ResponseBuilder(context)
const params = {
baseUrl: data.baseUrl,
paths: {
...new JustListenDef().openApiPathSpec(),
},
}
return responseBuilder.getJsonResponse(openapiSpec(params))
}

0 comments on commit 894b06f

Please sign in to comment.