JSON with HTTP
2017-06-15 18:50
134 查看
原文
Play通过HTTP API与JSON库共同支持内容类型为JSON的HTTP请求和应答。
关于 Controllers, Actions, 和routing的详细资料看HTTP Programming
我们将通过设计一个简单的RESTful Web服务来解释必要的概念,这个服务可以GET 到实体集合,并接收POSTs 创建新的实体。并且这个服务将对所有的数据使用JSON类型。
这是我们在我们的服务中将使用的模型:
在我们写我们的Action之前,我们将需要探究一下从我们的模型转换为
接下来我们写我们的Action
Action 取到Place 对象列表,使用Json.toJson和我们的隐式
我们可以使用浏览器或HTTP工具生成一个请求测试Action,这个例子使用了Unix的命令行工具 cURL.
Play通过HTTP API与JSON库共同支持内容类型为JSON的HTTP请求和应答。
关于 Controllers, Actions, 和routing的详细资料看HTTP Programming
我们将通过设计一个简单的RESTful Web服务来解释必要的概念,这个服务可以GET 到实体集合,并接收POSTs 创建新的实体。并且这个服务将对所有的数据使用JSON类型。
这是我们在我们的服务中将使用的模型:
case class Location(lat: Double, long: Double) case class Place(name: String, location: Location) object Place { var list: List[Place] = { List( Place( "Sandleford", Location(51.377797, -1.318965) ), Place( "Watership Down", Location(51.235685, -1.309197) ) ) } def save(place: Place) = { list = list ::: List(place) } }
以Json形式提供实体列表
我们将以给我们的Controller添加必须的导入开始:import play.api.mvc._ import play.api.libs.json._ import play.api.libs.functional.syntax._ object Application extends Controller { }
在我们写我们的Action之前,我们将需要探究一下从我们的模型转换为
JsValue形式。这是通过定义隐式
Writes[Place]实现.
implicit val locationWrites: Writes[Location] = ( (JsPath \ "lat").write[Double] and (JsPath \ "long").write[Double] )(unlift(Location.unapply)) implicit val placeWrites: Writes[Place] = ( (JsPath \ "name").write[String] and (JsPath \ "location").write[Location] )(unlift(Place.unapply))
接下来我们写我们的Action
def listPlaces = Action { val json = Json.toJson(Place.list) Ok(json) }
Action 取到Place 对象列表,使用Json.toJson和我们的隐式
Writes[Place]把他们转换成JsValue ,然后再把它作为结果Body返回。Play将会认出JSON结果并相应的为应答设置 Content-Type头和Body值。最后一步是把我们的Action 路由添加到
conf/routes:
GET /places controllers.Application.listPlaces
我们可以使用浏览器或HTTP工具生成一个请求测试Action,这个例子使用了Unix的命令行工具 cURL.
curl --include http://localhost:9000/places[/code]
应答:HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 141 [{"name":"Sandleford","location":{"lat":51.377797,"long":-1.318965}},{"name":"Watership Down","location":{"lat":51.235685,"long":-1.309197}}]通过JSON创建一个新的实体引用
对于这个Action ,我们将需要定义一个隐式的Reads[Place]来把JsValue转换成我们的模型。implicit val locationReads: Reads[Location] = ( (JsPath \ "lat").read[Double] and (JsPath \ "long").read[Double] )(Location.apply _) implicit val placeReads: Reads[Place] = ( (JsPath \ "name").read[String] and (JsPath \ "location").read[Location] )(Place.apply _)
这个Action 比我们的列表例子复杂些,一些事情需要注意:
这个Action 要求有一个Content-Type头为text/json或application/json,body 包含需要创建的实体的JSON形式。
它使用JSON指定的BodyParser ,它将 解析请求 并提供做为JsValue的request.body
我们使用依赖我们的隐式Reads[Place]的validate 方法进行转换。
为了处理验证结果,我们使用有错误和成功流的fold。这个模式也类似于使用表单提交.
Action 也发送JSON应答
Body 解析器可以用Case类,隐式的Reads 或接受函数的方式被输入。因此我们可以省掉更多的工作,让Play自动把Json解析成Case类并在调用我们的Action之前进行[验证]。(https://www.playframework.com/documentation/2.5.x/ScalaJsonCombinators#Validation-with-Reads)import play.api.libs.json._ import play.api.libs.json.Reads._ import play.api.libs.functional.syntax._ implicit val locationReads: Reads[Location] = ( (JsPath \ "lat").read[Double](min(-90.0) keepAnd max(90.0)) and (JsPath \ "long").read[Double](min(-180.0) keepAnd max(180.0)) )(Location.apply _) implicit val placeReads: Reads[Place] = ( (JsPath \ "name").read[String](minLength[String](2)) and (JsPath \ "location").read[Location] )(Place.apply _) // This helper parses and validates JSON using the implicit `placeReads` // above, returning errors if the parsed json fails validation. def validateJson[A : Reads] = BodyParsers.parse.json.validate( _.validate[A].asEither.left.map(e => BadRequest(JsError.toJson(e))) ) // if we don't care about validation we could replace `validateJson[Place]` // with `BodyParsers.parse.json[Place]` to get an unvalidated case class // in `request.body` instead. def savePlaceConcise = Action(validateJson[Place]) { request => // `request.body` contains a fully validated `Place` instance. val place = request.body Place.save(place) Ok(Json.obj("status" ->"OK", "message" -> ("Place '"+place.name+"' saved.") )) }
最后,我们将在conf/routes文件里添加一个路由绑定:POST /places controllers.Application.savePlace
我们将使用有效的和无效的请求测试Action,以验证我们成功和错误流。
使用有效的数据测试Action:curl --include --request POST --header "Content-type: application/json" --data '{"name":"Nuthanger Farm","location":{"lat" : 51.244031,"long" : -1.263224}}' http://localhost:9000/places[/code]
应答:HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 57 {"status":"OK","message":"Place 'Nuthanger Farm' saved."}
使用没有“name” 字段的无效数据测试Action:curl --include --request POST --header "Content-type: application/json" --data '{"location":{"lat" : 51.244031,"long" : -1.263224}}' http://localhost:9000/places[/code]
应答:HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 Content-Length: 79 {"status":"KO","message":{"obj.name":[{"msg":"error.path.missing","args":[]}]}}
使用错误数据类型“lat”的无效数据测试Action:curl --include --request POST --header "Content-type: application/json" --data '{"name":"Nuthanger Farm","location":{"lat" : "xxx","long" : -1.263224}}' http://localhost:9000/places[/code]
应答:HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 Content-Length: 92 {"status":"KO","message":{"obj.location.lat":[{"msg":"error.expected.jsnumber","args":[]}]}}总结
Play是被设计来支持REST使用JSON并且开发这些服务应该是简单的。大部分的工作是给你的模型写Reads和Writes,这将会在下一节中详细介绍。
相关文章推荐
- .net Web API 2,return HttpResponseMessage with ObjectContent Json Type
- posting-jsonobject-with-httpclient-from-web-api
- Consuming XML and JSON web services (MyMoviesWithHttpClient)
- JSON with HTTP
- JSON with HTTP
- No mapping found for HTTP request with URI [/service/model/xxx/json] in DispatcherServlet
- [PHP] Http API with JSON data
- No mapping found for HTTP request with URI [/test2/test/add.json] in DispatcherServlet with name 'dispatcher'
- securely implement request processing, filtering and content redirection with HTTP pipeline in ASP.NET
- New Adventures in Comet: polling, long polling or Http streaming with AJAX. Which one to choose?
- A Helper class with JSON serialization
- 【译】 Using JSON (JavaScript Object Notation) with Yahoo! Web Services(z)
- Using WebDAV with IIS -- http://www.windowsnetworking.com/ - Easy Company 的 .Net 开发博客 - 博客园
- Ajax:拥抱JSON,让XML走开http://searchwebservices.techtarget.com.cn/tips/481/2708981_3.shtml
- The request failed with HTTP status 401: Access Denied
- Nginx HTTP Server + PHP5 (With fast-cgi And xcache) On Ubuntu Feisty Fawn
- The request failed with HTTP status 401:Access Denied
- The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this ap
- the request failed with http status 401:unauthorized
- The request failed with HTTP status 401:Access Denied