开发克朗代克纸牌Web分布式应用的REST API资源URL设计咨询
Hey there! Let’s work through this REST API design for your Klondike Solitaire app—mapping the game’s structure to RESTful endpoints makes total sense once you anchor everything to the core game resource. All other components (stock, waste, tableau piles, foundation piles) are sub-resources belonging to a specific game instance, so we’ll build a clear hierarchy around that.
1. Game Resource (The Root of Everything)
Every game instance is the parent resource for all other components. Here’s how to model it:
GET /games
Fetch a list of all active games for the user (return summaries like game ID, status, creation time—no need for full card details here).POST /games
Create a new Klondike game. The server initializes the full牌局 (stock, tableau piles, foundations) and returns the new game’s ID along with its complete initial state.GET /games/{gameId}
Fetch the full state of a specific game. This should include every detail: stock count, waste pile cards, all tableau piles (with face-up/face-down status), and foundation progress.DELETE /games/{gameId}
Delete a game (for when the user abandons it or you need to clean up stale sessions).
2. Stock, Waste, Tableau, Foundation Sub-Resources
All these components are nested under /games/{gameId} since they only exist within a specific game.
Stock (Draw Pile)
GET /games/{gameId}/stock
Get the current state of the stock (remaining card count, whether there are cards left to deal).
Waste (Discard Pile)
GET /games/{gameId}/waste
Get the waste pile’s cards (usually only the top card is face-up—include that detail).
Tableau Piles (7 Piles)
Since there are 7 distinct tableau piles, each gets a unique ID (1-7 works perfectly):
GET /games/{gameId}/tableaus
Fetch all 7 tableau piles with their full card lists and face-up/face-down status.GET /games/{gameId}/tableaus/{tableauId}
Fetch details for a single tableau pile.
Foundation Piles (4 Suit-Based Piles)
Similarly, use IDs 1-4 (one per suit):
GET /games/{gameId}/foundations
Fetch all 4 foundation piles (show the top card’s rank and suit, or that the pile is empty).GET /games/{gameId}/foundations/{foundationId}
Fetch details for a single foundation pile.
Your game class has methods like moveFromStockToWaste and moveFromTableauToTableau—these are state-changing actions, and REST prefers modeling state changes over verb-based URLs. The cleanest approach is to use a centralized moves endpoint for all game actions, since most moves modify multiple resources (e.g., moving from stock to waste changes both the stock and waste piles).
Centralized Moves Endpoint
Use POST /games/{gameId}/moves for every valid game action. The request body specifies the move type and required parameters. This keeps your API consistent, makes validation easier, and simplifies logging.
Example Move Requests
Move from Stock to Waste (Klondike usually deals 3 cards at a time):
POST /games/klondike-123/moves Content-Type: application/json { "type": "stock-to-waste", "count": 3 }Move from Tableau to Tableau:
POST /games/klondike-123/moves Content-Type: application/json { "type": "tableau-to-tableau", "sourceTableauId": 2, "targetTableauId": 5, "cardCount": 2 // Move the top 2 face-up cards from tableau 2 to 5 }Move from Waste to Foundation:
POST /games/klondike-123/moves Content-Type: application/json { "type": "waste-to-foundation", "foundationId": 3 // Target the foundation for clubs, e.g. }
Response Best Practice
After processing any move, return the full updated game state (the same as GET /games/{gameId}). This lets your frontend refresh the entire UI in one go, without making multiple requests to fetch individual resources.
- Avoid verb-heavy URLs: Don’t use
/games/{gameId}/move-stock-to-waste—REST is about resources, not actions. The centralized moves endpoint is far cleaner. - Validate every move server-side: Never trust the frontend to enforce game rules. The server should check if a move is legal (e.g., can you move that card to the foundation?) before updating state.
- Use meaningful IDs: For tableau and foundation piles, simple numerical IDs (1-7 for tableau, 1-4 for foundation) are intuitive for both your backend and frontend code.
内容的提问来源于stack exchange,提问作者MABC

