If I have an apiary.io API described like this:
### Create a User [POST]
+ Request (application/json; charset=utf-8)
{
"user_id": 1053,
"username": "demo#demo.com",
"email": "demo#demo.com",
"active": "true"
}
+ Response 201 (application/json)
{
"user_id": 1053,
"username": "demo#demo.com",
"email": "demo#demo.com",
"active": "true"
}
When I call it from my application and pass it data, it will always pass me back the described payload no matter what data I pass in.
Is there a way to get it to echo back the exact data that I passed in instead of the described payload?
According to Apiary docs/examples you can not, only static request-response mocking. Also you could track this issue.
If you want to use kind of advanced mocks I would suggest you wiremock. It's not so fancy, but way more feature reach. You could run it as a service and update mock mappings at runtime by sending HTTP requests.
Please check solution for your question using wiremock. Related documentation.
Related
I am creating a JSON API that implements the JSON:API specification. I have a question about it however, and this question applies more generally to RESTful design in general: What is the recommended way to handle the "creation" of a resource, where one of the attributes is "calculated" by the server?
In my example, I have a POST /auth/tokens endpoint that accepts a user's credentials and returns a JWT. I've used a POST endpoint, because it seems to me that we are creating a token resource, even if that token is not saved to a database. However, according to JSON:API, what would the proper request/response look like? This?:
POST /auth/tokens
{
"data": {
"type": "tokens",
"attributes": {
"email": "...",
"password": "..."
}
}
}
However, does it even make sense to create a token with an email and password? It seems that it would be creating a token for an email/password. Is there a difference?
More importantly, what would the response look like? It seems like it would look something like:
{
"data": {
"type": "tokens",
"attributes": {
"token": "..."
}
}
}
But the specification states:
Every resource object MUST contain an id member and a type member. The values of the id and type members MUST be strings.
Since the tokens aren't saved to the database, I don't really have an ID for them. What should I do?
JSON:API specification doesn't say anything about such case but if you look on some live implementations like https://docs.unit.co/customer-api-tokens#customers-create-customer-bearer-token they use similar approach as you described. It seems to be just ok in this case to omit ID for a resource which is short lived.
I came across HATEOAS on my researches and was thinking : doesn't HATEOAS multiplicate HTTP requests ?
Let's take the basic customer and order example.
Let's say you want to retrieve an order, the endpoint would be /orders/2
with the following JSON response :
{
"id": 2,
"total": 50.00,
"links": [{
"rel": "customer",
"href": "http://api.domain.com/customer/1
}]
}
Now what if I also need the customer ? Do I have to make another request to /customer/1 ? Doesn't this overload the HTTP traffic ?
Couldn't I get the couple customer + order with a single endpoint like /customers/1/orders/2 ?
Or just send the customer in the /orders/2 JSON response ?
{
"id": 2,
"total": 50.00,
"customer": {
"id": 1,
"name": "Dylan Gauthier"
}
}
What's the benefit(s) of one solution or another ? When do I need one or the other ?
Thanks ! :-)
If the server only supplies the customer and order separately, then you have to make two requests regardless of whether they are following REST or not.
Nothing about REST or its HATEOAS constraint prevents the server from providing both customer and order in the same resource, exactly as you have suggested:
GET /orders/2
{
"id": 2,
"total": 50.00,
"customer": {
"name": "Dylan Gauthier"
}
}
But the customer in that response has no connection to the identifier /customers/1 — the server could combine the two ideas:
{
"id": 2,
"total": 50.00,
"links": [{
"rel": "customer",
"href": "http://api.domain.com/customer/1
}],
"resources": {
"http://api.domain.com/customer/1": {
"name": "Dylan Gauthier"
}
}
}
or better yet, group the links by their relation to the requested resource:
{
"id": 2,
"total": 50.00,
"links": {
"customer": [{
"href": "http://api.domain.com/customer/1"
}]
},
"resources": {
"http://api.domain.com/customer/1": {
"name": "Dylan Gauthier"
}
}
}
Whilst this would make it a bit more work for the client to print the name of the customer (nothing at all taxing, mind), it allows the client to fetch more information about the customer if they want to!
Just to add to Nicholas' answer:
Embedding related resources
Pros: saves you a trip to the server
Cons: While it saves you a trip the first time and may be a few lines of code, you are giving up on caching: if something changes in a related resource (that you embedded) client cache is no more valid, so the client has to make the request again. Of course, assuming you leverage HTTP caching. Which you should...
If you want to go this route, you are better off using something like GraphQL... but wait!
Going "pure" HATEOS
Pros: resources have independent life-cycles; easier to make each (type of) resource evolve without impacting the others. By fully leveraging the cache, overtime, the overall performance is far better.
Cons: more requests (at first access), this might be a little slower on first access; some more code to manage the HATEOS thing...
I personally tend to use the second approach whenever possible.
The classic web analogy:
If it can help, a classic website is just another api that serves html related resources, the client app being the browser itself. If you have ever done some html/css/js, you might want to approach it the same way:
For the given particular website, given its navigation architecture...etc would you rather inline all/part of the css/js (the related resources) in the html pages (the main resource) or not.
Currently, I'm working on new product and making REST API for both - public and internal needs. I started with {json:api} specification and I was pretty happy with it until I faced some questions I cannot find answers to.
According to JSON API specification, every resource MUST contain id.
http://jsonapi.org/format/
Every resource object MUST contain an id member and a type member. The values of the id and type members MUST be strings.
And that's fine in many cases but not all.
Most of our endpoints are about "resources"
If I ask for a "things" collection (http://example.com/things)
{
"data": [{
"type": "things",
"id": "1",
"attributes": {
"title": "first"
},
"links": {
"self": "http://example.com/things/1"
}
}, {
"type": "things",
"id": "1",
"attributes": {
"title": "second"
},
"links": {
"self": "http://example.com/things/2"
}
}]
}
If I ask for a single "things" resource (http://example.com/things/1)
{
"data": {
"type": "things",
"id": "1",
"attributes": {
"title": "first"
},
"links": {
"self": "http://example.com/things/1"
}
}
}
But what to do with endpoints which are not about resources and does not have ID?
For example, in our application, there is an endpoint http://example.com/stats which should return stats of current logged in user. Like
{
"active_things": 23,
"last_login": "2017"
}
There is no id for this "resource" (it's not actually a resource, is it?). Backend just collects some "stats" for logged in user and returns an object of stats. There many endpoints like this in this application, for example, we have Notification center page where the user can change email addresses for different notifications.
So frontend app (single-page-app) first has to get current values and it sends the request to GET http://example.com/notification-settings.
{
"notifications_about_new_thing": "arunas#example.com",
"notification_about_other_thing": "arunas#example.com"
}
And there are many more endpoints like this. The problem is - how to return these responses in JSONAPI format? There is no ID in these endpoints.
And the biggest question is - why nobody else is facing this issue (at least I cannot find any discussion about this)? :D All APIs I ever made has some endpoints which don't have "id".
I have two ideas, first is to fake id, like "id": "doesnt_matter", the second - do not use json-api for these endpoints. But I don't like both of them.
Think RESTfully and everything can (must) be a resource. There is no "logged in" user as there are no sessions in RESTful APIs as they are stateless. There's no session state maintained between REST API invocations, so you have to be explicit about who the user is.
In this case, the resource is the user who has some stats attributes (in the simple case) or perhaps a relationship to a separate stats relationship (more complicated, not shown):
GET /users/1234
{
"data": {
"type": "users",
"id": "1234",
"attributes": {
"name": "etc.",
"active_things": 23,
"last_login": "2017"
}
}
}
I'm no JSON API expert- but it's worth noting that while JSON API is a concrete specification, it is not the same thing as JSON, nor as a REST API. If you don't like its semantics, I agree with commenters who argue, "Don't use it." If you are going to use JSON API, do so in a compliant way, where every response is a resource; every resource has an ID and a type; and additional information is supplied as attributes of the resource.
Toward your question, I'm thinking about something similar where my application returns computation results. Now on the one hand, these are not strictly "resources" and so I've been toying with the idea of returning the raw result as an array (which I believe would be valid JSON, with a caveat), e.g:
[ 47 ]
On the other hand, there is the idea that the results are the results of a computation that the client specified RESTfully, in which case one of the following two cases is likely true:
The same request submitted later is likely to have the same result. This suggests that in fact the result really is a resource.
The same request submitted later is likely to have a different result. This suggests that the client may want to track how results change for various queries, and so at least the query parameters should be part of the response.
In both cases, the response really is a 'result' object, and even though it doesn't have an ID per se, it does have an identity. If nothing else fits, the ID could be the query that generated the response.
This seems RESTful to me. User #n2ygk suggests that this is not correct as regards the JSON API spec, that an ID should simply be a unique ID and not have another semantic interpretation.
I'd love to hear other perspectives.
Is it ok to return extra information in http PUT response such as createdDateTime or lastUpdateTime
E.g. PUT request comes as follows
properties
{
"name": "somename"
"addr": "someaddr"
}
In response along with sending the resource representation I am sending extra information
HTTP OK or CREATED
properties
{
"name": "somename"
"addr": "someaddr"
"lastUpdateTime": "somedatetime"
}
Is this a bad practice ?
I see no problem with that. If the client needs that information, then the resource will have to include it as a property. The client can POST/PUT without it (NULL), or the server will ignore it anyway (since this is only set server-side), but it will have to reflect it afterwards.
You can always secure your API if you're going to expose it publicly (OAuth, API keys etc).
We have an existing web application which has an API not based on REST. We'd like to put a REST API in front of it, using Strongloop, however, getting lost in the documentation and not sure if this can be achieved.
Example:
Want to configure an endpoint in Strongloop which looks like;
localhost:3000/api/DataObject/Orders?StartDate=01/01/2016&EndDate=31/01/2016
A GET on this end point should service the request from our existing web application, where the URL would like;
localhost:4000/wh?Page=ObjectBuilder&Name=Orders&StartDate=01/01/2016&EndDate=31/01/2016
i.e. take Orders from the API request and insert into the remote URL, along with the remaining parameters.
I could code this using express.js, but was wondering if this is possible using configuration in Strongloop?
Thanks!
I think you might be able to use the built-in REST connector even though your legacy API is not REST per se (although you don't get all the benefits of the built-in mapping to find, create, destroy, etc). The connector simply translates URLs into model methods. That said, I think you do need to have the old API spit out JSON... does it do that? If not, then you basically just have to write a full translator.
This is not working code, but might help you get part of the way there.
In your server/datasources.json file:
"old-service": {
"name": "old-service",
"connector": "rest",
"operations": [{
"template": {
"method": "GET",
"url": "http://localhost:4000/wh",
"headers": {
// whatever you might need to send...
},
"query": {
"Page": "ObjectBuilder",
"Name": "{name}",
"StartDate": "{start}",
"EndDate": "{end}"
},
"responsePath": "$.results.theObject" // be sure to custom ize this
},
"functions": {
"buildObject": ["name", "start", "end"]
}
}]
}
In your server/model-config.json be sure too map your DataObject model to this datasource:
{
// ...
"DataObject": {
"public": true,
"dataSource": "old-service"
},
}
And in your model itself (common/models/DataObject.js) you can now call the buildObject() method:
DataObject.buildObject('Order', '01/01/2016', '31/01/2016', function(err, result, response) {
if (err) { ... }
// otherwise look at the result or response...
});
Now that you can call this method, you could put it into a remoteMethod or even override the default find method for this model.
Good luck, but in many of these cases you simply have to write the "conversion" code yourself. Might be easier to rewrite the API from scratch. ;)