Giter Site home page Giter Site logo

rescu's Introduction

ResCU - a lightweight Rest client utility for Java (JAX-RS)

ResCU enables the user to create a proxy Rest client in run-time directly from a JAX-RS annotated interface. ResCU is mostly focused on json-based services, and uses Jackson for json-to-object mapping.

Several other libraries do this (eg. Jersey and RESTEasy); the benefit of ResCU is that it is very lightweight with minimal dependencies. This makes it useful for quickly creating REST clients in Android apps etc.

Dependencies

  • jackson (json parser)
  • slf4j (logging interface)
  • jsr-311 (JAX-RS) (a set of REST-service specific annotations)
  • jsr-305 (a set of annotations)

Features and benefits

  • Lightweight, minimal dependencies.
  • JAX-RS-annotated server-side interfaces may be reused to create clients; basic support is provided for @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS, @Path, @QueryParam, @FormParam, @HeaderParam, @PathParam, @Consumes and @Produces (application/json and text/plain only).
  • Support for basic HTTP authentication and some common request signing paradigms. See the Basic HTTP Authentication wiki.
  • Support for custom exceptions on API methods: on an exceptional HTTP response, rescu can deserialize the response body as an exception. See Exception handling wiki.
  • Suppoft for custom interceptors.

Limitations

  • Rescu is meant mostly for json-based REST services. The response body is always interpreted as json or plain text. No XML, no binary data, and no plans to add it.
  • JAX-RS: No support yet for the following annotations: @MatrixParam, @CookieParam, @ApplicationPath, @HttpMethod, @Encoded, @DefaultValue.

Logging

ResCU uses slf4j for logging. For best results, a supported logging implementation (eg. log4j, JUL, logback, ...) should be provided in runtime, though this is not required. See slf4j's documentation for more info.

See logback.xml in test sources for example configuration.

Set the logging level for rescu to debug or trace in logback.xml for debugging:

<logger name="si.mazi.rescu" level="trace"/>

Usage

Maven

Rescu is hosted in Maven Central so all you need to do is add this dependency to your pom:

<dependency>
    <groupId>com.github.mmazi</groupId>
    <artifactId>rescu</artifactId>
    <version>3.0</version>
</dependency>

Usage in code

  1. Create a JAX-RS-annotated interface (or get it from the REST service developer), eg. ExampleService.java.
  2. Call ExampleService service = RestProxyFactory.createProxy(ExampleService.class, "http://www.example.com/").
  3. That's it! Just use the service object you just got.

Examples

See the tests for some examples. ExampleService is an example of a JAX-RS-annotated interface.

For more working examples, see XChange, eg. BitstampTradeServiceRaw.java.

Settings

Rescu can be configured by adding a rescu.properties file in your classpath.

Supported settings with example values (copy this into your rescu.properties file):

rescu.http.readTimeoutMillis = 5000             # Read timeout in milliseconds when performing HTTP requests. The default is 30000 (30 seconds).
rescu.http.readProxyHost = www.example.com      # Proxy host. Both host and port must be set in order to use a proxy.
rescu.http.readProxyPort = 80                   # Proxy port. Both host and port must be set in order to use a proxy.
rescu.http.readProxyType = SOCKS                # Proxy type. Applied only when readProxyHost and readProxyPort are set. Allowed values: DIRECT, HTTP, SOCKS.
rescu.http.ignoreErrorCodes = true              # If set to true, the HTTP response body never be parsed as Exception but always as the method response type. Defaults to false.

License

Rescu is released under the MIT License. Please see LICENSE.txt for the full text.

rescu's People

Contributors

bigscoop avatar cyrus13 avatar dependabot[bot] avatar dominicwilliams avatar ericanderson1000 avatar ezoer avatar gtoison avatar jpe42 avatar kyr7 avatar martinzima avatar milczarekit avatar mmazi avatar mrmx avatar obsessiveorange avatar pavelniedoba avatar rafalkrupinski avatar sutra avatar timmolter avatar tommuhm avatar tonykwok1992 avatar veken0m avatar wlk avatar zholmes1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

rescu's Issues

Configuring authentication when creating proxy client.

I'm writing an API using jax-rs annotations. I want to create a proxy client in an Android application. The proxy client resource and the server side rest resource implementations are using shared interfaces so there is no mismatch between the client and the server.

I'm securing the API with http basic authentication. The problem is, the resources methods do not have parameters annotated with @HeaderParam("Authorization") because that is handled in a filter before each resource invocation, and not per resource. Other jax-rs proxy clients, such as jersey's, apache's, and rest-easy's configure authentication in separately for example, in jersey:

HttpAuthenticationFeature authentication = HttpAuthenticationFeature.basic(username, password);

WebTarget target = ClientBuilder.newClient(
            new ClientConfig().register(authentication))
            .target(baseUrl);

MyResource proxy = WebResourceFactory.newResource(MyResource.class, target);

I like rescu because it is Android compatible, but I would like to be able to configure authentication when creating the proxy client, not when invoking a method. Thanks for your work on rescu. Let me know if there is a workaround for this, or if this could be supported.

Status Code 500, but need the JSON

Try out: com.xeiam.xchange.examples.mtgox.v2.service.account.WithdrawalFundsDemo.java in xchange-examples.

The status code returned is 500 which causes an HTTPException, but I would like to have the JSON it returns to log the error message.

Any ideas?

isEmpty() not available in Android 2.2

Some Bitcoinium users running Android 2.2 are experiencing crashes because of the isEmpty() function. This function is only available in Android 2.3+

Would you mind using another method to check for empty strings?

Thanks!

java.lang.NoSuchMethodError: java.lang.String.isEmpty
at si.mazi.rescu.RestInvocation.appendIfNotEmpty(RestInvocation.java:142)
at si.mazi.rescu.RestInvocation.(RestInvocation.java:97)
at si.mazi.rescu.RestInvocationHandler.invoke(RestInvocationHandler.java:49)
at $Proxy3.getMarketData(Native Method)
at com.veken0m.cavirtex.BitcoinChartsActivity.getBitcoinCharts(BitcoinChartsActivity.java:76)
at com.veken0m.cavirtex.BitcoinChartsActivity$bitcoinchartsThread.run(BitcoinChartsActivity.java:196)

1.2.0 release?

Hi Matija,

I'd like to release XChange 1.8.0 which depends on rescu 1.2.0. Any chance of a release??

Null returned by getJsonObject in JSONUtils

I wonder if the API could be improved by throwing an exception like on line 68 rather than returning null on line 60. If null is returned, the client will probably stumble upon a NPE.

I'm referencing this issue: knowm/XChange#154

I think it would be better to throw a runtime exception with a nice desciption of what happened. It could even be checked in HttpTemplate before getJSONObject is called.

What do you think?

~Tim

Connection Timeout

Any chance that a connection timeout could be added, in addition to the readTimeout? I'd be happy to do the necessary changes.

error handling

Hi,

indeed a nice lib!
but i just faced an issue, may be you can have a look at it:
si.mazi.rescu. HttpTemplate
Current line 145
https://github.com/mmazi/rescu/blob/develop/src/main/java/si/mazi/rescu/HttpTemplate.java#L145

throw new IOException(String.format("HTTP status code was %d; response body: %s", httpStatus, httpBody));

imho not the best way to throw a simple IOException with a message.
the client, in my case, needs to know, what went wrong, at least the http status is required...

than, does the error come from the http layer or the json parser? no way to know, parsing the message is not an option

best regards
andre

JsonParseException: Unexpected character

I am trying to implement Netagio's new API into XChange but I'm unable to parse their JSON response, due to an odd character in the response which seems to crash Jackson.

Here is the character: http://www.fileformat.info/info/unicode/char/feff/index.htm

The stack trace:

Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Unexpected character ('' (code 65279 / 0xfeff)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
 at [Source: java.io.StringReader@243c4f91; line: 1, column: 2]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1524)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:557)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:475)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddValue(ReaderBasedJsonParser.java:1415)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:679)
    at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3031)

And the raw JSON: http://pastebin.com/raw.php?i=UBxKKSaF

Seems like the exchange is doing something weird when they generate their JSON. There are some other people who have had the same issue. See here: https://stackoverflow.com/questions/10188899/json-object-parsing-error

Any ideas?

More advanced configuration of HttpsURLConnection (certificates)

Hello everybody,
first of all, thanks for the library, although I've just started using it, I kinda like its simplicity! (What do the CU letters in the name stand for by the way? :-D)

I am currently in a position where I need to be able to configure the used HTTP(S) connection in more detail. I would appreciate the possibility to manually set the SSL socket factory (HttpsURLConnection.setSSLSocketFactory) to my own instance. And when we are at this, I guess being able to override the HostnameVerifier (HttpsURLConnection.setHostnameVerifier) wouldn't do much harm either.

I need this to adjust the HTTPS certificate verification process to be able to use our self-signed certificates on our private servers (see http://developer.android.com/training/articles/security-ssl.html#CommonProblems for example). I will probably implement this somehow for myself in the meantime (might commit later?), but for the future users of ResCU, it would be nice if it already had this functionality in stock version.

What do you think?

Fix json to Exception deserialization on Google App Engine

Rescu fails to deserialize json to Exceptions on Google App Engine. Here's a relevant part of the stack trace:

com.fasterxml.jackson.databind.JsonMappingException: Can not access private java.lang.Throwable java.lang.Throwable.cause (from class java.lang.Throwable; failed to set access: java.lang.IllegalAccessException: Reflection is not allowed on private java.lang.Throwable java.lang.Throwable.cause
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:266)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:241)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:381)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3154)

Include a proper license header in source files

It would make it easier to redistribute rescu if each source file contains a license header.

Missing or generated license headers:

src/main/java/si/mazi/rescu/AwareException.java                                 
src/main/java/si/mazi/rescu/ClientConfig.java                                   
src/main/java/si/mazi/rescu/ClientConfigUtil.java                               
src/main/java/si/mazi/rescu/ExceptionalReturnContentException.java              
src/main/java/si/mazi/rescu/HttpResponseAware.java                              
src/main/java/si/mazi/rescu/HttpStatusException.java                            
src/main/java/si/mazi/rescu/HttpStatusExceptionSupport.java                     
src/main/java/si/mazi/rescu/HttpStatusIOException.java                          
src/main/java/si/mazi/rescu/Interceptor.java                                    
src/main/java/si/mazi/rescu/InvocationAware.java                                
src/main/java/si/mazi/rescu/Utils.java                                          
src/main/java/si/mazi/rescu/serialization/jackson/IgnoreThrowableProperties.java
src/test/java/si/mazi/rescu/ExampleException.java                               
src/test/java/si/mazi/rescu/ExampleInvocationAwareException.java                
src/test/java/si/mazi/rescu/ExampleResponseHeadersAwareException.java           
src/test/java/si/mazi/rescu/Http500Exception.java                               
src/test/java/si/mazi/rescu/MessageException.java                               
src/test/java/si/mazi/rescu/ParamsTest.java                                     
src/test/java/si/mazi/rescu/ResponseReaderTest.java                             
src/test/java/si/mazi/rescu/TestTrailingGarbage.java                            
src/test/java/si/mazi/rescu/UtilsTest.java                                      
src/test/java/si/mazi/rescu/serialization/jackson/serializers/EnumIntDeserializerOneBasedTest.java

Top level associative arrays

I have a service I would like to interface with that returns JSON in this structure:

{"1":{"foo":123},
"2":{"foo":456},
"3":{"foo":789}}

This is an associative array where the keys also happen to be an array index. It's also at the top level, rather than assigned to some variable.

Just wondering if there is some way with rescu to deal with this sort of deserialization?

Many thanks.

How to annotate POJO for rest serialization

Coinbase accepts JSON objects for parameters, i.e., https://coinbase.com/api/doc/1.0/accounts/generate_receive_address.html. I'm trying to figure out how to create a POJO so that it will be serialized to JSON, but it looks like it will always just use toString()? Do I have to have the toString produce JSON representing the object?

I was hoping to be able to do something like this:

public class CoinbaseCallbackUrlParam {
public String callback_url;
public String label;
.... }
...
@post
@path("account/generate_receive_address")
CoinbaseReceiveAddress generateReceiveAddress(@FormParam("address") CoinbaseCallbackUrlParam callbackUrl,...);

How to update to newest version in Eclipse/Maven?

I am developing for XChange in Eclipse, and I have the project imported as a Maven project. I need to be able to use the newest version to deal with Netagio's API, but I can't seem to get ResCU to update to the newest version with the necessary commit which removes the byte order mark. I've edited xchange-core's pom.xml to use rescu version 1.7.2-SNAPSHOT, which is reflected in my Maven dependencies. However when I download the source and open HttpTemplate.class I still see the old code in there. Any ideas?

JSONUtils Question

After updating to 1.4.0-SNAPSHOT, I noticed another place that might need to be cleaned up a bit in ResCU: the getJSONString method in JSONUtils. Like the other methods in the class, should it throw RestJsonException rather than JsonProcessingException?

Socket closed after each request

Currently the socket is closed after each request by HttpTemplate.executeRequest -> connection.disconnect()

The problem is that if a connection has a keep-alive header it would automatically be cached and this disconnect prevents this.

I'm now quite sure if the disconnect can just be removed or if it should just be skipped for keep alive requests.

What is the best way to solve this problem?

FYI:

Here is the description for disconnect from the JavaDoc:
Indicates that other requests to the server are unlikely in the near future.

Here are some infos how the connection is cached:
http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html

And some other infos for the HttpUrlConnection:
Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances. Calling the close() methods on the InputStream or OutputStream of an HttpURLConnection after a request may free network resources associated with this instance but has no effect on any shared persistent connection. Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.

Please release 1.4.1

Hi Matija,

I'd like to release XChange 1.10.0.

One quick question though...

I've received an issue regarding an exception sneaking though here: knowm/XChange#192

I've verified this:

com.fasterxml.jackson.core.JsonParseException "Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens

Do you think ResCU could and should catch and wrap this as well?

~Tim

Unable to parse as custom Exceptions when Android app is obfuscated

My Proguard configuration is set up to keep rescu, XChange, Jackson, and Hamcrest. I've decompiled my app and confirmed that the name of the error message ("String message") has remained untouched, even after obfuscation. So why would rescu be unable to parse the response as BitfinexException? Might there be any other libraries that are used for rescu's exception handling that I need to exclude from obfuscation?

Change the default content-type header?

Right now, the default content-type header is application/x-www-form-urlencoded. Using the Consumes annotation, we can set that header. The problem is though that what if I'm sending no request body as is the case for many public marketdata requests? That header shouldn't even be sent.

I think if we were designing this from the beginning, you'd have to explicitly set the Consumes annotation for all requests where containing a request body, and the default is no body and no content-type header. There is no Consumes annotation for "no body".

If we switch it now, ResCU isn't backwards compatible, but it's strange how the default behavior is now.

What do you think?

Please release 1.4.0

Hi Matija,

I'm ready to release XChange, and I need a release of ResCU. No rush.

Synchronized write and producing JSON body

I've just discovered a problem with SynchronizedValueFactory: when a client produces JSON body (@consumes(APPLICATION_JSON)) then all data not passed as a header must be in a single unannotated parameter. If that object contains embedded SVF, RestInvocationHandler won't handle it at all, leaving it to the Jackson serializer.

There are two problems with that:

  1. Jackson won't serialize SVF
  2. ...and even if it did, RestInvocationHandler won't call the method in a synchronized block.

I see these possible solutions:

  1. Let RestInvocationHandler search for SVF inside the unannotated parameter and enable synchronization if found. Also, add serializer for Jackson.
  2. Add a new ResCU annotation @Synchronized to methods and rely on it to enable synchronization; stop looking for SVF in parameters. Because rescu would use exchange proxy object as the monitor, XChange would have to be modified, to keep single proxy instance per exchange (currently instance per PollingService).

I'd go for no. 1.

Dealing with empty json

Hello. I don't understand how you configure mappings when the getHttpBody() in the server response is effectively empty then can not be mapped. This is causing me problems in XChange at the moment.

You have checks here
si.mazi.rescu.ResponseReader

if (isHttpStatusPass) {
if (httpBody == null || httpBody.length() == 0 ){
return null;
} else {
/// do the mapping ??

But the only way I can see of dealing with getting an empty json object back is to do something like this.

if (isHttpStatusPass) {
if (httpBody == null || httpBody.length() == 0 || httpBody.toString().equals("[]")){
return null;
} else {

SSL support

This is a cool framework. I liked the simplicity. Have you tried any performance benchmark of this against RestEasy or Jersey or CXF based clients ? Do you have plans to support SSL.

Include Content-Length as a HeaderParam

Is there any way to include Content-Length as a header? I am getting an HTTP status code 411 from Netagio, which means this parameter is required. When I look at the TRACE log I can see that it is not being included.

Snapshot version not correct?

It looks like the current develop version is 1.2.0-SNAPSHOT. Shouldn't it be 1.2.1-SNAPSHOT since the last release was 1.2.0?

Preventing , in strings being encoded to %2C% or ensuring signature is created post encoding in

Hi,

I am trying to pass a comma seperated string with the folloiwng method, where the order_ID is a string like 1233455,1234324,2123131.

@post
@path(value = "future_orders_info.do")
// @consumes(MediaType.app
OkCoinFuturesOrderResult getFuturesOrders(@FormParam("api_key") String api_key, @FormParam("order_id") String orderId,
@FormParam("symbol") String symbol, @FormParam("contract_type") String contract, @FormParam("sign") ParamsDigest sign) throws IOException;

However when the request is posted, the order_id param is encoded to 1233455%2C1234324%2C2123131, which does not match the params of 1233455,1234324,212313 that were passed to the signature, hence the request is rejected.

I could not see any obvious annotation to prevent the encoding using value=orderid, encode=false does not seem to be supported.

Anyone found a neat way to ensure the params of the post request are not encoded, or the signature is created on the encoded string, pass it in a byte array?

Support text/plain return type

The @Produces annotation is currently completely ignored. Rescu should at least support text/plain in addition to application/json.

Please release 1.6.0

Hi Matija, I'm going to release XChange 2.0.0 soon. Could you deploy a 1.6.0 version?

Much appreciated, Tim

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.