Difference between revisions of "W3911 Sudoku Server"

From Coder Merlin
m (Editorial review and minor corrections)
 
(31 intermediate revisions by 3 users not shown)
Line 1: Line 1:


Background
== Getting Started ==
See [[Vapor]]
 
== Background ==
A Sudoku board is made up of nine boxes.
A Sudoku board is made up of nine boxes.
Boxes (container for nine cells) are listed from top-to-bottom, left-to-right indexed from zero.
The boxes (containers for nine cells) are listed from top to bottom, left to right, and indexed from zero.
Cells are listed from top-to-bottom, left-to-right, indexed from zero.
Cells are listed from top to bottom, left to right, and indexed from zero.
All valid payloads and responses must use well-formed JSON.   
All valid payloads and responses must use well-formed JSON.   
“cells” is returned as follows:
The value of “cells” is returned as follows:
“cells”: [[<nine values from top-left>], [<nine values from top-middle>], …]
“cells”: [[<nine values from top-left>], [<nine values from top-middle>], …]


End Points
== End Points ==
{{RestAPI
{{RestAPI
|endpoint=POST /games?difficulty=<difficulty>
|endpoint=POST /games?difficulty=<difficulty>
Line 18: Line 21:
     {"id":<id>}
     {"id":<id>}
|responseExample={"id": 728134}
|responseExample={"id": 728134}
|errors=400 Bad Request (difficulty specified doesn't match requirements)
}}
}}
{{RestAPI
{{RestAPI
|endpoint=GET /games/<id>/cells
|endpoint=GET /games/<id>/cells?filter=<filter>
|action=Returns the current cells for the specified game
|action=Returns the current cells for the specified game
|parameters=filter: all {{Bar}} repeated {{Bar}} incorrect
|body=<span style="font-style: italic;">none</span>
|statusCode=200 OK
|response=
  {"board":
    [{"cells":[{"position":{"boxIndex":<boxIndex>,"cellIndex":<cellIndex>},"value":<value>}...
|responseExample=
  {"board":
    [{"cells":[{"position":{"boxIndex":0,"cellIndex":0},"value":0},{"position":{"boxIndex":0,"cellIndex":1},"value":1},
              {"position":{"boxIndex":0,"cellIndex":2},"value":2},{"position":{"boxIndex":0,"cellIndex":3},"value":3},
              {"position":{"boxIndex":0,"cellIndex":4},"value":4},{"position":{"boxIndex":0,"cellIndex":5},"value":5},
              {"position":{"boxIndex":0,"cellIndex":6},"value":6},{"position":{"boxIndex":0,"cellIndex":7},"value":7},
              {"position":{"boxIndex":0,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}
  ]}
|errors=400 Bad Request (filter specified doesn't match requirements)
}}
{{RestAPI
|endpoint=PUT /games/<id>/cells/<boxIndex>/<cellIndex>
|action=Place specified value at in game at boxIndex, cellIndex
|parameters=<span style="font-style: italic;">none</span>
|parameters=<span style="font-style: italic;">none</span>
|body=<span style="font-style: italic;">none</span>
|body=
  {"value":<value>}
|statusCode=200 OK
|statusCode=200 OK
|response=Cells
|response=<span style="font-style: italic;">none</span>
    {"id":<id>}
|responseExample=<span style="font-style: italic;">none</span>
|responseExample={"id": 728134}
|errors=
  400 Bad Request (boxIndex is out of range 0 ... 8)
  400 Bad Request (cellIndex is out of range 0 ... 8)
  400 Bad Request (value is out of range 1 ... 9 or null)
}}
}}


* PUT /games/<id>/cells/<boxIndex>/<cellIndex>
== JSON Encoding ==
    * Action: Place specified value at in game at boxIndex, cellIndex
    * Payload: value (null for removing value)
    * Response: Nothing
    * Status: 204 No Content
 
=== JSON Encoding ===
{{CodeExplorer
{{CodeExplorer
|exerciseID=1
|exerciseID=1
|mode=swift
|language=swift
|height=400
|height=400
|initialCode=import Foundation
|initialCode=import Foundation


struct Cell: Codable {
let board = Board()  
    let value: Int?
}
 
let cell = Cell(value: 17)
let encoder = JSONEncoder()
let encoder = JSONEncoder()


guard let data = try? encoder.encode(cell),  
guard let data = try? encoder.encode(board),  
       let json = String(data: data, encoding: .utf8) else {
       let json = String(data: data, encoding: .utf8) else {
     fatalError("Failed to encode data into json.")
     fatalError("Failed to encode data into json.")
}
}
print(json)
print(json)
// Structure definitions
struct Position: Codable {
    let boxIndex: Int
    let cellIndex: Int
}
struct Cell: Codable {
    let position: Position
    let value: Int?
}
struct Box: Codable {
    let cells: [Cell]
 
    init(boxIndex: Int) {
        var cells = [Cell]()
        for cellIndex in 0 ..< 9 {
            cells.append(Cell(position: Position(boxIndex: boxIndex, cellIndex: cellIndex), value: cellIndex))
        }
        self.cells = cells
    }
}
struct Board: Codable {
    let board: [Box]
 
    init() {
        var board = [Box]()
        for boxIndex in 0 ..< 9 {
            board.append(Box(boxIndex: boxIndex))
        }
        self.board = board
    }
}
}}
}}
=== JSON Decoding ===
 
== JSON Decoding ==
{{CodeExplorer
{{CodeExplorer
|exerciseID=2
|exerciseID=2
|mode=swift
|language=swift
|height=400
|height=400
|initialCode=import Foundation
|initialCode=import Foundation
let json =
#"""
{"board":
    [{"cells":[{"position":{"boxIndex":0,"cellIndex":0},"value":0},{"position":{"boxIndex":0,"cellIndex":1},"value":1},
              {"position":{"boxIndex":0,"cellIndex":2},"value":2},{"position":{"boxIndex":0,"cellIndex":3},"value":3},
              {"position":{"boxIndex":0,"cellIndex":4},"value":4},{"position":{"boxIndex":0,"cellIndex":5},"value":5},
              {"position":{"boxIndex":0,"cellIndex":6},"value":6},{"position":{"boxIndex":0,"cellIndex":7},"value":7},
              {"position":{"boxIndex":0,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]},
    {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1},
              {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3},
              {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5},
              {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7},
              {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}
]}
"""#
let decoder = JSONDecoder()
guard let data = json.data(using: .utf8),
      let board: Board = try? decoder.decode(Board.self, from: data) else {
    fatalError("Failed to decode json into board.")
}
dump(board)
// Structure definitions
struct Position: Codable {
    let boxIndex: Int
    let cellIndex: Int
}


struct Cell: Codable {
struct Cell: Codable {
    let position: Position
     let value: Int?
     let value: Int?
}
}


let json = #"{"value":17}"#
struct Box: Codable {
let decoder = JSONDecoder()
    let cells: [Cell]
  }


guard let data = json.data(using: .utf8),
struct Board: Codable {
      let cell: Cell = try? decoder.decode(Cell.self, from: data) else {
    let board: [Box]
    fatalError("Failed to decode json into cell.")
}
}
dump(cell)
}}
}}
=== Issue Request from Client to Server ===
 
== Issue Request from Client to Server ==
{{CodeExplorer
{{CodeExplorer
|exerciseID=3
|exerciseID=3
|mode=swift
|language=swift
|height=400
|height=400
|initialCode=import Foundation                                                                                                                                                                                                                           
|initialCode=import Foundation                                                                                                                                                                                                                           
Line 124: Line 282:
}
}
}}
}}
== Server-side Query String Access ==
<syntaxhighlight lang="swift">
  let difficulty: String? = request.query["difficulty"]
</syntaxhighlight>
== Server-side Content Access for JSON ==
<syntaxhighlight lang="swift">
  app.put("value") { req -> String in
      struct CellValue: Decodable {
          let value: Int?
      }
      let cellValue = try req.content.decode(CellValue.self)
      return "Done"
  }
</syntaxhighlight>
== Server-side Parameter Access and Error Handling ==
<syntaxhighlight lang="swift">
    guard let boxIndex = req.parameters.get("boxIndex", as: Int.self),
        let cellIndex = req.parameters.get("cellIndex", as: Int.self) else {
        throw Abort(.badRequest, reason: "boxIndex and cellIndex MUST be integers")
    }
</syntaxhighlight>
== Server-side Returning "No Content" ==
<syntaxhighlight lang="swift">
  return Response(status: .noContent)
</syntaxhighlight>

Latest revision as of 08:59, 11 February 2023

Within these castle walls be forged Mavens of Computer Science ...
— Merlin, The Coder

Getting Started[edit]

See Vapor

Background[edit]

A Sudoku board is made up of nine boxes. The boxes (containers for nine cells) are listed from top to bottom, left to right, and indexed from zero. Cells are listed from top to bottom, left to right, and indexed from zero. All valid payloads and responses must use well-formed JSON. The value of “cells” is returned as follows: “cells”: [[<nine values from top-left>], [<nine values from top-middle>], …]

End Points[edit]

POST /games?difficulty=<difficulty>
Creates a new game and associated board
   Parameters: 
   difficulty: easy | medium | hard | hell
   Body: none
   Status code: 201 Created
   Response: ID (integer) of newly created game
   {"id":<id>}
   
{"id": 728134}
   Errors:
   
400 Bad Request (difficulty specified doesn't match requirements)



GET /games/<id>/cells?filter=<filter>
Returns the current cells for the specified game
   Parameters: 
   filter: all | repeated | incorrect
   Body: none
   Status code: 200 OK
   Response: {"board":
   [{"cells":[{"position":{"boxIndex":<boxIndex>,"cellIndex":<cellIndex>},"value":<value>}...
   
{"board": [{"cells":[{"position":{"boxIndex":0,"cellIndex":0},"value":0},{"position":{"boxIndex":0,"cellIndex":1},"value":1}, {"position":{"boxIndex":0,"cellIndex":2},"value":2},{"position":{"boxIndex":0,"cellIndex":3},"value":3}, {"position":{"boxIndex":0,"cellIndex":4},"value":4},{"position":{"boxIndex":0,"cellIndex":5},"value":5}, {"position":{"boxIndex":0,"cellIndex":6},"value":6},{"position":{"boxIndex":0,"cellIndex":7},"value":7}, {"position":{"boxIndex":0,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]} ]}
   Errors:
   
400 Bad Request (filter specified doesn't match requirements)



PUT /games/<id>/cells/<boxIndex>/<cellIndex>
Place specified value at in game at boxIndex, cellIndex
   Parameters: 
   none
   Body: {"value":<value>}
   Status code: 200 OK
   Response: none
   
none
   Errors:
   
400 Bad Request (boxIndex is out of range 0 ... 8) 400 Bad Request (cellIndex is out of range 0 ... 8) 400 Bad Request (value is out of range 1 ... 9 or null)


JSON Encoding[edit]

CoderMerlin™ Code Explorer: W0000 (1) 🟢


JSON Decoding[edit]

CoderMerlin™ Code Explorer: W0000 (2) 🟢


Issue Request from Client to Server[edit]

CoderMerlin™ Code Explorer: W0000 (3) 🟢


Server-side Query String Access[edit]

  let difficulty: String? = request.query["difficulty"]

Server-side Content Access for JSON[edit]

  app.put("value") { req -> String in
      struct CellValue: Decodable {
          let value: Int?
      }
      let cellValue = try req.content.decode(CellValue.self)
      return "Done"
  }

Server-side Parameter Access and Error Handling[edit]

    guard let boxIndex = req.parameters.get("boxIndex", as: Int.self),
        let cellIndex = req.parameters.get("cellIndex", as: Int.self) else {
        throw Abort(.badRequest, reason: "boxIndex and cellIndex MUST be integers")
    }

Server-side Returning "No Content"[edit]

  return Response(status: .noContent)