Skip to content

Commit 5960b44

Browse files
committed
Use cloudflare worker to proxy api calls
Signed-off-by: Jay Wang <[email protected]>
1 parent 40c9d81 commit 5960b44

11 files changed

+543
-5
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"typescript": "^5.4.5",
3030
"vite": "^5.2.12",
3131
"vite-plugin-dts": "^3.9.1",
32-
"vite-plugin-web-components-hmr": "^0.1.3"
32+
"vite-plugin-web-components-hmr": "^0.1.3",
33+
"wrangler": "^3.64.0"
3334
}
3435
}

src/api/semantic-scholar.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ const authorCitationSearchMocks = [
4141
authorCitationSearchMockJSON9 as SemanticAuthorDetail[]
4242
];
4343

44+
const proxyFetch = (url: string, options?: RequestInit) => {
45+
const proxyUrl = 'https://recrec-api.jay-8dc.workers.dev';
46+
const newURL = `${proxyUrl}?proxyUrl=${encodeURIComponent(url)}`;
47+
return fetch(newURL, options);
48+
};
49+
4450
/**
4551
* Searches for an author by name using the Semantic Scholar API.
4652
* @param query - The name of the author to search for.
@@ -52,7 +58,7 @@ export const searchAuthorByName = async (
5258
): Promise<SemanticAuthorSearchResponse> => {
5359
const baseURL = 'https://api.semanticscholar.org/graph/v1/author/search';
5460
const url = `${baseURL}?query=${encodeURIComponent(query)}`;
55-
const result = await fetch(url);
61+
const result = await proxyFetch(url);
5662
if (!result.ok) {
5763
throw Error(`Search request failed with status: ${result.statusText}`);
5864
}
@@ -104,7 +110,7 @@ export const searchAuthorDetails = async (
104110

105111
// Fetch the author details
106112
try {
107-
const response = await fetch(url, options);
113+
const response = await proxyFetch(url, options);
108114
const data = (await response.json()) as SemanticAuthorDetail[];
109115

110116
// downloadJSON(data, null, 'author.json');
@@ -137,7 +143,7 @@ export const getAllPapersFromAuthor = async (authorID: string) => {
137143
const url = `${baseURL}?${encodedParameters.toString()}`;
138144

139145
// Fetch the paper details
140-
const response = await fetch(url);
146+
const response = await proxyFetch(url);
141147
if (!response.ok) {
142148
throw Error(
143149
`Fetch error when getting paper details, status: ${response.status}`
@@ -189,7 +195,7 @@ export const getPaperCitations = async (paperIDs: string[]) => {
189195
const url = `${baseURL}?${encodedParameters.toString()}`;
190196

191197
// Fetch the author details
192-
const response = await fetch(url, options);
198+
const response = await proxyFetch(url, options);
193199
if (!response.ok) {
194200
throw Error(
195201
`Fetch error when getting author details, status: ${response.status}`

src/recrec-api/.editorconfig

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# http://editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = tab
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true
10+
11+
[*.yml]
12+
indent_style = space

src/recrec-api/.eslintrc.cjs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
module.exports = {
18+
root: true,
19+
parser: '@typescript-eslint/parser',
20+
extends: [
21+
'eslint:recommended',
22+
'plugin:@typescript-eslint/recommended',
23+
'plugin:@typescript-eslint/recommended-requiring-type-checking',
24+
'plugin:wc/recommended',
25+
'plugin:lit/recommended',
26+
'prettier'
27+
],
28+
parserOptions: {
29+
ecmaVersion: 'latest',
30+
sourceType: 'module',
31+
tsconfigRootDir: __dirname,
32+
project: ['./tsconfig.json', './tsconfig.node.json'],
33+
extraFileExtensions: ['.cjs']
34+
},
35+
env: {
36+
es6: true,
37+
browser: true
38+
},
39+
plugins: ['lit', '@typescript-eslint', 'prettier'],
40+
ignorePatterns: ['node_modules'],
41+
rules: {
42+
indent: 'off',
43+
'linebreak-style': ['error', 'unix'],
44+
quotes: ['error', 'single', { avoidEscape: true }],
45+
'prefer-const': ['error'],
46+
semi: ['error', 'always'],
47+
// 'max-len': [
48+
// 'warn',
49+
// {
50+
// code: 80
51+
// }
52+
// ],
53+
'no-constant-condition': ['error', { checkLoops: false }],
54+
'prettier/prettier': 2,
55+
'@typescript-eslint/ban-ts-comment': 'off',
56+
'@typescript-eslint/restrict-template-expressions': 'off',
57+
'@typescript-eslint/no-non-null-assertion': 'off',
58+
'@typescript-eslint/no-empty-function': 'off',
59+
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
60+
'@typescript-eslint/no-unused-vars': [
61+
'warn',
62+
{
63+
argsIgnorePattern: '^_',
64+
varsIgnorePattern: '^_',
65+
caughtErrorsIgnorePattern: '^_'
66+
}
67+
],
68+
'no-self-assign': 'off'
69+
}
70+
};

src/recrec-api/.gitignore

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Logs
2+
3+
logs
4+
_.log
5+
npm-debug.log_
6+
yarn-debug.log*
7+
yarn-error.log*
8+
lerna-debug.log*
9+
.pnpm-debug.log*
10+
11+
# Diagnostic reports (https://nodejs.org/api/report.html)
12+
13+
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
14+
15+
# Runtime data
16+
17+
pids
18+
_.pid
19+
_.seed
20+
\*.pid.lock
21+
22+
# Directory for instrumented libs generated by jscoverage/JSCover
23+
24+
lib-cov
25+
26+
# Coverage directory used by tools like istanbul
27+
28+
coverage
29+
\*.lcov
30+
31+
# nyc test coverage
32+
33+
.nyc_output
34+
35+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
36+
37+
.grunt
38+
39+
# Bower dependency directory (https://bower.io/)
40+
41+
bower_components
42+
43+
# node-waf configuration
44+
45+
.lock-wscript
46+
47+
# Compiled binary addons (https://nodejs.org/api/addons.html)
48+
49+
build/Release
50+
51+
# Dependency directories
52+
53+
node_modules/
54+
jspm_packages/
55+
56+
# Snowpack dependency directory (https://snowpack.dev/)
57+
58+
web_modules/
59+
60+
# TypeScript cache
61+
62+
\*.tsbuildinfo
63+
64+
# Optional npm cache directory
65+
66+
.npm
67+
68+
# Optional eslint cache
69+
70+
.eslintcache
71+
72+
# Optional stylelint cache
73+
74+
.stylelintcache
75+
76+
# Microbundle cache
77+
78+
.rpt2_cache/
79+
.rts2_cache_cjs/
80+
.rts2_cache_es/
81+
.rts2_cache_umd/
82+
83+
# Optional REPL history
84+
85+
.node_repl_history
86+
87+
# Output of 'npm pack'
88+
89+
\*.tgz
90+
91+
# Yarn Integrity file
92+
93+
.yarn-integrity
94+
95+
# dotenv environment variable files
96+
97+
.env
98+
.env.development.local
99+
.env.test.local
100+
.env.production.local
101+
.env.local
102+
103+
# parcel-bundler cache (https://parceljs.org/)
104+
105+
.cache
106+
.parcel-cache
107+
108+
# Next.js build output
109+
110+
.next
111+
out
112+
113+
# Nuxt.js build / generate output
114+
115+
.nuxt
116+
dist
117+
118+
# Gatsby files
119+
120+
.cache/
121+
122+
# Comment in the public line in if your project uses Gatsby and not Next.js
123+
124+
# https://nextjs.org/blog/next-9-1#public-directory-support
125+
126+
# public
127+
128+
# vuepress build output
129+
130+
.vuepress/dist
131+
132+
# vuepress v2.x temp and cache directory
133+
134+
.temp
135+
.cache
136+
137+
# Docusaurus cache and generated files
138+
139+
.docusaurus
140+
141+
# Serverless directories
142+
143+
.serverless/
144+
145+
# FuseBox cache
146+
147+
.fusebox/
148+
149+
# DynamoDB Local files
150+
151+
.dynamodb/
152+
153+
# TernJS port file
154+
155+
.tern-port
156+
157+
# Stores VSCode versions used for testing VSCode extensions
158+
159+
.vscode-test
160+
161+
# yarn v2
162+
163+
.yarn/cache
164+
.yarn/unplugged
165+
.yarn/build-state.yml
166+
.yarn/install-state.gz
167+
.pnp.\*
168+
169+
# wrangler project
170+
171+
.dev.vars
172+
.wrangler/

src/recrec-api/.prettierrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"printWidth": 140,
3+
"singleQuote": true,
4+
"semi": true,
5+
"useTabs": false
6+
}

src/recrec-api/package.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "recrec-api",
3+
"version": "0.0.0",
4+
"private": true,
5+
"scripts": {
6+
"deploy": "wrangler deploy",
7+
"dev": "wrangler dev",
8+
"start": "wrangler dev",
9+
"cf-typegen": "wrangler types"
10+
},
11+
"devDependencies": {
12+
"@cloudflare/workers-types": "^4.20240701.0",
13+
"itty-router": "^3.0.12",
14+
"typescript": "^5.5.2",
15+
"wrangler": "^3.60.3"
16+
}
17+
}

src/recrec-api/src/index.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Welcome to Cloudflare Workers! This is your first worker.
3+
*
4+
* - Run `npm run dev` in your terminal to start a development server
5+
* - Open a browser tab at http://localhost:8787/ to see your worker in action
6+
* - Run `npm run deploy` to publish your worker
7+
*
8+
* Bind resources to your worker in `wrangler.toml`. After adding bindings, a type definition for the
9+
* `Env` object can be regenerated with `npm run cf-typegen`.
10+
*
11+
* Learn more at https://developers.cloudflare.com/workers/
12+
*/
13+
14+
export interface Env {
15+
SEMANTIC_API: string;
16+
}
17+
18+
export default {
19+
async fetch(request, env, ctx): Promise<Response> {
20+
const url = new URL(request.url);
21+
const proxyUrl = url.searchParams.get('proxyUrl'); // get a query param value (?proxyUrl=...)
22+
23+
if (!proxyUrl) {
24+
return new Response('Bad request: Missing `proxyUrl` query param', { status: 400 });
25+
}
26+
27+
const newRequest = new Request(request, {
28+
headers: {
29+
...request.headers,
30+
'x-api-key': `${env.SEMANTIC_API}`,
31+
},
32+
body: request.body,
33+
});
34+
35+
// make subrequests with the global `fetch()` function
36+
const res = await fetch(proxyUrl, newRequest);
37+
38+
return res;
39+
},
40+
} satisfies ExportedHandler<Env>;

0 commit comments

Comments
 (0)