Working on a project and using Spray
Want to add Swagger to get a nice UI for all the calls
Found :
http://github.com/gettyimages/spray-swagger
Problem is I cant seem to get it to work with my project, with no docs or
run examples its like walking in the dark .... (and time consuming)
did any 1 get to work with this and has a
test example
wiki page
any thing helpful
So i can get get it working?
Thanks!
So I took a stab at this and got it working. You can check out my repo here.
Granted, it is my scratchpad for exploring Spray, so some things may change. Also, this is based on Spray 1.3.0.
The general gist of getting this to work, as I understand it, is:
You have your traits/classes that hold your routes; lets call this a "Resource". Each one of these traits/classes roughly corresponds to a "path" (e.g. /posts)
In your Resources, instead of directly using the Spray DSL to construct one big route, you need to have one method for each endpoint(roughly corresponding to an "action" in Rails controller, or a route in Sinatra/Scalatra). These methods need to be annotated. So for example you would have separate def postCreate, def postDeletes, etc. These would then need to be composed separately for your Resource.
You instantiate a SwaggerHttpService, implementing the necessary methods (including a Sequence of all the traits/classes in 1, and a Sequence of all your ApiModels that are used in your annotations).
The combination of all your routes (across your actual API and the SwaggerHttpService) needs to get passed to your central routing actor's receive method wrapped in a runRoute (this is the actor that gets in Boot.scala)
I believe 1. and 2. are necessary because spray-swagger works with Java annotations, which cannot be retrieved when wrapped inside an opaque function (which is what the Spray routing DSL normally composes for you).
the project has been updated with a wiki and usage information!
This looks promising :
https://github.com/gettyimages/spray-swagger
didn't try it out yet but looking good!
One of my concerns spray-swagger is that the annotations make the code harder to read. Any ideas for how to make the code readable & still get the benefits of Swagger?
#Api(value = "/pet", description = "Operations about pets")
trait PetHttpService extends HttpService {
#ApiOperation(httpMethod = "GET", response = classOf[Pet], value = "Returns a pet based on ID")
#ApiImplicitParams(Array(
new ApiImplicitParam(name = "petId", required = false, dataType = "integer", paramType = "path", value = "ID of pet that needs to be fetched")
))
#ApiResponses(Array(
new ApiResponse(code = 400, message = "Invalid ID Supplied"),
new ApiResponse(code = 404, message = "Pet not found")))
def petGetRoute = get { path("pet" / IntNumber) { petId =>
complete(s"Hello, I'm pet ${petId}!")
} }
}
I'm going to create a trait with annotations & extend to see if the annotations work. Will let you guys know what happens!
Related
I defined a domain model class with a few properties and marked it as a RESTful resource using #Resource following the official Grails guide on Web services. Now, when testing the application (using Ruby's RestClient) I can see that things are working fine. However, after defining an associated Controller that overrides save method (for creating new resource), I've been getting 404 even on just simple GET requests. I defined some test objects using BootStrap so GET should be working.
My controller code looks like this:
class ModelController {
#Transactional
def save(Model model) {
def status = 201
if (model.validate()) {
model.save(flush: true, failOnError: true)
} else {
status = 422
}
render status:status
}
}
Do I still need to do something with the UrlMappings.groovy or is there something wrong with my controller code (all my unit tests for it are passing though)?
Update
I have created a sample project to demonstrate what's happening. Please check my bookstore-demo repository on GitHub. In the repository, I've defined 2 tags, rest-working, and rest-not-working. The first one marks the point where things are still working, and second one, as the name suggests, marks where I've created a controller that causes 404 response. This is pretty much what I've done with my actual project so far, and I'm getting the the same error.
The code looks OK, if you are getting a 404 then it sounds like its not even hitting this Controller. I would open developer console and try capture what URL it is hitting - URL being sent is potentially incorrect. If I am experimenting I tend to put println "1" println "2" and so on between my logics to see where the code is going or did it return it at all meaning it didn't even get there. so maybe if you doubt your code try this tactic between your if statements see which numbers get hit.
Also there is not a lot to go on to try give anything of more useful as feedback, but I would also check out the allowedMethods of this Controller if any defined...
unsure how it is being posted by if you have ..
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
try changing it to
static allowedMethods = [update: "POST", delete: "POST"]
unsure if this is still supported:
static allowedMethods = [save:['POST','GET'],update: "POST", delete: "POST"]
For all the methods refer to:
http://grails.org/doc/latest/ref/Controllers/allowedMethods.html
My web application will be triggered from an external system. It will call one request path of my app, but uses different query parameters for different kinds of requests.
One of the parameters is the "action" that defines what is to be done. The rest of the params depend on the "action".
So I can get request params like these:
action=sayHello&user=Joe
action=newUser&name=Joe&address=xxx
action=resetPassword
...
I would like to be able to encode it similarly in the routes file for play so it does the query param based routing and as much of the validation of other parameters as possible.
What I have instead is one routing for all of these possibilities with plenty of optional parameters. The action processing it starts with a big pattern match to do dispatch and parameter validation.
Googling and checking SO just popped up plenty of samples where the params are encoded in the request path somehow, so multiple paths are routed to the same action, but I would like the opposite: one path routed to different actions.
One of my colleagues said we could have one "dispatcher" action that would just redirect based on the "action" parameter. It would be a bit more structured then the current solution, but it would not eliminate the long list of optional parameters which should be selectively passed to the next action, so I hope one knows an even better solution :-)
BTW the external system that calls my app is developed by another company and I have no influence on this design, so it's not an option to change the way how my app is triggered.
The single dispatcher action is probably the way to go, and you don't need to specify all of your optional parameters in the route. If action is always there then that's the only one you really need.
GET /someRoute controller.dispatcher(action: String)
Then in your action method you can access request.queryString to get any of the other optional parameters.
Note: I am NOT experienced Scala developer, so maybe presented snippets can be optimized... What's important for you they are valid and working.
So...
You don't need to declare every optional param in the routes file. It is great shortcut for type param's validation and best choice would be convince 'other company' to use API prepared by you... Anyway if you haven't such possibility you can also handle their requests as required.
In general: the dispatcher approach seems to be right in this place, fortunately you don't need to declare all optional params in the routes and pass it between actions/methods as they can be fetched directly from request. In PHP it can be compared to $_GET['action'] and in Java version of Play 2 controller - DynamicForm class - form().bindFromRequest.get("action").
Let's say that you have a route:
GET /dispatcher controllers.Application.dispatcher
In that case your dispatcher action (and additional methods) can look like:
def dispatcher = Action { implicit request =>
request.queryString.get("action").flatMap(_.headOption).getOrElse("invalid") match {
case "sayHello" => sayHelloMethod
case "newUser" => newUserMethod
case _ => BadRequest("Action not allowed!")
}
}
// http://localhost:9000/dispatcher?action=sayHello&name=John
def sayHelloMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
Ok("Hello " + name )
}
// http://localhost:9000/dispatcher?action=newUser&name=John+Doe&address=john#doe.com
def newUserMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
val address = request.queryString.get("address").flatMap(_.headOption).getOrElse("")
Ok("We are creating new user " + name + " with address " + address)
}
Of course you will need to validate incoming types and values 'manually', especially when actions will be operating on the DataBase, anyway biggest part of your problem you have resolved now.
I'm having trouble setting something up that I'm pretty sure /should/ be easy, so I thought I'd throw it to the crowd. I can't seem to find what I'm looking for elsewhere on the web or on SE.
I am simplifying my project of course, but basically I have a JAX-WS annontated Jersey resource class that looks something like this:
#Path("myresource")
public class MyResource {
#Autowired
MyComplexObjectDAO daoInstance;
#Path("findObject/{id}")
#GET
public MyComplexObject findObject( #PathParam(value="id") String id ) {
return daoInstance.findObject( id );
}
#Path("saveObject")
#PUT
public MyComplexObject saveObject( MyComplexObject objectToSave ) {
MyComplexObject savedObject = daoInstance.saveObject( objectToSave );
return savedObject;
}
}
So you can see I'm autowiring a DAO object using spring, and then I use the DAO methods in the REST handlers.
The 'findObject' call seems to work fine - so far it works exactly as I expect it to.
The 'saveObject' call is not working the way I want and that's what I need some advice on.
You can see that I'm trying to directly take an instance of my complex object as a parameter to the REST method. Additionally I would like to return an instance of the complex object after it's been saved.
I put together some 'client' code for testing this out.
#Test
public void saveTest() {
WebResource wsClient = createWebServiceClient();
MyComplexObject unsavedInstance = createMyComplexObject();
MyComplexObject savedInstance =
wsClient
.path("saveObject")
.accept(MediaType.APPLICATION_XML)
.put(MyComplexObject.class, unsavedInstance);
assertNotNull(savedIntent);
}
Which is returning the following error:
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8081/rest/myresource/save returned a response status of 400 Bad Request
I don't see why this isn't working and I think I've tried just about everything I can think of. Any help or direction would be very much appreciated.
Thanks so much!
I see that you call the accept() method in your test client (which means that a "Accept:" header is added to the request, indicating the server what type of representation you would like). However, you don't call the type() method to add a "Content-type:" header and inform the server that you are sending XML data. See http://jersey.java.net/nonav/documentation/latest/client-api.html#d4e644 for examples.
Side remark: your URLs are not RESTful - you should avoid verbs in your path:
So, instead of:
/api/findObject/{id}
/api/saveObject
You should use:
/api/objects/{id}
/api/objects
Last note: to create an object on calling /api/objects, you should do a POST and not a PUT to adhere to REST best practices and widely adopted patterns.
switching to the 'concrete class' solution I alluded to in my earlier comment is what fixed things up for me.
I wanted to develop a RESTful Application with use of CRUD in Play framework. Unfortunately I can't find a way to define DELETE and PUT in the routes of Play. Maybe there is just POST and GET available in Play?
Are you sure you cannot use DELETE/PUT? The docs say otherwise.
The HTTP method
The HTTP method can be any of the valid methods
supported by HTTP (GET, POST, PUT, DELETE, HEAD).
http://www.playframework.org/documentation/2.0.4/JavaRouting
Play 2.x has not a CRUD module known from 1.x branch (IMHO fortunately), for defining routes using not standard methods like DELETE or PUT you need to just use required method in the route:
conf/routes:
PUT /put-item controllers.Application.putItem()
Anyway to use them from the browser methods other than GET or POST you'll need to create an AJAX call, There is a large step-by-step sample on this topic, anyway you can also build it with common jQuery.ajax() by defining the request type
$.ajax({
type: "PUT",
url: "#routes.Application.putItem()",
data: { name: "John", location: "Boston" }
}).done(function( msg ) {
alert( "Data Saved: " + msg );
});
A good way to define these is using a wildcard (*)
This will allow you to use any method valid http method, including those that you have asked about.
For example,
* /items/{id} Items.display
in routes will allow a GET /items/15 or a PUT /items/15. Use wildcards like this to make your route definitions simpler and more flexible.
Don't forget OPTIONS method, if you going to use PUT or DELETE from web browser.
Here is what I did for Delete and Update
POST /path/:id controllers.Controller.update(id: Integer)
POST /path/:id/delete controllers.Controller.delete(id: Integer)
And in Controller just
public static Result delete(Integer id) {
Result result = null;
if(id>0){
//your code
}
else{
result = ok("invalid id");
}
return result;
}
It worked for us for delete and puts
If your intention is only to use RESTFul of play framework and you are using Java it is better use CXF or Spring webservices or Jersey. Play is a fantastic framework but best fit with play is scala
This is an example router in a play scala application that uses the most prominent http verbs:
GET / controllers.Application.listProjects
PUT /projects/:name controllers.Application.createProject(name: String)
GET /projects/list controllers.Application.listProjects
GET /projects/:id controllers.Application.projects(id: Long)
PUT /projects/:id/:name controllers.Application.addTaskToProject(name: String, id: Long)
PATCH /tasks/:id controllers.Application.modifyTask(id: Long, color:Option[String] ?= None)
You can have a look at the whole play scala example project here: https://github.com/nemoo/play-slick3-example
i am confused on how to combine the json library in dispatch and lift to parse my json response.
I am apparently a scala newbie.
I have written this code :
val status = {
val httpPackage = http(Status(screenName).timeline)
val json1 = httpPackage
json1
}
Now i am stuck on how to parse the twitter json response
I've tried to use the JsonParser:
val status1 = JsonParser.parse(status)
but got this error:
<console>:38: error: overloaded method value parse with alternatives:
(s: java.io.Reader)net.liftweb.json.JsonAST.JValue<and>
(s: String)net.liftweb.json.JsonAST.JValue
cannot be applied to (http.HttpPackage[List[dispatch.json.JsObject]])
val status1 = JsonParser.parse(status1)
I unsure and can't figure out what to do next in order to iterate through the data, extract it and render it to my web page.
Here's another way to use Dispatch HTTP with Lift-JSON. This example fetches JSON document from google, parses all "titles" from it and prints them.
import dispatch._
import net.liftweb.json.JsonParser
import net.liftweb.json.JsonAST._
object App extends Application {
val http = new Http
val req = :/("www.google.com") / "base" / "feeds" / "snippets" <<? Map("bq" -> "scala", "alt" -> "json")
val json = http(req >- JsonParser.parse)
val titles = for {
JField("title", title) <- json
JField("$t", JString(name)) <- title
} yield name
titles.foreach(println)
}
The error that you are getting back is letting your know that the type of status is neither a String or java.io.Reader. Instead, what you have is a List of already parsed JSON responses as Dispatch has already done all of the hard work in parsing the response into a JSON response. Dispatch has a very compact syntax which is nice when you are used to it but it can be very obtuse initially, especially when you are first approaching Scala. Often times, you'll find that you have to dive into the source code of the library when you are first learning to see what is going on. For instance, if you look into the dispatch-twitter source code, you can see that the timeline method actually performs a JSON extraction on the response:
def timeline = this ># (list ! obj)
What this method is defining is a Dispatch Handler which converts the Response object into a JsonResponse object, and then parses the response into a list of JSON Objects. That's quite a bit going on in one line. You can see the definition for the operand ># in the JsHttp.scala file in the http+json Dispatch module. Dispatch defines lots of Handlers that do a conversion behind the scenes into different types of data which you can then pass to block to work with. Check out the StdOut Walkthrough and the Common Tasks pages for some of the handlers but you'll need to dive into the various modules source code or Scaladoc to see what else is there.
All of this is a long way to get to what you want, which I believe is essentially this:
val statuses = http(Status(screenName).timeline)
statuses.map(Status.text).foreach(println _)
Only instead of doing a println, you can push it out to your web page in whatever way you want. Check out the Status object for some of the various pre-built extractors to pull information out of the status response.