Your go-to microservice framework for any situation, from the creator of Netty et al. You can build any type of microservice leveraging your favorite technologies, including gRPC, Thrift, Kotlin, Retrofit, Reactive Streams, Spring Boot and Dropwizard.
APACHE-2.0 License
Bot releases are hidden (Show)
It is now statically required to add a Service<? super HttpRequest, ? extends HttpResponse>
when adding a Service
to a ServerBuilder
or a VirtualHostBuilder
. We do not accept Service<?, ?>
anymore.
Using a method reference to the one-arg constructor of a decorator service may not work anymore because of Java compiler's type inference failure. For example, you need to use LoggingService.newDecorator()
instead of LoggingService::new
.
The type of RequestContext.method()
and RequestLog.method()
were changed from String
to HttpMethod
.
RequestContext.path()
and RequestLog.path()
have been split into path()
and query()
.
RequestContext.fragment()
and RequestLog.fragment()
are now nullable.
Revamped PathMapping
to support path variables. You can now do the following:
ServerBuilder sb = ...;
sb.serviceAt("/hello/:name", new AbstractHttpService() {
@Override
protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) {
final String name = ctx.pathParam("name");
res.respond(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, "Hello, %s!", name);
}
});
sb.service(PathMapping.ofRegex("^/files/(?<filePath>.*)$"), new AbstractHttpService() {
@Override
protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) {
final String filePath = ctx.pathParam("filePath");
// ... Serve the file ...
}
});
#567 Inject AggregatedHttpMessage
into a DynamicHttpFunction
method automatically.
#567 Handle a DynamicHttpFunction
method whose return type is AggregatdHttpMessage
.
public class MyAnnotatedHttpService {
@Post
@Path("/upload")
public AggregatedHttpMessage hello(AggregatedHttpMessage uploadRequest) {
...
}
}
CatchAllPathMapping.prefix()
should return '/'
.CompletableFuture
returned by HttpRequest/Response.aggregate()
will not complete forever if the stream is aborted, mostly due to timeout.armeria-retrofit2
should respect the encoded
annotation parameter.armeria-spring-boot
armeria-spring-boot-autoconfigure
armeria-spring-boot-starter
armeria-retrofit2
for cleaner API and @Url
annotation support
PrometheusExporterHttpService
DocService
debug form support for unframed gRPC-JSON
ServiceRequest
into a DynamicHttpService
method automaticallylogging
package to metric
package for consistencyDynamicHttpService
does not allow binding a path without a path variable.ServerBuilder.maxNumConnections()
which allows a user to limit the number of open connections of a Server
.ServerBuilder.maxPendingRequests()
which was never implementedStreamMessage.subscribe(...)
which yields reduced memory copiesBackoff.withJitter()
RandomBackoff
#499 Unframed GRPC support
#504 Allow adding a listener to any EndpointGroup
implementations
Listeneable
and AbstractListenable
as a common utility#507 More convenient deferred construction of RpcResponse
and HttpResponse
Before:
// RpcResponse
DefaultRpcResponse res = new DefaultRpcResponse();
CompletableFuture<Object> future = doAsync();
future.whenComplete((value, cause) -> {
if (cause != null) {
res.completeExceptionally(cause);
} else {
res.complete(value);
}
});
return res;
// HttpResponse
DeferredHttpResponse res = new DeferredHttpResponse();
CompletableFuture<HttpResponse> future = doAsync();
future.whenComplete((actualRes, cause) -> {
if (cause != null) {
res.close(cause);
} else {
res.delegate(actualRes);
}
});
return res;
After:
// RpcResponse
return RpcResponse.from(doAsync());
// HttpResponse
return HttpResponse.from(doAsync());
#507 Add RpcResponse.join()
and RpcResponse.getNow()
#507 Add Exceptions.throwUnsafely()
THttpService
Boolean
type in DynamicHttpService
NullPointerException
when aggregating an HTTP message with a trailing headerAssertionError
in ThriftDocServicePlugin.toTypeSignature()
OrElseEndpointGroup
does not handle dynamic endpoint changes correctly-Djava.net.preferIPv4Stack=true
option to work around it. We will release a new version that depends on the Netty version with the fixes once it's available.#421 #424 Add PathParamExtractor
which extracts parameters from a URI path.
PathParamExtractor e = new PathParamExtractor("/users/{userId}");
assert e.extract("/users/lespinside").get("userId").equals("lespinside");
(Potentially breaking) #461 #483 Support Tomcat 8.5
armeria-tomcat
will support the latest stable Tomcat release.armeria-tomcat8.0
to use Tomcat 8.0.return
in armeria.js
for DocService
AssertionError
due to broken RequestLogAvailabilitySet.of(int flags)
implementation-Djava.net.preferIPv4Stack=true
option to work around it. We will release a new version that depends on the Netty version with the fixes once it's available.#455 #465 Add RequestContext.onChild()
which adds a callback that is invoked when a child context replaces the current context
This is useful especially when you want to inherit an attribute of the current context to its children:
AttributeKey<UserInfo> CURRENT_USER = ...;
RequestContext ctx = ...;
ctx.onChild((curCtx, newCtx) -> {
newCtx.attr(CURRENT_USER).set(curCtx.attr(CURRENT_USER).get());
});
#460 Add DynamicEndpointGroup
which notifies its listeners when its list of Endpoint
s changes
HealthCheckedEndpointGroup
and ZooKeeperEndpointGroup
extends DynamicEndpointGroup
.#471 Provide more simpler ways to write a decorating client/server
Add DecoratingClientFunction
which is similar to DecoratingServiceFunction
:
ServerBuilder sb = new ServerBuilder();
sb.serviceUnder("/my_service",
new MyService().decorate((delegate, ctx, req) -> {
// Intercept an incoming request here.
return delegate.serve(ctx, req);
});
ClientBuilder cb = new ClientBuilder(...);
cb.decorator(HttpRequest.class, HttpResponse.class,
(delegate, ctx, req) -> {
// Intercept an outgoing request here.
return delegate.execute(ctx, req);
});
Add SimpleDecoratingService
and SimpleDecoratingClient
, which is similar to DecoratingService
and DecoratingClient
but with fewer number of type parameters:
public class MyDecoratingService extends SimpleDecoratingService<RpcRequest, RpcResponse> { ... }
public class MyDecoratingClient extends SimpleDecoratingClient<RpcRequest, RpcResponse> { ... }
SerializationFormat
when content-type
is application/x-thrift
without the protocol
parameterNullPointerException
at ServiceRequestContext.toString()
DocService
.proto
file with DocService
.HttpDecodingClient
MediaTypeSet
which provides the methods useful for HTTP content negotiation
SerializationFormat.mediaTypes()
now returns MediaTypeSet
instead of Set<MediaType>
. It should be OK because MediaTypeSet
implements Set<MediaType>
.SessionOption.USE_HTTP1_PIPELINING
-Dcom.linecorp.armeria.defaultUseHttp1Pipelining=false
option to JVM orSessionOption.USE_HTTP1_PIPELINING
option to false
when creating an AllInOneClientFactory
.THttpClient
THttpService
does not handle HTTP accept
header correctly.RequestLog.statusCode()
is not set on server-side timeout.RetryingClient
and RetryingRpcClient
which are decorating clients that retry the requests with flexible retry policy such as exponential back-off with jitters.DocService
for better extensibility
DocServiceBuilder
instead of the DocService
constructor to specify the example HTTP headers and requests.DocService
DocServiceBuilder.exampleRequest(...)
. e.g. builder.exampleRequest(new HelloService.hello_args("foo"));
armeria-thrift
and armeria-thrift-shaded
now depend on libthrift 0.10.0.armeria-thrift0.9
or armeria-thrift0.9-shaded
to use libthrift 0.9.3.HttpHeaders
for better user experience
HttpHeaders
now performs case-insensitive comparisons for header names.HttpHeaders
now accepts the header names with upper-case alphabets and silently lower-cases them.SessionIdManager
RequestContextAwareEventLoop.next()
must return itself, not its delegate.UnsupportedOperationException
when HttpMessage.aggregate()
failsDocService
from Map<Class<?>, Iterable<HttpHeaders>>
to Map<String, Iterable<HttpHeaders>>
because not all RPC protocols use a class name as a service identifierTomcatService
throws a NullPointerException
when a POST request contains an empty body.DocService
fails to handle typedef
-ed types.#395 #407 Hide Guava from the public API and provide the shaded and unshaded JARs
com.google.common.net.MediaType
replaced with com.linecorp.armeria.common.MediaType
com.google.common.collect.Multimap
replaced with java.util.Map<..., Collection<...>>
Multimap
into a Map
using Multimap.asMap()
.-shaded
. For example:
armeria
vs. armeria-shaded
armeria-thrift
vs. armeria-thrift-shaded
#375 #408 Make HttpClient
respect the path specified when creating it. For example:
HttpClient hc = Clients.newClient("none+http://example.com/foo", HttpClient.class);
HttpResponse res = hc.get("/bar"); // This will now send a request to /foo/bar, not /bar
Note: If you were specifying a path when creating an HttpClient
with an old Armeria, your code may stop to work because of this behavioral change. For example:
HttpClient hc1 = Clients.newClient("none+https://api.github.com/zen", HttpClient.class);
hc1.get("/zen"); // 404 - the request is sent to /zen/zen
HttpClient hc2 = Clients.newClient("none+https://api.github.com/", HttpClient.class);
hc2.get("/zen"); // 200 - the request is sent to /zen
com.linecorp.armeria:armeria
to com.linecorp.armeria:armeria-thrift
armeria-thrift
to your dependencies if you are using Thrift.SessionProtocol
and SerializationFormat
are not enum
s anymore.
SessionProtocol
have been deprecated. Use HttpSessionProtocols.*
instead.SerializationFormat
have been deprecated. Use ThriftSerializationFormats.*
instead.DocService
has been changed.
TBase
requests anymore. We are going to add this feature back in less intrusive way in the future.Multimap<Class<?>, HttpHeaders>
.RequestLog
RequestLog.request/responseContent()
returns RpcRequest
and RpcResponse
rather than ThriftCall
and ThriftReply
.ThriftCall
or ThriftReply
, use RequestLog.rawRequest/ResponseLog()
.RequestLogBuilder.request/responseContent(...)
now requires 2 parameters - one for RpcRequest/Response
and the other for ThriftCall/Reply
.DynamicHttpService
asynchronousHttpAuthService
application/vnd.apache.thrift.*
media types in THttpService
Ascii.toLower/UpperCase/equalsIgnoreCase()
to String.toLower/UpperCase/equalsIgnoreCase()
EndpointGroup
naming rule
EndpointGroup
name is now case-insensitive and must match /^[-_.0-9a-zA-Z]+$/
armeria-retrofit2
raises IllegalArgumentException
when the URI scheme is h1
, h1c
, h2
or h2c
.DynamicHttpService
It's much easier to build a non-RPC HTTP service now:
ServerBuilder builder = new ServerBuilder();
// Use annotations (like JAX-RS and Spring Web)
public class MyServiceA extends DynamicHttpService {
@Get
@Path("/int/{var}")
public CompletionStage<Integer> returnInt(@PathParam("var") int var) {
return CompletableFuture.supplyAsync(() -> var);
}
@Get
@Path("/string/{var}")
public String returnString(@PathParam("var") String var) {
return var;
}
}
builder.serviceUnder("/service/a", new MyServiceA());
// Use builder (like SparkJava)
builder.serviceUnder("/service/b", new DynamicHttpServiceBuilder()
.addMapping(HttpMethod.GET, "/int/{var}",
(ctx, req, args) -> Integer.parseInt(args.get("var")))
.addMapping(HttpMethod.GET, "/string/{var}",
(ctx, req, args) ->args.get("var"))
.build());
For the complete example, please see HttpServiceTest.java
.
Please note that this feature is experimental and thus it has some rough edges and its API may change (in a positive direction) in the future. If you have any feed back on the current API, please let us know!
DynamicHttpService
which implements advanced request mappingRequestContext.makeContextAware(CompletionStage)
and makeContextAware(CompletableFuture)
SampledLoggingService
WeightedRoundRobinStrategy
does not refresh min/max/sumWeight
even if endpointGroup
returns different endpoints.okhttp3.Request
object always has 0.0.0.0 authority when armeria-retrofit2 is used.Response
is not completed when timeout is disabled dynamically.ServerBuilder.numBosses(int)
ServerBuilder.serverListener(ServerListener)
armeria-retrofit2
handles a large response.RpcRequest
and RpcResponse
RpcRequest.of()
, RpcResponse.of() and
ofFailure()` for easier instantiationRpcRequest
parametersMetricSet
RequestLog
API
RequestLog
and ResponseLog
have been merged into RequestLog
and rewritten.RequestLogBuilder
and ResponseLogBuilder
have been merged into RequestLogBuilder
and rewritten.ThriftCall
and ThriftReply
have been replaced with DefaultRpcRequest
and DefaultRpcResponse
.ApacheThriftCall
and ApacheThriftReply
have been renamed to ThriftCall
and ThriftReply
.RequestLog
API
RequestLog
.MetricRegistry
.ThriftCompletableFuture
and ThriftListenableFuture
AsyncMethodCallback
and your favorite Future
types.Note: From this release on, the version string will not have the .Final
suffix.
UnitFormatter
to TextFormatter
com.linecorp.armeria.client.routing
to endpoint
MessageLog.start/endTimeNanos()
with durationNanos()
EndpointGroup
implemenetationHealthCheckedEndpointGroup
to select the alive endpointEndpointGroup.orElse(EndpointGroup)
MessageLog.start/endTimeNanos()
with durationNanos()
EndpointGroupException
instead of ArithmeticException
SimpleHttpClient
com.linecorp.armeria.client.routing
to endpoint