How to test a Java RESTful web service with curl -

2019-08-08 08:09发布

问题:

I'm trying my first Java RESTful web service and probably I don't have clear some mechanisms.

Here an example of my code:

@Path(Paths.USERS)
public class UserService {

    private static final String OK_MESSAGE_USERSERVICE_PUT = Messages.OK_MESSAGE_USERSERVICE_PUT;
    private Client esClient = ElasticSearch.getClient();

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String get(@QueryParam(QParams.ID) String id) {
        // TODO Authentication
        try {
            GetResponse response = esClient
                    .prepareGet(PRIMARY_INDEX_NAME, USERS_TYPE_NAME, id)
                    .execute().actionGet();

            if (response != null) {
                return response.getSourceAsString();
            }


        }catch (ElasticsearchException e) {
            e.printStackTrace();
            return e.getMessage();
        }
        return Messages.RESOURCE_NOT_FOUND;
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    public String update(@QueryParam(QParams.ID) String id,
            @PathParam("metadata") String metadata) {
        // TODO Authentication
        boolean isMyself = true;

        // precondition, the user exsists. If the check fails, you
        // should put the isMyself flag at false.
        if (isMyself){

                    esClient
                    .prepareIndex(PRIMARY_INDEX_NAME, USERS_TYPE_NAME, id)
                    .setSource(metadata).execute().actionGet();
        }

        return OK_MESSAGE_USERSERVICE_PUT;
    }

My problem is:

How should I pass the metadata to the web service? I tried with

 curl -g -X PUT 'http://localhost:8080/geocon/users?id=007&metadata={"name":{"first":"james","last":"bond"}}'

but I encounter an error like

Root Cause: java.net.URISyntaxException: Illegal character in query at index 33: /geocon/users?id=007&metadata=%7B"name":%7B"first":"james","last":"bond"%7D%7D

    java.net.URI$Parser.fail(URI.java:2848)

Googling around, I've tried this different solution:

curl -X PUT -H "application/json" -d '{"name":{"first":"james","last":"bond"}}' http://localhost:8080/geocon/users/

but with this approach, I don't know how to pass to the web service my will of updating the user with ID 007 (since, AFAIK, I'm only communicating {"name":{"first":"james","last":"bond"}}).

How would you do? Thanks!

回答1:

I would completely refactor this solution.

First: Change the url scheme to make the id part of the URI path. This is a more RESTful approach

@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
public String update(@PathParam("id") String id) {

Second: The request entity body should be the JSON. I don't see any reason for this to be "metadata". You can get rid of that altogether. You want to update the resource representation with the data you are sending, so this should be part of the body.

Third: If you're working with JSON, you should take advantage of Pojo Mapping with a provider like Jackson. This will automatically pars the JSON to a Pojo. You can do something like

public class Agent {
    private Name name;
    // getters and setters

    public static class Name {
        private String first;
        private String last;
        // getters and setters
    }  
}

Then just have the Agent argument in the method signature, signifying that it is the body of the request.

@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
public String update(@PathParam("id") String id, Agent agent) {

You will need to add the Jackson provider to the project. Hopefully you are using Maven. You can add

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.4.0</version>
</dependency>

Then in your application configuration, register the JacksonJsonProvider. If you need help with this, then show how you are configuration your application (whether web.xml or an Application subclass). If you want to skip the Pojo mapping and just get the raw JSON, the just set the method argument type to String as you already are doing (just without the annotation)

Fourth: Then your request would be (I'm on Windows, where we need to use double quotes and escape the interior quotes)

curl -v -X PUT
        -H "Content-Type:application/json"
        -d "{\"name\":{\"first\":\"james\", \"last\":\"bond\"}}"
        http://localhost:8080/geocon/users/007

Fifth: I would change the @GET method also, to make the id part of the URL path, instead of a query param.



回答2:

It looks like you mix the way parameters are passed to a GET request (?foo=bar) with a PUT method, which is much more like POST.

I'd expect that you send your JSON data to an URL like /gecon/user/13, of course after having your URL mapping edited properly.

Try reading the wikipedia and this answer.