Skip to content

Commit

Permalink
Merge pull request #414 from sfrunza13/issue-410-sf
Browse files Browse the repository at this point in the history
issue410 on first click searchbar shows top 5 subreddits by popularity
  • Loading branch information
gregrickaby authored Oct 30, 2022
2 parents 7e6af92 + 2debcc6 commit 756af7c
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 1 deletion.
3 changes: 2 additions & 1 deletion components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export default function Search() {
const {setSubreddit, searchInput, setSearchInput} = useRedditContext()
const {classes} = useStyles()
const [debounced] = useDebouncedValue(searchInput, 300)
const {data: beforeSearch} = useSWR(`/api/preSearch?limit=5`, fetcher)
const {data: results} = useSWR(`/api/search?term=${debounced}`, fetcher, {
revalidateIfStale: true,
revalidateOnFocus: false,
Expand All @@ -63,7 +64,7 @@ export default function Search() {
<Autocomplete
aria-label="Search sub-reddits"
className={classes.searchBar}
data={results ? results : []}
data={results ? results : beforeSearch ? beforeSearch : []}
icon={<IconSearch />}
itemComponent={AutoCompleteItem}
nothingFound="No subs found. Start typing to search."
Expand Down
138 changes: 138 additions & 0 deletions pages/api/preSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import type {NextRequest} from 'next/server'

export const config = {
runtime: 'experimental-edge'
}

/**
* Popular Subreddit Reddit API.
*
* @example
* /api/preSearch?limit=5
*
* @see https://www.reddit.com/dev/api#GET_subreddits_{where}
* @see https://nextjs.org/docs/api-routes/edge-api-routes
* @see https://nextjs.org/docs/api-reference/edge-runtime
*/
export default async function search(req: NextRequest) {
// Parse and sanitize query params from request.
const limit = req.nextUrl.searchParams.get('limit') || '5'

try {
// Generate random device ID.
// @see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
const array = new Uint32Array(24)
const deviceId = self.crypto.getRandomValues(array)

// Try and fetch a new access token.
const tokenResponse = await fetch(
`https://www.reddit.com/api/v1/access_token?grant_type=client_credentials&device_id=${deviceId}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json charset=UTF-8',
'User-Agent': 'reddit-image-viewer/* by Greg Rickaby',
Authorization: `Basic ${btoa(
`${process.env.REDDIT_CLIENT_ID}:${process.env.REDDIT_CLIENT_SECRET}`
)}`
}
}
)

// Bad response? Bail...
if (tokenResponse.status != 200) {
return new Response(
JSON.stringify({
error: `${tokenResponse.statusText}`
}),
{
status: tokenResponse.status,
statusText: tokenResponse.statusText
}
)
}

// Get the access token.
const token = await tokenResponse.json()

// Issue with token? Bail...
if (token.error) {
return new Response(
JSON.stringify({
error: token.error
}),
{
status: token.status,
statusText: token.statusText
}
)
}

// Attempt to fetch subreddits.
const response = await fetch(
`https://oauth.reddit.com/subreddits/popular?limit=${limit}`,
{
headers: {
authorization: `Bearer ${token.access_token}`
}
}
)

// No response? Bail...
if (response.status != 200) {
return new Response(
JSON.stringify({
error: `${response.statusText}`
}),
{
status: response.status,
statusText: response.statusText
}
)
}

// Parse the response.
const subs = await response.json()

// No data in the response? Bail...
if (!subs.data && !subs.data.children.length) {
return new Response(
JSON.stringify({
error: `No data returned from Reddit.`
}),
{
status: 400,
statusText: 'Bad Request'
}
)
}

// Filter uneeded data to keep the payload small.
const filtered = subs.data.children.map(
(sub: {data: {over18?: string; url?: string; display_name?: string}}) => {
return {
over_18: sub.data.over18 ? true : false,
url: sub.data.url ? sub.data.url : '',
value: sub.data.display_name ? sub.data.display_name : ''
}
}
)

// Send the response.
return new Response(JSON.stringify(filtered), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, s-maxage=1, stale-while-revalidate=59'
},
status: 200,
statusText: 'OK'
})
} catch (error) {
// Issue? Leave a message and bail.
console.error(error)
return new Response(JSON.stringify({error: `${error}`}), {
status: 500,
statusText: 'Internal Server Error'
})
}
}

1 comment on commit 756af7c

@vercel
Copy link

@vercel vercel bot commented on 756af7c Oct 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.