Simple http call inside a Lagom service

1,836 views
Skip to first unread message

Felipe Gusmao

unread,
Jan 6, 2017, 4:10:28 PM1/6/17
to Lagom Framework Users
Hello, everyone and thanks in advance.

I building a prototype for my company. However, I'm not a java programmer.

What I want to accomplish is really simple. I want to make an http call to an external resource inside a lagom service.

Ex       getWikiSearchAPI
           getWikiSearchImpl -> Inside here I want to make a http call to a wikipedia's api endpoint

Can anyone provide me with a snippet or just a clue on how to do this.

Thank you
Felipe

Tim Moore

unread,
Jan 8, 2017, 8:21:13 PM1/8/17
to Felipe Gusmao, Lagom Framework Users
Hi Felipe,

You have a couple of options for integrating with external, non-Lagom services: you could model the external service API as if it were a Lagom service, or you could use an HTTP client library directly.

Modelling as a Lagom service

The recommended approach is to write a service interface for the external service API. In Lagom, a service descriptor contains all of the information needed by the client to make HTTP requests, including the set of paths and HTTP methods, supported by the server and the format for serialized request and response data. You can take advantage of this to communicate with external HTTP services, as long as they use the common HTTP idioms that can be represented by a Lagom service descriptor.

In practice, this would mean creating something like a wikipedia-api sub-project, and writing a WikipediaService interface that declares methods corresponding to the different API requests available in the Wikipedia API. http://www.lagomframework.com/documentation/1.2.x/java/ServiceDescriptors.html

You would create immutable Java objects with that mirror the JSON format used by the Wikipedia API. http://www.lagomframework.com/documentation/1.2.x/java/Serialization.html#Jackson-Modules

Lagom uses a library called Jackson to map Java objects to JSON, and it supports flexible annotations for configuring the mapping. You can learn more about that at https://github.com/FasterXML/jackson-annotations

Then, in your service implementation that needs to communicate with the Wikipedia API, you can bind and inject the service client just as you would with another Lagom service: http://www.lagomframework.com/documentation/1.2.x/java/ServiceClients.html

Lagom will generate a dynamic client that can communicate with the external service. You'll also need to configure the ServiceLocator you're using with the URL of the external service. In development, you can do that in your Maven POM or sbt build.sbt file: http://www.lagomframework.com/documentation/1.2.x/java/ServiceLocator.html#communicating-with-external-services

In this scenario, the main difference between an internal and an external service is that you write an implementation for your internal service interfaces, but you don't for the external ones. From the client perspective, there is no difference.


Using an HTTP client library

If either you prefer not to write a service interface, or the external API you're communicating with can't be specified using the features supported by Lagom service descriptors for some reason, you can use an HTTP client library directly. Lagom does not provide any special support for this at this time; you are free to use any Java HTTP client library. We do recommend, however, using a non-blocking HTTP client library, so that your request threads don't get tied up waiting for responses from the external services, and are able to be used to service other requests while I/O is pending.

Under the hood, Lagom uses the Play Framework's WS library, so this is a good choice: https://www.playframework.com/documentation/2.5.x/JavaWS

This approach is a lower-level API than using a Lagom service interface, and you'll need to handle things like serializing requests and deserializing responses yourself. You also won't get the automatic support for circuit breakers that Lagom service clients have, so be sure to consider how your client will behave if the external service is failing or slow: http://www.lagomframework.com/documentation/1.2.x/java/ServiceClients.html#circuit-breakers


I hope this all makes sense 🙂 Please reply back to the list if you have more questions about this.

Cheers,
Tim


--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lagom-framework/91c7ed55-adf1-4b19-bc67-bb73ea71948a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Tim Moore
Senior Engineer, Lagom, Lightbend, Inc.


tim....@lightbend.com

unread,
Mar 31, 2017, 3:13:18 AM3/31/17
to Lagom Framework Users, fgu...@gmail.com, Samuel Sayag
Just adding some more detail to this thread from discussion on Gitter with Samuel Sayag. He asked if I could share it here.

Here are some answers to your questions about external service modelling:

1 - Suppose a sub project api that declare a service is made, do I have to use namedCall, pathCall or restCall identifier ?

namedCallpathCall and restCall are just different ways to specify the same thing, ultimately. From left to right, they go from more abstract with less control to more concrete and specific. restCall is the most powerful and specific: anything you can declare with namedCall and pathCall can also be declared with restCall. When in doubt, use restCall.

They're all described in detail at https://www.lagomframework.com/documentation/1.3.x/scala/ServiceDescriptors.html#Call-identifiers.

and in the case of path what is the linked between the external services url and the path I decide (is there one ?).

In this situation, you aren't deciding on paths, you are specifying the ones actually used by the external service.A Lagom Service interface is a way of describing how to use a REST API to clients. When you build a Lagom service, you use a Service interface to describe it, so that Lagom can dynamically generate a client. What we're doing here is using a Lagom Service interface to describe a third-party service that isn't built in Lagom. Lagom can still use that interface on the client to dynamically generate a client.

To put this another way: there are two ways to write any kind of specification. You can write the spec first and the build the implementation from the spec. This is what you usually do when building a Lagom service. Alternatively, you could build the implementation first and then reverse engineer a specification from it. This is effectively what you're doing when you integrate a non-Lagom service into Lagom.

If I used named call, how do I specify the method of the external services (GET, POST...) ?

If you don't use restCall, the method is guessed from the request type of the service call: if it's NotUsedGET; otherwise POST.

2 - The external services is declared in sbt build.sbt file. How do I bind the given name of the service when the declaration is done to my api service call ?

External services are declared as a map of name -> URL. The name is the one declared in the Service Descriptor named("someName").



 The following shows how to implement the external call with Lagom (1.3.x). In this example the microservices wish to POST some computer result to an external Web Component.

In the microservices multi-project, an external-call-api subproject has been added with this service declaration.

trait WebComponentService extends Service {

  def send_abstract_stimuli: ServiceCall[AbstractStimuli, NotUsed]

  def send_behavior_3s: ServiceCall[BehavioralState, NotUsed]

  override final def descriptor = {
    import Service._
    named("web-component").withCalls(
      restCall(Method.POST, "/abstract/stimuli", send_abstract_stimuli),
      restCall(Method.POST, "/behavior/3s", send_behavior_3s)
    )
  }
}

 In the build.sbt an external service is declared:

lagomUnmanagedServices in ThisBuild := Map(
"web-component" -> "http://localhost:9000"
)
 
Note that the name "web-component" is corresponding to the descriptor declaration.

This is an example of the binding that has been made in the abstract "Application" class of one of the microservices implementation (the one that want to operate the external calls)

abstract class xxxxxApplication(context: LagomApplicationContext)
extends LagomApplication(context)
with AhcWSComponents {

// Bind the services that this server provides
override lazy val lagomServer = LagomServer.forServices(
//.. some server binding ...
)

lazy val webComponentService = serviceClient.implement[WebComponentService]

// ... some other lazy val serviceClient declaration ...
}

Hope it will help other beginners...
Reply all
Reply to author
Forward
0 new messages