This repository has been archived by the owner on Jan 7, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from ZDK-UTsukuba/develop
masterに実装をmerge
- Loading branch information
Showing
2 changed files
with
169 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,53 @@ | ||
# hello2024-backend | ||
新入生情報Web2024バックエンド | ||
|
||
## API | ||
|
||
### GET `/posts` | ||
|
||
記事一覧を返す | ||
|
||
example | ||
```json | ||
[ | ||
{ | ||
"number":971, | ||
"name":"テスト2", | ||
"created_at":"2024-02-01T22:17:30+09:00", | ||
"categories":["test"] | ||
} | ||
] | ||
``` | ||
|
||
### GET `posts/:number` | ||
|
||
記事の内容を返す | ||
|
||
example | ||
```json | ||
{ | ||
"number":971, | ||
"name":"テスト2", | ||
"created_at":"2024-02-01T22:17:30+09:00", | ||
"categories":["test"], | ||
"body":"テストの2番目のページです" | ||
} | ||
``` | ||
|
||
### GET `/faqs` | ||
|
||
FAQを返す | ||
|
||
example | ||
```json | ||
[ | ||
{ | ||
"question": "そぽたんってなんですか", | ||
"answer": "筑波山に住む妖精です。\r\nそぽ~。\r\n\r\n" | ||
}, | ||
{ | ||
"question": "筑波大学の住所を教えてください", | ||
"answer": "茨城県つくば市天王台1-1-1です。\r\n\r\n" | ||
} | ||
] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,134 @@ | ||
/** | ||
* Welcome to Cloudflare Workers! This is your first worker. | ||
* | ||
* - Run `npm run dev` in your terminal to start a development server | ||
* - Open a browser tab at http://localhost:8787/ to see your worker in action | ||
* - Run `npm run deploy` to publish your worker | ||
* | ||
* Learn more at https://developers.cloudflare.com/workers/ | ||
*/ | ||
|
||
import { Hono } from 'hono' | ||
const app = new Hono() | ||
|
||
//esaからデータを取得する関数 | ||
const getEsaContents = async (c) =>{ | ||
const cache = await c.env.KV.get('esa'); | ||
//もしキャッシュがあればそれを返す | ||
if (cache) { | ||
console.log("hit!") | ||
return JSON.parse(cache); | ||
} | ||
|
||
// esa の API を叩いてデータを取得する、特定のカテゴリに含まれ、WIP でない記事のみを絞り込み | ||
const endpoint = new URL('https://api.esa.io/v1/teams/zdk/posts'); | ||
|
||
// 記事の取得 | ||
const postCategory = 'project/2023/新情Web/記事/_production'; | ||
endpoint.searchParams.set('q', `in:${postCategory} wip:false`); | ||
|
||
const postResponse = await fetch(endpoint.href, { | ||
headers: { | ||
Authorization: `Bearer ${c.env.ESA_TOKEN}`, | ||
}, | ||
}); | ||
const postResult = await postResponse.json(); | ||
|
||
// FAQの取得 | ||
const faqFullName = 'project/2023/新情Web/FAQ'; | ||
endpoint.searchParams.set('q', `full_name:${faqFullName} wip:false`); | ||
|
||
const faqResponse = await fetch(endpoint.href, { | ||
headers: { | ||
Authorization: `Bearer ${c.env.ESA_TOKEN}`, | ||
}, | ||
}); | ||
const faqResult = await faqResponse.json(); | ||
|
||
const result = { | ||
posts: postResult, | ||
faqs: faqResult | ||
}; | ||
|
||
//KVにesaの値を保存する | ||
await c.env.KV.put('esa', JSON.stringify(result),{ | ||
//このデータは6時間キャッシュする | ||
expirationTtl: 60 * 60 * 6, | ||
}); | ||
|
||
console.log('hit no cache'); | ||
return result; | ||
} | ||
|
||
// 記事の取得 | ||
const getPosts = async (c) =>{ | ||
const data = await getEsaContents(c); | ||
return data.posts; | ||
} | ||
|
||
const cache = await c.env.KV.get('esa'); | ||
//もしキャッシュがあればそれを返す | ||
if (cache) { | ||
console.log("hit!") | ||
return JSON.parse(cache); | ||
} | ||
|
||
// esa の API を叩いてデータを取得する、特定のカテゴリに含まれ、WIP でない記事のみを絞り込み | ||
const endpoint = new URL('https://api.esa.io/v1/teams/zdk/posts'); | ||
const category = 'project/2023/新情Web/記事/_production'; | ||
endpoint.searchParams.set('q', `in:${category} wip:false`); | ||
|
||
const response = await fetch(endpoint.href, { | ||
headers: { | ||
Authorization: `Bearer ${c.env.ESA_TOKEN}`, | ||
}, | ||
}); | ||
const result = await response.json(); | ||
|
||
//KVにesaの値を保存する | ||
await c.env.KV.put('esa', JSON.stringify(result),{ | ||
//このデータは6時間キャッシュする | ||
expirationTtl: 60 * 60 * 6, | ||
}); | ||
|
||
console.log('hit no cache'); | ||
return result; | ||
// FAQの取得 | ||
const getFAQ = async (c) =>{ | ||
const data = await getEsaContents(c); | ||
return data.faqs.posts[0]; | ||
} | ||
|
||
//記事のリストを返すエンドポイント | ||
app.get('/posts',async (c) => { | ||
const data = await getPosts(c); | ||
const result = data.posts.map(({ number, name, created_at, full_name}) => { | ||
const categories = full_name.split('/').slice(5, -1); | ||
return { | ||
number, | ||
name, | ||
created_at, | ||
categories, | ||
}; | ||
}); | ||
|
||
return c.json(result); | ||
const data = await getPosts(c); | ||
const result = data.posts.map(({ number, name, created_at, full_name}) => { | ||
const categories = full_name.split('/').slice(5, -1); | ||
return { | ||
number, | ||
name, | ||
created_at, | ||
categories, | ||
}; | ||
}); | ||
|
||
return c.json(result); | ||
}); | ||
|
||
//記事の詳細を返すエンドポイント | ||
app.get('posts/:number', async(c) =>{ | ||
const number = parseInt(c.req.param('number')); | ||
const data = await getPosts(c); | ||
const post = data.posts.find((post) => post.number === number); | ||
if (!post) { | ||
return c.text('Not found', 404); | ||
} | ||
|
||
const categories = post.full_name.split('/').slice(5, -1); | ||
return c.json({ | ||
number: post.number, | ||
name: post.name, | ||
created_at: post.created_at, | ||
categories, | ||
body: post.body_md, | ||
}); | ||
app.get('/posts/:number', async(c) =>{ | ||
const number = parseInt(c.req.param('number')); | ||
const data = await getPosts(c); | ||
const post = data.posts.find((post) => post.number === number); | ||
if (!post) { | ||
return c.text('Not found', 404); | ||
} | ||
|
||
const categories = post.full_name.split('/').slice(5, -1); | ||
return c.json({ | ||
number: post.number, | ||
name: post.name, | ||
created_at: post.created_at, | ||
categories, | ||
body: post.body_md, | ||
}); | ||
}); | ||
|
||
//FAQを返すエンドポイント | ||
app.get('/faqs',async (c) => { | ||
const number = parseInt(c.req.param('number')); | ||
const data = await getFAQ(c); | ||
|
||
if (!data) { | ||
return c.text('Not found', 404); | ||
} | ||
|
||
const lines = data.body_md.split("\r\n"); | ||
const qAndAList = []; | ||
const questionRe = /^##\s(.+)\s*$/; | ||
let tmpQAndA; | ||
|
||
for(const line of lines){ | ||
const result = questionRe.exec(line); | ||
if(result !== null){ | ||
if(tmpQAndA !== undefined){ | ||
qAndAList.push(tmpQAndA); | ||
} | ||
tmpQAndA = { | ||
question: result[1], | ||
answer: "" | ||
}; | ||
}else if(tmpQAndA !== undefined){ | ||
tmpQAndA.answer = tmpQAndA.answer + line + "\r\n"; | ||
} | ||
} | ||
qAndAList.push(tmpQAndA); | ||
|
||
return c.json(qAndAList); | ||
}); | ||
|
||
|
||
export default app; |