I am developing an API in a microservice for Invoice entity that takes in input a list of Purchase Order Item (i.e. PO Item) identifiers for ex. PO# + productIdentifier together can be used to identify a POItem uniquely. The response of the API is the invoiced quantity of each PO Item.
Input Model -
input GetInvoicedQuantityForPOItemsRequest {
poItemIdentifierList : POItemIdentifierList
}
Structures
list POItemIdentifierList {
member : POItemIdentifier
}
structure POItemIdentifier {
purchaseOrderNumber : String,
productIdentifier : Long
}
Invoiced Quantity of a POItem = SUM of Quantity of Invoice Items created from that PO Item.
Note : A single PO can be used to create multiple Invoices. An Invoice can be created from multiple POs.
I am quite new to REST and so far we have been using RPC endpoints in our legacy service. But now i am building a new service where i am defining endpoints in REST format (for ex. CreateInvoice has been changed to POST /invoice) and I need some suggestions from Stack Overflow community what would be the right approach for defining the REST endpoint of this API or should we keep it in RPC format itself.
RPC endpoint for this API in legacy system : POST /getInvoicedQuantityForPOItems
Our first attempt on REST for this is : POST /invoice/items/invoicedQuantityForPOItems. But this URI does not look like a Noun it is a Verb.
this URI does not look like a Noun it is a Verb.
REST doesn't care what spelling conventions you use for your resource identifiers.
Example: this URI works exactly the same way that every other URI on the web works, even though "it looks like a verb"
https://www.merriam-webster.com/dictionary/post
The explanation is that, in HTTP, the semantics of the request are not determined by parsing the identifier, but instead by parsing the method token (GET, POST, PUT, etc).
So the machines just don't care about the spelling of the identifier (besides purely mechanical concerns, like making sure it satisfies the RFC 3986 production rules).
URI are identifiers of resources. Resources are generalizations of documents. Therefore, human beings are likely to be happier if your identifier looks like the name of a document, rather than the name of an action.
Where it gets tricky: HTTP is an application protocol whose application domain is the transfer of files over a network. The methods in HTTP are about retrieving documents and metadata (GET/HEAD) or are about modifying documents (PATCH/POST/PUT). The notion of a function, or a parameterized query, doesn't really exist in HTTP.
The usual compromise is to make the parameters part of the identifier for a document, then use a GET request to fetch the current representation of that document. On the server, you parse the identifier to obtain the arguments you need to generate the current representation of the document.
So the identifier for this might look something like
/invoicedQuantityForPOItems?purchaseOrder=12345&productIdentifiers=567,890
An application/x-www-form-urlencoded representation of key value pairs embedded in the query part of the URI is a common spelling convention on the web, primarily because that's how HTML forms work with GET actions. Other identifier conventions can certainly work, though you'll probably be happier in the long term if you stick to a convention that is easily described by a URI template.
Related
For example, should controller return updated entity after update?
To fit into your question we can set the "best practices" in the range of the verbs. What is the best option to return for each verb?
I'm going to use the book RESTful Web Services (Chapter 4) to answer your question.
This is textual iformation from the book, none of the following words are mine.
GET
The server sends back a representation in the response entity-body.
POST
Response of POST request usually has an HTTP status code of 201 ("Created"). Its Location header contains the URI of the newly created resource.
PUT
The entity-body contains the client's proposed new representation of the resource. What data this is, and what format it's in, depends on the service.
DELETE
The response entity-body may contain a status message or nothing at all
HEAD
Retrieve a metadata-only representation.
A client can use HEAD to check wheter a resource exists, or find out other information about the resource, without fetching its entire representation. HEAD gives you exactly what a GET request would give you, but without the entity-body
OPTIONS
Contains the HTTP Allow header, which lays out the subset of the uniform interface this resource supports.
I am pondering about schema design with regard to explicit vs implicit relation when to...
for example:
in an imaginary schema with 2 custom types author and post, each with several properties, A post type can reference an author in 1 of 2 ways:
explicit: having an Autor type property
implicit: having a scalar value that indirectly points to the author
when designing a shema. what should be my compass in this kind of desicion making?
thanks in advance
There's absolutely no value to the client in only returning the ID of a related resource when you could just expose a field that would return the entire resource. Exposing only the ID will mean the client will have to make subsequent requests to your service to fetch the related resources, instead of being able to fetch the entire data graph in one request.
In the context of other services, like a REST API, it might make sense to only return the ID or URL of a related resource. This is because in those cases, the payload is of a fixed size, so returning every related resource by default can quickly and unnecessarily bloat a response. In GraphQL, however, request payloads are client-driven so this is not a concern -- the client will always get exactly what it asks for. If the client needs only the author's ID, they may still fetch just that field through the author field -- while allowing a more complete Author object to be fetched in other requests or by other clients.
I'm thinking about using Stormpath with it's Java API as a user storage.
Looks good, except that I can't search for users.
For example, I get this error:
Exception in thread "main" com.stormpath.sdk.resource.ResourceException: HTTP 400, Stormpath 2105 (http://docs.stormpath.com/errors/2105): Account ID is not a supported query property.
when I execute this query:
HashMap<String, Object> queryParams = Maps.newHashMap();
queryParams.put("ID", "4mPXXXXXXXXXX");
searchResult = application.getAccounts(queryParams);
Searching for a user by e-mail however works. I get the same error when I try to search a user by a login-token I stored in the customData property.
It looks like what I want to do is not possible as it looks like the only properties you can query are e-mail and username. But why would they provide this functionality if it didn't work. What am I missing?
There is an impedance mismatch between common relational database behaviors and those in a REST API. Querying by id, while common in relational databases, is not idiomatic behavior for REST APIs (or most HTTP-based web sites). The URL (href) is the canonical 'pointer' to a resource on the web. In other words, in REST APIs, the canonical identifier is the href. Any token inside an href (any internal 'id', special characters, whatever) should be opaque to REST clients and ignored by clients entirely. URLs are king in HTTP and REST.
That being the case, the Stormpath SDK tries to be true to RESTful best practices, so you can obtain any Stormpath resource by using the client.getResource method, which accepts an href and the type of object you expect that href to represent:
String href = "https://api.stormpath.com/v1/accounts/" + id;
Account account = client.getResource(href, Account.class);
That said, there's nothing wrong with wanting this to be more conveniently represented in the client API, for example, client.getAccount(String id) if you want to keep the notion of IDs. If so, please open a new feature request and we'll be very happy to consider it.
As for queryable Account properties, those are documented here. Stormpath will soon make data in Custom Data searchable as well. While Stormpath feature timelines are never announced, it is the company's highest engineering priority and it should be out soon.
One workaround that is helpful for some people is to store data they want to search in Account Fields that you don't use in your applications. For example, you could use the 'middle name' field to store, say, favorite color. This would only be temporary until custom data search is available. HTH!
I want to build a typical mvc app for CRUD of simple items, the api s should be RESTful. The catch here is, that i have a large pallete of items that needs to be initialized. On the server side those items are defined as java beans and the corresponding create form for the item is dynamically created from the field information(data type, validation constraints etc) harvested from the bean.
I am new to REST and just read up about how the urls should be nouns defining the resource and action specified by HTTP verb. In that perspective how to model something like
.../client/showForm?type=xyz from non RESTful way to RESTful one ?? My intention here is to tell the server to dynamically construct and send back a CREATE form for client of type xyz. The obvious problem with url i mentioned above is that it specifies action in the url which, from what i have read, makes it non RESTful.
When I think of REST, I think of resources. I think of data. In other words, I don't think of REST as being something that I would typically use to retrieve a form, which is a user interface component.
REST is an architectural style that is used to identify a resource on a server using a uniform resource identifier, or URI. Additionally, actions performed on those resources identified by the URI are determined based on the specific HTTP Method used in the request: GET, POST, PUT, DELETE, etc.
Thus, let's say you have a Client object. That client object might have the following properties:
Name
Location
AccountNumber
If I wanted to retrieve the data for a single client, I might use the following URI:
GET /client/xyz/ # xyx is the accountnumber used to identify the client.
I would use a GET method, since REST describes GET as being the method to use when retrieving data from the server.
The data could theoretically be returned in HTML, since REST is not a standard but more like a series of flexible guidelines; however, to really decouple my data from my user interface, I would choose to use something platform independent like JSON or XML to represent the data.
Next, when adding a client to the collection on the server, I would use the /client/ URI pattern, but I would use the HTTP Method POST, which is used when adding a resource to a collection on the server.
# Pass the data as JSON to the server and tell the server to add the client to the
# collection
POST /client/ {"accountnumber":"abc" , "Name" : "Jones" , "Location" : "Florida"}
If I were to modify an existing record on the server or replace it, I would most likely use the HTTP Method PUT, since REST guidelines say that PUT should be used if repeating the same operation repeatedly would not change the state of the server.
# Replace the client abc with a new resource
PUT /client/abc/ {"accountnumber":"abc" , "Name" : "Bob Jones" , "Location" : "Florida"}
The general idea behind REST is that it is used to identify a resource and then take action on that resource based on what HTTP Method is used.
If you insist on coupling your data with your view, one way accomplish this and retrieve the actual form, with the client data, could be to represent the form as a resource itself:
GET /client/abc/htmlform/
This URL would of course return your client data for client abc, but in an HTML form that would be rendered by the browser.
While my style of coding utilizes data transports such as JSON or XML to abstract and separate my data from my view, you could very well transport that data as HTML. However, the advantage of using JSON or XML is that your RESTful API becomes platform independent. If you ever expand your API to where other developers wish to consume it, they can do so, regardless of what specific platform or programming language they are using. In other words, the API could be used my PHP, Java, C#, Python, Ruby, or Perl developers.
In other words, any language or platform that can make HTTP requests and can send GET, POST, PUT, DELETE requests can be used to extend or build upon your API. This is the true advantage of REST.
For more information on setting up your controllers to use REST with Spring MVC, see this question. Additionally, check out the Spring MVC Documentation for more information.
Also, if you haven't checked out the Wikipedia article on REST, I strongly encourage you to do so. Finally, another good, classic read on REST is How I Explained REST To My Wife. Enjoy.
I am trying to make a RESTful api and have some function which needs credentials. For example say I'm writing a function which finds all nearby places within a certain radius, but only authorised users can use it.
One way to do it is to send it all using GET like so:
http://myapi.heroku.com/getNearbyPlaces?lon=12.343523&lat=56.123533&radius=30&username=john&password=blabla123
but obviously that's the worst possible way to do it.
Is it possible to instead move the username and password fields and embed them as POST variables over SSL, so the URL will only look like so:
https://myapi.heroku.com/getNearbyPlaces?lon=12.343523&lat=56.123533&radius=30
and the credentials will be sent encrypted.
How would I then in Sinatra and Ruby properly get at the GET and POST variables? Is this The Right Way To Do It? If not why not?
If you are really trying to create a restful API instead if some URL endpoints which happen to speak some HTTP dialect, you should stick to GET. It's even again in your path, so you seem to be pretty sure it's a get.
Instead of trying to hide the username and password in GET or POST parameters, you should instead use Basic authentication, which was invented especially for that purpose and is universally available in clients (and is available using convenience methods in Sinatra).
Also, if you are trying to use REST, you should embrace the concept of resources and resoiurce collections (which is implied by the R and E of REST). So you have a single URL like http://myapi.heroku.com/NearbyPlaces. If you GET there, you gather information about that resource, if you POST, you create a new resource, if you PUT yopu update n existing resource and if you DELETE, well, you delete it. What you should do before is th structure your object space into these resources and design your API around it.
Possibly, you could have a resource collection at http://myapi.heroku.com/places. Each place as a resource has a unique URL like http://myapi.heroku.com/places/123. New polaces can be created by POSTing to http://myapi.heroku.com/places. And nearby places could be gathered by GETing http://myapi.heroku.com/places/nearby?lon=12.343523&lat=56.123533&radius=30. hat call could return an Array or URLs to nearby places, e.g.
[
"http://myapi.heroku.com/places/123",
"http://myapi.heroku.com/places/17",
"http://myapi.heroku.com/places/42"
]
If you want to be truly discoverable, you might also embrace HATEOAS which constraints REST smentics in a way to allows API clients to "browse" through the API as a user with a browser would do. To allow this, you use Hyperlink inside your API which point to other resources, kind of like in the example above.
The params that are part of the url (namely lon, lat and radius) are known as query parameters, the user and password information that you want to send in your form are known as form parameters. In Sinatra both of these type of parameters are made available in the params hash of a controller.
So in Sinatra you would be able to access your lon parameter as params[:lon] and the user parameter as params[:user].
I suggest using basic or digest authentication and a plain GET request. In other words, your request should be "GET /places?lat=x&lon=x&radius=x" and you should let HTTP handle the authentication. If I understand your situation correctly, this is the ideal approach and will certainly be the most RESTful solution.
As an aside, your URI could be improved. Having verbs ("get") and query-like adjectives ("nearby") in your resource names is not really appropriate. In general, resources should be nouns (ie. "places", "person", "books"). See the example request I wrote above; "get" is redundant because you are using a GET request and "nearby" is redundant because you are already querying by location.