I Built a Tinder-Style GitHub Discovery App (And Ran Into Some Interesting API Problems) — DeepSeek Blog | Neura Market
    Neura MarketNeura Market/DeepSeek
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityDeepSeekDeepSeek
    CoPilotCoPilotStable DiffusionStable DiffusionMidjourneyMidjourney
    View All Directories
    OverviewRulesPromptsMCPsAgentsBlogVideosGuidesCoursesCommunityTrendingGenerate
    DeepSeekBlogI Built a Tinder-Style GitHub Discovery App (And Ran Into Some Interesting API Problems)
    Back to Blog
    I Built a Tinder-Style GitHub Discovery App (And Ran Into Some Interesting API Problems)
    opensource

    I Built a Tinder-Style GitHub Discovery App (And Ran Into Some Interesting API Problems)

    Osman March 8, 2026
    0 views

    Scrolling through GitHub to find interesting repositories can feel exhausting. You search for...

    Scrolling through GitHub to find interesting repositories can feel exhausting. You search for something like _Python tools_ or _Swift libraries_ and suddenly you’re staring at hundreds of repositories. Lists... More lists... Endless scrolling... So I started thinking: **What if discovering repositories worked like Tinder?** Instead of scrolling through hundreds of repos, you would see **one repository at a time** and simply swipe. Right → ⭐ Star Left → ❌ Skip That idea became **_gitinder**, a SwiftUI-based iOS app that lets developers discover GitHub repositories using swipe gestures. ![intro](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93xdobajqsa3j7mwfd2a.gif) But building it turned out to be a great learning experience about: - OAuth authentication - API limitations - local state management - configuration handling in mobile apps Here are a few things I learned along the way. --- ## The OAuth Problem (PKCE vs Backend) Authentication is always the first real challenge when integrating with GitHub. Initially I wanted to implement **OAuth with PKCE**, since it’s the recommended approach for mobile apps. But after experimenting with PKCE for a while, I kept running into issues with GitHub’s OAuth implementation and the flow wasn’t behaving as expected in the iOS environment. Instead of spending more time fighting the flow, I switched to a simpler and reliable architecture. I created a tiny backend service whose only job is to exchange the authorization code for an access token. The authentication flow now looks like this: 1. The app opens GitHub’s OAuth authorization page 2. GitHub redirects back to the app with an authorization code 3. The app sends that code to the backend 4. The backend exchanges it for an access token 5. The token is returned to the app and stored in the Keychain The important part is that **the client secret never exists inside the mobile app**. The backend itself is extremely small and only performs the token exchange. --- ## The GitHub Search API and the OR Query Problem ![language preferences](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g88jsz0rtb3xxkkrgh9k.gif) One of the core features of _gitinder is filtering repositories by programming language. My first attempt looked something like this: ```url language:Swift OR language:Python OR language:Rust ``` Simple, right? However, GitHub’s search API has a **hard limit on logical operators**. If too many OR conditions are used, the API returns a validation error. This forced me to rethink how filtering should work. Instead of one large query, I split the requests into **multiple smaller queries**, each targeting a specific language. For example: - language:Swift - language:Python - language:Rust The results are then combined inside the app. This solution works, but I have to admit something: **✨ It’s not ideal!!** Right now the app sends multiple requests to GitHub’s API, which increases the number of API calls and makes the system less efficient than I would like. It solved the immediate problem, but it’s definitely something I want to improve in the future. If anyone has ideas on how to better structure the query or reduce the number of API requests while keeping language filtering flexible, I would love to hear your thoughts. This is an open-source project, and contributions or suggestions are always welcome. --- ## Handling Multiple API Requests Another interesting challenge appeared while implementing the **star and unstar system**. At first, every time the user swiped right to star a repository, the app would immediately send a request to GitHub: ```http PUT /user/starred/{owner}/{repo} ``` This worked, but it quickly became inefficient. Imagine a user swiping through many repositories quickly. The app could end up sending **dozens of API requests in a very short time**, which is not great for performance or rate limits. So I decided to rethink the approach. Instead of immediately sending requests to GitHub, the app **collects star and unstar actions locally**. Inside the authentication manager, I store them like this: ```swift @Published var pendingStars: [(owner: String, repo: String)] = [] @Published var pendingUnstars: [(owner: String, repo: String)] = [] ``` Whenever the user swipes right on a repository in **HomeView**, the app: - adds the repository to a local starred list - appends the action to pendingStars Similarly, when a repository is removed from the starred list in **ProfileView**, the action is added to pendingUnstars. ![add remove](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3bl0znod0ldawpsxl0w5.png) But the interesting part is **when the API requests are actually sent**. Instead of firing them immediately, I trigger synchronization when the user switches views. ```swift .onDisappear { auth.syncStarChanges() } ``` This creates a nice flow inside the app: - **Home tab (left side)** Users discover repositories and swipe right to star them. These actions are **collected locally**. - When the user navigates to **Profile tab (right side)** All pending star actions are sent to GitHub in one batch. - **Profile tab** allows users to remove starred repositories. Those removals are also collected locally. - When the user navigates back to **Home**, all pending unstar actions are synchronized. In other words: Home → collects **stars** Profile → collects **unstars** And the API is only called **when switching between tabs**. This approach dramatically reduces the number of API requests and keeps the UI responsive. It also creates a surprisingly natural mental model for the user: Discover on the left. Manage on the right. --- ## Managing Secrets the Right Way (.env + xcconfig) Another important lesson was how to handle secrets properly. For the backend, I used a classic approach: ```conf .env ``` This file stores sensitive information like: - CLIENT_ID - CLIENT_SECRET The .env file is ignored by Git and never pushed to GitHub. However, mobile apps have a different challenge. Environment variables are not as straightforward as they are in backend environments. After some research, I implemented a more professional solution using: ```plaintext xcconfig ``` With this setup: - OAuth client IDs are defined in Config.xcconfig - The value is injected into Info.plist - The Swift code reads it from the app bundle This approach keeps configuration separate from the codebase and allows other developers to easily configure the app locally. --- ## The “-1 Star Limit” Easter Egg While building the preferences system, I added an option where users can limit repository results by star count. For example: - < 100 - < 500 - < 1000 But while testing the feature I thought: _“What happens if the limit is… -1?”_ So I added a small **easter egg**. When the star limit is set to -1, the app stops searching GitHub entirely and instead shows something very important: **✨My own repositories...✨** ![easter egg](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4ejpzhujhmra150nz97.gif) Purely for scientific reasons, of course. It’s a completely unnecessary feature, but I like the idea that somewhere in the settings there is a hidden option that quietly turns the app into: > _"Discover Osman’s projects instead."_ Every serious software project needs at least one completely unnecessary feature. This one just happens to promote my GitHub profile. --- ## What I Learned Building _gitinder taught me several valuable lessons: - Authentication flows in mobile apps require careful design. - APIs do not always behave exactly as expected, especially when rate limits or caching are involved. - Local state management can dramatically improve the user experience. - Configuration management is an important part of building professional software. - Most importantly, building something end-to-end teaches far more than reading documentation. --- ## Final Thoughts _gitinder started as a small idea: making GitHub discovery more interactive. But during development, it became a great opportunity to explore real-world engineering problems: - OAuth authentication - API limitations - State synchronization - Configuration management If you’re interested in the project, you can check it out here: {% embed https://github.com/Osman-Kahraman/_gitinder %} And if you like the idea; **maybe give it a ⭐** **or just swipe left...**

    Tags

    opensourceswiftiosshowdev

    Comments

    More Blog

    View all
    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠ai

    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠

    Hi everyone! 👋 I’m Tara, a Senior Software Engineer and Consultant. Over the years, I've jumped...

    T
    tworrell
    Local AI Will Save Us All (The Math Says So, Trust Me)ai

    Local AI Will Save Us All (The Math Says So, Trust Me)

    Every few weeks a take goes viral in tech circles making the case for ditching cloud AI and running...

    S
    Sebastian Schürmann
    Lost in the AI Hype, I Started Smallai

    Lost in the AI Hype, I Started Small

    And it helped me get back into tech without drowning TL;DR at the end Coming back to...

    R
    Rohini Gaonkar
    Building a Replay-Tested Interactive Brokers Client in Gogo

    Building a Replay-Tested Interactive Brokers Client in Go

    I wanted an IBKR library that felt like Go and had testing I could trust. So I wrote one.

    T
    Thomas Marcelis
    Playwright in Pictures: Fully Parallel Modeplaywright

    Playwright in Pictures: Fully Parallel Mode

    Playwright’s fullyParallel mode is often treated as a simple performance switch. In practice, it...

    V
    Vitaliy Potapov
    Designing a CLI for Both Humans and Agentscli

    Designing a CLI for Both Humans and Agents

    Learn how Alpic designed its CLI for both human developers and AI agents — covering tradeoffs like polling, context windows, interactivity, and statelessness.

    J
    Julien Vallini

    Stay up to date

    Get the latest DeepSeek prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for DeepSeek and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.