Java API

Discussion in 'Shapeways API' started by entertailion, Mar 28, 2013.

  1. entertailion
    entertailion New Member
    I'm working on a Java library to call the Shapeways API. I'm planning on using it for an Android app. I've got the basic OAuth flows working but I have some questions:
    1. Why is the API based on OAuth 1.0? Most other web API's are based on either OAuth 1.0a or OAuth 2.0. Any plans to update?
    2. There are some inconsistencies for the path formats for invoking the API. For example, "/materials/v1" for materials and "/material/{materialId}/v1" for a particular material makes sense. But then "/printers/v1" for printers and "/printers/{printerId}/v1" for a printer doesn't follow the same singular pattern (i.e "/printer/{printerId}/v1").
    3. The JSON format of the results are not consistent. For example, the list of printers ("/printers/v1") are returned as a JSON array, but the list of materials ("/materials/v1") are not using the same array ("[ ]") notation.
    4. The results contain duplicated data. For example, the list of all materials ("/materials/v1") has an ID for each material that is duplicated. The result for "/api/v1/" returns duplicated data about the rate limits.
    5. Why isn't HTTPS supported for the API?

    I'm trying to come up with a generic design to invoke the API and parse the JSON responses, but these inconsistencies is making it more difficult than it needs to be. Are there any plans to update the API?

    Last edited: Mar 28, 2013
  2. admin_nathan
    admin_nathan New Member
    Hey there,

    Shapeways API is OAuth1.0a compliant.

    There was a bug in the docs - it should be "/materials/{materialId}/v1". /material/ and /printer/ also work for the time being, but those URIs will be phased out eventually, so please do not rely on them.

    Materials are intentionally returned as an object of objects. The key value is the material id and the same pattern is used for material objects in /models requests. However, you make a good point about consistency of lists and I will raise this concern.

    The materials object of objects uses material id as the key, and also includes the material id in the object itself. This is intentional.
    /api/v1 returns duplicate data for backwards compatibility reasons and will be phased out. Only the rate limit object should be used. Please use the developer docs ( as a guide for request parameters and return values that you can expect to be supported.

    I believe that HTTPS protocol for the API will be supported in the future.

    Aside from the LIST materials object (instead of the typical LIST array), do you still have any consistency concerns? Much thought goes into the nomenclature and structure of the API. I can't promise that you'll be able to completely rely on a generic design, but our design decisions should be intuitive enough for you to know what to expect. Of course, if they aren't, please do let us know :)

    Thank you!

    - Nathan
  3. entertailion
    entertailion New Member
    Thanks for the detailed response.

    All the Java libraries I found for OAuth 1.0a and 2.0 requires the request, access and authorization URL's to be provided. Since the Shapeways docs only mentioned the request and access URL's, I assumed it was OAuth 1.0.

    The only path that is left singular is for prices ("/price/v1").

    The JSON libraries I tried prefers the array notation and can automatically do data binding. I had to manually parse the "objects of objects" notation.

    I have seen some other inconsistencies. I'm making my way through all of the API's. I'll make a list and post it when I'm done.

  4. entertailion
    entertailion New Member
    For the " /models/v1/" API, the model attributes all have "model" prefixes like "modelVersion" and "modelTitle". But the "/materials/v1" API does not use prefixes for most of the attributes like "title" and "swatch". It probably makes sense to have a consistent naming convention for attributes across all API calls.

    The "nextActionSuggestions" response value isn't consistent. The "/api/v1/" returns a value. For the "/printers/v1" API, the doc says it should have a "nextActionSuggestions" response value, but I don't get any. For some of the other API calls like "/models/v1/" it always has an empty value. Not a critical issue since its unclear why this attribute would be useful especially for a native app.

    Error handling isn't documented for the API. The only response status that is documented is the "result" field and only the "success" value is mentioned for all the API calls. What is the expected response for invalid parameters, missing parameters or server-side errors? Are error codes used or are HTTP response codes used?

    I've open sourced the code for an Android app that calls the Shapeways API:

    The GET API calls are working. I can't get the POST API calls to work; not sure what the issue is. I'm not an OAuth expert and since I couldn't get the OAuth libraries to work with the Shapeways API, I had to cobble some client code together to make it work.

    Last edited: Mar 30, 2013
  5. entertailion
    entertailion New Member
    I've updated the app code to use a hybrid approach for OAuth: the request token, access token and authorization is done with my client-side code; then I use an OAuth library for the rest of the API calls using the access token and secret.

    I can now see the errors generated when I do a POST API call. For example, if I call the "/orders/cart/v1" API, I get the following:
    {"result":"failure","reason":"\n Field <modelId> is required, but missing."}
    However, I did pass the "modelId", "materialId" and "quantity" parameters to the POST, so I'm confused why there is an error.

    Also, I'm now using the Apache Commons HTTP library, since there's a bug in Android's that keeps it from working with some service providers. I've checked in the latest code:

  6. entertailion
    entertailion New Member
    I got the POST API calls working. I had been assuming the parameters were passed as HTTP parameters, but they need to be encoded in JSON and submitted as the body of the POST request.
  7. admin_nathan
    admin_nathan New Member
    Good work!

    Invalid requests should return a 500 code along with the reason that the request failed (if available). Rate limited requests will return a 429. Oauth related errors return 401 and unimplemented method errors return 405.

    The API docs page does not contain error responses, although the API discovery system (learn more about that on the getting started page does reveal the basic error response.

    - Nathan
  8. entertailion
    entertailion New Member
    More comments:
    1. The documentation should show examples of the parameters that need to be passed to the API and show examples of the expected response from the API. For example, the order list of cart items ("GET /orders/cart/v1") and list of models ("GET /models/v1/") are not documented.
    2. "GET /models/{modelId}/info/v1" requires the "modelId" parameter. Since the "modelId" is part of the path, its not clear why the id needs to be duplicated in the request. My testing shows it works even if the parameter isn't provided. The "DELETE /models/{modelId}/v1/" API requires a "modelId" parameter but I don't think HTTP allows that for DELETE (The Apache HTTP library doesn't allow DELETE requests to set a body)
    3. I uploaded various model file names like "original, id=52936.stl" and the JSON results and parsing were all good. Looks like the API handles special characters.
    4. It would be great if there was a developer sandbox or test account support so that developers can test orders without using real money.

    I've updated the Android example app with the latest code:
    The app can do OAuth and the various GET, POST and DELETE API's. I'm planning to add more features to the app like a storefront, shopping cart and STL viewer.
  9. hans_lambermont
    hans_lambermont Shapeways Employee Dev Team
    They are documented in the JSON discovery at and . (You might need a JSON View addon for your browser , get it at
    The html documentation should also have this info, I'll raise that point internally.

    The idea is that the modelId is only given in the path. From :
    "parameters": {
        "modelId": {
            "type": "int",
            "description": "Model id",
            "location": "path",
            "dependencies": "required"
    I'll raise this internally. I think we should have a whiltelist of allowed characters.

    Yes, we want to add this.

    -- Hans
  10. leforthomas
    leforthomas New Member

    I had a good look at your Android library, thanks a lot for making it open source.

    I started (and would like to finish) building my own Java library and am currently stuck with the same problems you had on POST. My GET commands work but not my POSTs. I was hoping you could have a quick look and let me know if there is anything obviously wrong with my implementation.

    I am basing my library on scribe, which is quite popular for Oauth, may be you tried it?

    First I create my oAuthRequest
    OAuthRequest oAuthRequest = new OAuthRequest(Verb.POST, serviceURL);
    I then add the parameters to the body as json encoded
    I set the headers
    oAuthRequest.addHeader("Content-Type", "application/json; charset=utf-8");
    oAuthRequest.addHeader("Accept", "application/json");
    and sign my request
    service.signRequest(accessToken, oAuthRequest);
    and finally send my request
    Response oAuthResponse = oAuthRequest.send();

    The response is always 500 Internal Server error.

    If I look at the actual message sent,
    (1) body content is my json encoded string, eg {"modelId":1773183} for the post cart.
    (2) Url is my API endpoint, eg
    (3) My headers are set for content type and accept and the OAuth Authorisation header is as follows
    Authorization=OAuth oauth_signature="UpmlcoxxxxxxxxxxxxjYY%3D", oauth_version="1.0", oauth_nonce="2003439524", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="45bxxxxxxxxxxxxxxxxxxxd58d308", oauth_token="e3aebxxxxxxxxxxxxxxxxxxx03a2af2", oauth_timestamp="1410427574"


  11. xerces
    xerces New Member
    I have a working java impl based on Scribe and GSON. The only difference I see is that I don't touch the headers. A cut & paste from a price req:

    String url_string = BASE_URL + PRICE_URL;
    OAuthRequest request = new OAuthRequest(Verb.POST, url_string);
    service.signRequest(accessToken, request);

    Response response = request.send();
    InputStream is = response.getStream();
  12. leforthomas
    leforthomas New Member
    Hi, thanks a lot for your reply. I tried without the headers but I get the same cryptic (and useless really...) '500 internal error'.

    Given that we both use Scribe (I use v1.3.5), my only option left is the parameters being passed.

    For the cart test, I have the following payload


    The id is correct and corresponds to one of my models.

    I am on the dev server but I suppose this is not an issue.

    Not sure what to try now...
  13. xerces
    xerces New Member
    I also am using scribe 1.3.5.

    I always include material and quantity in cart requests. api doc does say they are optional though.
  14. leforthomas
    leforthomas New Member
    Nope. Thanks for your suggestion anyway.

    Is there anybody from Shapeways on the forum? I wonder if it is possible to get more information than the 500 HTTP error code I get... may be it means something in itself?
  15. ProfessorBeekums
    ProfessorBeekums New Member
    There is usually a response body that goes with the 500 error to show why there was a 500. If so, please send that over.

    If there is no response body, please capture the packets with wireshark or a web proxy like Charles and attach the files.

  16. leforthomas
    leforthomas New Member

    Thanks for helping out!

    The body of the response is always null, no data.

    Here is the message being sent, it's a Cart POST:

    POST /orders/cart/v1 HTTP/1.1
    Authorization: OAuth oauth_signature="7BKKmJiF8vlik67223M7mGSa2tY%3D", oauth_version="1.0", oauth_nonce="-108383452", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="45b191241ebd672bddf04b3fe3d5b691ed58d308 ", oauth_token="0977b73f3ee66747fa4f3333d7dafd52789b16f", oauth_timestamp="1410815847"
    Accept: application/json
    Content-Type: application/json; charset=utf-8
    Cache-Control: no-cache
    Pragma: no-cache
    User-Agent: Java/1.7.0_45
    Connection: keep-alive
    Content-Length: 53

    {"modelId":"1773183","materialId":"6","quantity":"1 "}
    Last edited: Sep 17, 2014
  17. leforthomas
    leforthomas New Member
    After further investigation I realised the body wasn't empty as I initially said, there is indeed an error message being passed, and it seems the problem comes from the parameters I am passing to the API, eg "Cannot add model 1773183 , material 6 to cart" for the Cart example.
    Appologies for not seing this before and thanks to all who helped out!