Статьи

Отдых с Scala и Vert.x

Предыдущий пост представил некоторые особенности использования Scala с
Vert.x . В этом посте рассказывается, как изящно и просто публиковать веб-сервисы Rest.

Как и в предыдущем посте, представлены примеры на Java и Scala, исходный код размещен на GitHub как часть lang-scala https://github.com/ouertani/vert.x/tree/master/vertx-lang/vertx-. Ланг-Скала

I- Resticle

Resticle — это единица развертывания, посвященная отдыху . Он предоставляет новый метод («дескрипторы»), который может использоваться Vert.x для запуска служб Rest. «Handles» возвращает последовательность обработчиков отдыха:

  • RestHandler: Action => Ответ
  • Действие:

    • GET (рисунок: строка)
    • POST (шаблон: строка)
    • PUT (рисунок: строка)
    • УДАЛИТЬ (рисунок: строка)
    • ГОЛОВА (рисунок: Строка)
    • ВСЕ (образец: строка)
  • Ответ: HttpServerRequest => Любой

    • ОК, Несанкционированный, ….

В этом уроке мы будем работать с классом SampleResticle для scala и java.

II — Hello World

Vert.x предоставляет мощный механизм маршрутизации и сопоставления маршрутов , который упрощает маршрутизацию HTTP-запросов к различным обработчикам на основе сопоставления с шаблоном в пути запроса.

В фрагменте Hello World давайте опубликуем статический сервис GET:

  • ПОЛУЧИТЬ: / привет → код: 200, тело: мир
Scala
			
class SampleResticle extends Resticle 
{
  override def handles = 
         { GET("/hello")      :>  OK( _ => "world ") }
}
Ява
public class SampleResticle extends Verticle {
 
    public void start() {
        HttpServer server = vertx.createHttpServer();
        RouteMatcher routeMatcher = new RouteMatcher();
        routeMatcher.get("/hello", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =200;
                req.response.end("world");
            }
        });
        server.requestHandler(routeMatcher).listen(8080, "localhost");
    }
}

III- Цепные погрузчики

Используя Resticle, мы можем легко завершить работу обработчиков цепочек. Следующие фрагменты создают статические сервисы GET и DELETE:

  • ПОЛУЧИТЬ: / привет → код: 200, тело: мир
  • УДАЛИТЬ: / posts → код: 401, тело: не разрешено пользователю
Scala
class SampleResticle extends Resticle 
{
  override def handles = 
         { GET("/hello")      :>  OK( _ => "world ") } ++
         { DELETE("/posts")   :>  Unauthorized {_ => "Not allowed user" }} 
}
Ява
public class SampleResticle extends Verticle {
 
    public void start() {
        HttpServer server = vertx.createHttpServer();
        RouteMatcher routeMatcher = new RouteMatcher();
        routeMatcher.get("/hello", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =200;
                req.response.end("world");
            }
        });
         routeMatcher.delete("/posts", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =401;
                req.response.end("Not allowed user");
            }
        });
        server.requestHandler(routeMatcher).listen(8080, "localhost");
    }
}

IV — Ценность пути

Сопоставление с образцом Vert.x позволяет извлечь значения из пути и использовать их в качестве параметров в запросе.

  • ПОЛУЧИТЬ: / привет → код: 200, тело: мир
  • УДАЛИТЬ: / posts → код: 401, тело: не разрешено пользователю
  • POST: /: blogname → code: 200, body: post {blogname} получено!

 

Scala: (с использованием строковой интерполяции )
class SampleResticle extends Resticle 
{
  override def handles = 
         { GET("/hello")      :>  OK( _ => "world ") } ++
         { DELETE("/posts")   :>  Unauthorized {_ => "Not allowed user" }} ++
         { POST("/:blogname") :>  OK {req  => val param = req.params().get("blogname") ; s"post $param received !" } }
}
Ява
public class SampleResticle extends Verticle {
 
    public void start() {
        HttpServer server = vertx.createHttpServer();
        RouteMatcher routeMatcher = new RouteMatcher();
        routeMatcher.get("/hello", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =200;
                req.response.end("world");
            }
        });
         routeMatcher.delete("/posts", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =401;
                req.response.end("Not allowed user");
            }
        });
 
         routeMatcher.post("/:blogname", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =200;
                String blogName = req.params().get("blogname");
                req.response.end("post "+blogName+ " received !");
            }
        });
 
        server.requestHandler(routeMatcher).listen(8080, "localhost");
    }
}

V- Json

Предположим, у нас есть класс Blog с двумя строковыми полями title и content:

case class Blog (title :String , content : String)

Java-эквивалент был перемещен в конец документа из-за его многословия;).

Публикация объекта с использованием Resticle проста и прозрачна благодаря неявному конвертеру: T => Buffer.

Скала (Тип Класс)
object Blog {
  implicit def toBuffer(blog : Blog):Buffer = JsonObject.withString("title" -> blog.title).withString("content" -> blog.content)
}
Java (с явным конвертором)
public class Convertor {
    public static  JsonObject toJson(Blog blog) {
       return new JsonObject().putString("title", blog.getTitle()).putString("content", blog.getContent());
    } 
}
  • ПОЛУЧИТЬ: / привет → код: 200, тело: мир
  • УДАЛИТЬ: / posts → код: 401, тело: не разрешено пользователю
  • POST: /: blogname → code: 200, body: post {blogname} получено!
  • GET: /: id → code: 200, body: {«title»: «rest», «content»: «scala & vertx»}
Scala
class SampleResticle extends Resticle 
{
  override def handles = 
         { GET("/hello")      :>  OK( _ => "world ") } ++
         { DELETE("/posts")   :>  Unauthorized {_ => "Not allowed user" }} ++
         { POST("/:blogname") :>  OK {req  => val param = req.params().get("blogname") ; s"post $param received !" } } ++
         { GET("/:id")        :>  OK ( _ => Blog("rest","scala & vertx"))}
}
Ява
public class SampleResticle extends Verticle {
 
    public void start() {
        HttpServer server = vertx.createHttpServer();
        RouteMatcher routeMatcher = new RouteMatcher();
        routeMatcher.get("/hello", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =200;
                req.response.end("world");
            }
        });
         routeMatcher.delete("/posts", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =401;
                req.response.end("Not allowed user");
            }
        });
 
         routeMatcher.post("/:blogname", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =200;
                String blogName = req.params().get("blogname");
                req.response.end("post "+blogName+ " received !");
            }
        });
 
        routeMatcher.get("/:id", new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                req.response.statusCode =200;
                Blog blog =  new Blog("rest","scala & vertx");
                JsonObject obj = Convertor.toJson(blog);
                req.response.end(obj.encode());
            }
        });
 
        server.requestHandler(routeMatcher).listen(8080, "localhost");
    }
}

Блог Java

public class Blog {
 
    private final  String title;
    private final String content;
 
    public Blog(String title, String content) {
        this.title = title;
        this.content = content;
    }
 
    public String getTitle() {
        return title;
    }
 
    public String getContent() {
        return content;
    }
  }

Вывод

Несмотря на то, что Resticle находится на первом этапе разработки, поддержка Rest намного проще и элегантнее в Scala, чем в Java. Как описано в первом уроке, Java-версия Vert.x обременена пугающим количеством обработчиков. Будет ли Vert.x 2.0 решать эту проблему с помощью API Promises / Deferred  ?