Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API v2 Proposal #147

Open
memsdm05 opened this issue Dec 6, 2021 · 1 comment
Open

API v2 Proposal #147

memsdm05 opened this issue Dec 6, 2021 · 1 comment
Labels
enhancement New feature or request

Comments

@memsdm05
Copy link
Contributor

memsdm05 commented Dec 6, 2021

sup gamers,

I come from my inactivity to outline some improvements and refactoring for Gulag's API. Thanks to FastAPI, it is possible to implement some improvements that were much harder to do with cmyui_pkg. In my opinion, I think the current API (hereby referred to as v1) is should be deprecated and replaced with a v2. That being said, here are my takes for a future API.

In General

  • /api rate limit via X-Ratelimit (good stack overflow about it)
  • OAuth2 client credentials, authorization flow, and implicit flow
  • OpenAPI specification (eh maybe / maybe not)
  • /api only is 301 redirect to Rick Roll (le epic troll)
  • Response cache improvements (not building responses every time, etc)
  • 10-second timeout
  • returned datetime is always UTC rfc3339 i.e. 2021-12-06T04:49:25+00:00
  • snake_case
  • cursor objects embbed into search queries (semantics for later)

REST

Here are all v1 endpoints at the time of writing:
https://github.com/cmyui/gulag/blob/e40ed8921eb62a7561ecb6d5042e7062bb6b9a61/mount/app/api/domains/api.py#L45-L63

Proposed Changes

:mode = <osu | mania | catch | taiko>
GET /api/v2/online : return total registered & online player counts. (? I have to think about this one)
GET /api/v2/player/:id : return info or stats for a given player.
GET /api/v2/player/:id/status : return a player's current status, if online. (should be a WebSocket)
GET /api/v2/player/:id/scores/<best | recent | most_played> :  return a list of best, recent, or most played scores for a given player.

GET /api/v2/map/:id : return information about a given beatmap
GET /api/v2/map/:id/:mode : return information about a given beatmap for a mode.
GET /api/v2/map/:id/:mode/scores : return the best scores for a given beatmap & mode.

GET /api/v2/mapset/:id : return information about a given beatmapset
GET /api/v2/mapset/:id/:mode : return information about a given beatmapset for a mode.
GET /api/v2/mapset/:id/:mode/scores : return the best scores for a given beatmap & mode.

GET /api/v2/score/:id : return information about a given score.
GET /api/v2/score/:id/dl: return the file for a given replay (with or without headers).
GET /api/v2/match/:id : return information for a given multiplayer match.

GET /api/v2/leaderboard/<score | pp>/:mode : return the top players for a given mode & sort condition
GET /api/v2/leaderboard/country/:country_code/<score | pp>/:mode

mode might be optional, just defaults to osu!std

GET /api/v2/map/:id/calc/pp : calculates pp
GET /api/v2/map/:id/calc/score : calculates largest possible score

GET /api/v2/me : user information about oneself
PUT /api/v2/me/avatar : upload an avatar

GET /api/v2/search/players : searches players
GET /api/v2/search/maps : searches maps
GET /api/v2/search/mapsets : searches mapsets
GET /api/v2/search/scores : searches scores scores

GET /api/v2/player/from/:name : returns a player response / id from a name

Reasoning

see osu!api v2

Get rid of "monopaths" and use a RESTful path system. Instead of a single endpoint returning a certain JSON response, every model should have child paths that return related responses. /get_user_info would become /user, /get_player_scores would become /player/scores, etc. The get_ prefix is redundant, as any request other than an HTTP GET should be a 405 error. _info endpoints can be moved to the root model path (i.e. /user, /beatmap, /score). When requesting models that have an Id (aka all of them), it would be better to pass their Id in the path (i.e /user/124493). In my mind path variables are required whereas query parameters are optional. Models should have two types of response structures: Compact and Full. The full structure is returned whenever the model is by itself, while compact is returned when it is in a list. Search endpoints should return a list of compact responses. If one needs more information one must request the full response.

Pros

  • Easy to set up
  • Everyone knows how to use a REST API

Cons

  • Returns unused data (sometimes the client only wants a few fields from the returned data)
  • Limited by number of endpoints
  • Harder to Documnet

GraphQL

If you're unfamiliar, please take a look at the offical guide. It's a good read.

example query

query {
     user(id: 124493) {
          id
          name
          created_at
          scores(type: RECENT) {
               map {
                    title
               }
               pp
          }
     }
}

example response

{
     "data": {
          "user": {
               "id": 124492,
               "name": "chocomint",
               "created_at": "2021-12-06T04:49:25+00:00",
               "scores": [    // blue zenith joke haha so funny
                    {
                         "map": {
                              "title": "Blue Zenith"
                         }
                         "pp": 727.21
                    }
               ]
           },
      },
}

Reasoning

Imagine taking all the previous endpoints and condensing them into one: /graphql. Yep. Instead of having a path represent an entity, root queries that represent certain types of REST endpoints (in a way). For example, say we want to query a single user. We could have a query along the lines of user(id: 124493). Say we wanted multiple users. We can just do something like users(ids: [124493, 3]). This allows for much more flexibility. Also, no versioning!.

@cmyui I'd be happy to code up GraphQL. We can talk semantics on Discord.

Pros

  • Much more flexibility
  • More efficient data retrieval
  • Better bulk requests (you can send files as Base64)
  • Option of using subscription for WebSocket use (getting new scores via ws 💯 )
  • Better development environment (GraphiQL)

Cons

  • More difficult to setup (despite FastAPI having built-in support)
  • Not many people know graphql

Final Notes

It's late, I'm tired, I'll keep this short. We should pick either REST or GraphQL. I think having both would be complicated: stick to one and do it well. I'm on side GraphQL. Ok bye.

@ghost
Copy link

ghost commented Dec 6, 2021

@cmyui cmyui added the enhancement New feature or request label Feb 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants