I am trying to host static resources, like javascript and css files, in finagle.
I've managed to get it to work, but I have to specifically configure every route to a resource folder in my routing service. For example:
def build():RoutingService[Request with Request] = {
val routingService = RoutingService.byPathObject {
case Root => ControllerRegistry.rootController.root()
case Root / "public" / resource => ControllerRegistry.publicController.findPublic()
case Root / "public" / "bootstrap"/ "css" / resource => ControllerRegistry.publicController.findPublic()
}
routingService
}
and
def findPublic(): Service[Request, Response] = {
val findPublic = new Service[Request, Response] {
def apply(request: Request) = {
Future {
val resource = Path(request.path) match {
case Root / "public" / resource => getResourceText(s"/public/$resource")
case Root / "public" / "bootstrap" / "css" / resource => getResourceText(s"/public/bootstrap/css/$resource")
case _ => throw new IllegalStateException
}
val response = Response()
response.setContent(copiedBuffer(resource, UTF_8))
response
}
}
}
findPublic
}
Now I can get any resource in public and public/bootstrap/css, but I can't get public/bootstrap/js without more configuration.
TLDR: Finagle is not exactly the right library to do what you want. You could use something like Finatra which is built on top of finagle.
Long version:
Finagle is designed to build distributed systems, it's not a web framework like ruby on rails (even if finagle-http provides very basic feature for doing that). It makes easy to build services that interact with each other (and take care of load-balancing, timeout, disconnection, back-pressure, distributed tracing, ...)
We have, at Twitter, a web framework library built on top of finagle, but it's not yet open-sourced, in the meantime you can use Finatra.
Related
I am new to swagger and I want to integrate swagger to Restful API project using grails framework. Please help if anybody have any idea what i am doing wrong?
my grails specification as below:
| Grails Version: 3.0.7
| Groovy Version: 2.4.4
| JVM Version: 1.8.0_71
Did some settings for swagger as below:
in build.gradle:
dependencies {
...
compile "io.swagger:swagger-core:1.5.3"
compile "io.swagger:swagger-jaxrs:1.5.3"
...
}
in resources.groovy
import io.swagger.jaxrs.config.BeanConfig
beans = {
swaggerConfig(BeanConfig) {
def serverUrl = "http://localhost:8080/"
def hostName = "localhost:8080"
resourcePackage = "grails.rest.example"
host = hostName
basePath = "/api"
version = 'v0' // Default "1".
title = 'Core Registration API, Version V0'
description = 'API for Accessing secured resources'
contact = 'testtest#mailinator.com'
license = ''
licenseUrl = ''
}
corsFilter(CorsFilter)
}
Added a Controller ApiDocController.groovy:
package grails.rest.example.apidoc
import grails.web.mapping.LinkGenerator
class ApiDocController {
LinkGenerator grailsLinkGenerator
def apiDocService
def index = {
String basePath = grailsLinkGenerator.serverBaseURL
render(view: 'index', model: [apiDocsPath: "${basePath}/api/swagger-json"])
//render(view: 'index', model: [apiDocsPath: "localhost:8080/api/swagger-json"])
//render(view: 'index', model: [apiDocsPath: "localhost:8080/dist/index.html"])
}
def swaggerJson = {
render apiDocService.generateJSON()
}
}
Added a URLMapping for controller:
"/api/info"(controller: 'ApiDoc')
"/"(controller: 'Index')
"500"(controller: 'InternalServerError')
"404"(controller: 'NotFound')
Added a service ApiDocService.groovy:
//package com.care.apidoc
package grails.rest.example.apidoc
import io.swagger.jaxrs.config.BeanConfig
import grails.transaction.Transactional
import io.swagger.util.Json
#Transactional
class ApiDocService {
def swaggerConfig
/*
* generates SWAGGer JSON
*/
def generateJSON() {
String[] schemes = ["http"] as String[]
swaggerConfig.setSchemes(schemes)
swaggerConfig.setScan(true)
def swagger = swaggerConfig.getSwagger()
Json.mapper().writeValueAsString(swagger);
}
}
added Swagger-ui in src/main/webapp/dist folder
with a working customised API URL "http://localhost:8080/api/orders" in index.html
added CorsFilter setting in src/main/groovy/CorsFilter.groovy
import org.springframework.web.filter.OncePerRequestFilter
import javax.annotation.Priority
import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
#Priority(Integer.MIN_VALUE)
public class CorsFilter extends OncePerRequestFilter {
public CorsFilter() { }
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
throws ServletException, IOException {
String origin = req.getHeader("Origin");
boolean options = "OPTIONS".equals(req.getMethod());
resp.addHeader("Access-Control-Allow-Headers", "origin, authorization, accept, content-type, x-requested-with");
resp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
resp.addHeader("Access-Control-Max-Age", "3600");
resp.addHeader("Access-Control-Allow-Origin", origin == null ? "*" : origin);
resp.addHeader("Access-Control-Allow-Credentials", "true");
if (!options) chain.doFilter(req, resp);
}
}
On starting the server.
API for orders is working correctly, however, when I try to load the API in Swagger UI index file. it shows.
No operations defined in spec!
as attached in a pics.
Have you looked at springfox?
Here is a sample Grails Application hosted in Heroku that demonstrates the capabilities of springfox integrating with it to produce the service description in the Open API specification 2.0 (fka swagger). The source code for the demo is available here.
You can see this demo running live here demonstrating the Open API specification generated by the grails application and rendered using swagger-ui.
The library that makes this possible is springfox-grails-integration library. It is about to be released and probably needs a little bit of work to make it a grails plugin. There is some preliminary documentation of how to configure this the library repository.
NOTE: This only works with grails 3.x
Also it was a notable library showcased in the SHOW US YOUR GRAILS contest. Feedback to improve this library is much appreciated.
I am developing a service that is called on one path with different query parameters. I have bind a Route to Http:
val route: Route = {
get {
pathPrefix("myRoute"){
parameterMap{ params =>
complete(
MyHandler.genExternResponse(params)
)
}
}
}
val bindingFuture = Http().bindAndHandleAsync(Route.asyncHandler(new myEndpoint().route), "localhost", 8081)
Since i have no influence on what parameters are used, i can't eliminate the calls that contain not-encoded special chars like German umlauts or trademark signs.
for example
www.myhost.com/myRoute?param1=asd¶m2=adäöü
I know that those URLs are not valid But one of the requirements is that even requests with those chars are accepted und that i handle them with URL encoding.
The problem is that when i call the service like above, akka-http rejects the request with the Response-status 400 without even handing it to my code.
Is there a way that i can catch those request and handle them by myself or let akka-http URL-encode the special chars for me.
edit:
will not solve
Try This
val route: Route = {
get {
pathPrefix("myRoute"){
parameters('params)
{ params =>
complete(
MyHandler.genExternResponse(params)
)
}
}
}
val bindingFuture = Http().bindAndHandleAsync(Route.asyncHandler(new myEndpoint().route), "localhost", 8081)
The play example for using Oauth and Twitter is show below.
In the Play Framework I am still learning how to use redirects and routes. How would you set up the routes file and the Appliction.scala file to handle this redirect?
Redirect(routes.Application.index).withSession("token" -> t.token, "secret" -> t.secret)
Would the routes be something like this?
GET /index controllers.Application.index(String, String)
Link to Play Framework documentation with the example code http://www.playframework.com/documentation/2.0/ScalaOAuth
object Twitter extends Controller {
val KEY = ConsumerKey("xxxxx", "xxxxx")
val TWITTER = OAuth(ServiceInfo(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize", KEY),
false)
def authenticate = Action { request =>
request.queryString.get("oauth_verifier").flatMap(_.headOption).map { verifier =>
val tokenPair = sessionTokenPair(request).get
// We got the verifier; now get the access token, store it and back to index
TWITTER.retrieveAccessToken(tokenPair, verifier) match {
case Right(t) => {
// We received the authorized tokens in the OAuth object - store it before we proceed
Redirect(routes.Application.index).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
}
}.getOrElse(
TWITTER.retrieveRequestToken("http://localhost:9000/auth") match {
case Right(t) => {
// We received the unauthorized tokens in the OAuth object - store it before we proceed
Redirect(TWITTER.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
})
}
def sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
for {
token <- request.session.get("token")
secret <- request.session.get("secret")
} yield {
RequestToken(token, secret)
}
}
}
It turned out that the reasons I had so many intermittent problems with routes and redirect was a combination of the versions of play, version of scala and the version of ScalaIDE for Eclipse. Using Play version 2.2.3, scala version 2.10.4 and ScalaIDE version 2.10.x solved the routes and redirect problems.
The following import statements are needed for the Twitter example.
import play.api.libs.oauth.ConsumerKey
import play.api.libs.oauth.ServiceInfo
import play.api.libs.oauth.OAuth
import play.api.libs.oauth.RequestToken
If your route is like this:
GET /index controllers.Application.index(param1:String, param2:String)
Then the reverse route would look like this:
routes.Application.index("p1", "p2")
Which would result in something like this:
/index?param1=p1¶m2=p2
Make sure that the documentation you are looking at is of the correct version, for 2.2.x you would need this url: http://www.playframework.com/documentation/2.2.x/ScalaOAuth
I'm using Specs2 to test my Scalatra web service.
class APISpec extends ScalatraSpec {
def is = "Simple test" ^
"invalid key should return status 401" ! root401^
addServlet(new APIServlet(),"/*")
def root401 = get("/payments") {
status must_== 401
}
}
This tests the web service locally (localhost). Now I would like to perform the same tests to the production Jetty server. Ideally, I would be able to do this by only changing some URL. Is this possible at all ? Or do I have to write my own (possible duplicate) testing code for the production server?
I don't know how Scalatra manages its URLs but one thing you can do in specs2 is control parameters from the command-line:
class APISpec extends ScalatraSpec with CommandLineArguments { def is = s2"""
Simple test
invalid key should return status 401 $root401
${addServlet(new APIServlet(),s"$baseUrl/*")}
"""
def baseUrl = {
// assuming that you passed 'url www.production.com' on the command line
val args = arguments.commandLine.split(" ")
args.zip(args.drop(1)).find { case (name, value) if name == "url" => value }.
getOrElse("localhost:8080")
}
def root401 = get(s"$baseUrl/payments") {
status must_== 401
}
}
I am trying to write a play! framework 2.1 application with ReactiveMongo, following this sample. however, with every call to the plugin, it seems that the application hangs after the operation completes, than the pluging closes and restarts, and we move on. functionality work, but i am not sure if it's not crashing and restarting along the way.
code:
def db = ReactiveMongoPlugin.db
def nodesCollection = db("nodes")
def index = Action {implicit request =>
Async {
Logger.debug("serving nodes list")
implicit val nodeReader = Node.Node7BSONReader
val query = BSONDocument(
"$query" -> BSONDocument()
)
val found = nodesCollection.find(query)
found.toList.map { nodes =>
Logger.debug("returning nodes list to requester")
Ok(views.html.nodes.nodes(nodes))
}
}
}
def showCreationForm = Action { implicit request =>
Ok(views.html.nodes.editNode(None, Node.nodeCredForm))
}
def create = Action { implicit request =>
Node.nodeCredForm.bindFromRequest.fold(
errors => {
Ok(views.html.nodes.editNode(None, errors))
},
node => AsyncResult {
Node.createNode(node._1, node._2, node._3) match {
case Right(myNode) => {
nodesCollection.insert(myNode).map { _ =>
Redirect(routes.Nodes.index).flashing("success" -> "Node Added")
}
}
case Left(message) => {
Future(Redirect(routes.Nodes.index).flashing("error" -> message))
}
}
}
)
}
logging:
[debug] application - in Node constructor
[debug] application - done inseting, redirecting to nodes page
--- (RELOAD) ---
[info] application - ReactiveMongoPlugin stops, closing connections...
[info] application - ReactiveMongo stopped. [Success(Closed)]
[info] application - ReactiveMongoPlugin starting...
what is wrong with this picture?
There seems nothing wrong with that picture. If you only showed me that log output I would say you would have changed a file in you play application. Which would cause the application to reload.
I guess that is not the case, so your database is probably located within your application directory, causing the application to reload on each change. Where is your database located?