I'm declaring a REST service API stub in RAML. My web application provides equipment, which can be listed, obtained by id or by code. When I want the whole list, I don't specify any URI parameter, however, to get a concrete equipment, I do. That's its current state:
/equipment:
get:
body:
application/json:
application/xml:
description:
List all the equipment
/id/{equipmentId}:
get:
body:
application/json:
application/xml:
description:
Get an equipment by id
/code/{code}:
get:
body:
application/json:
application/xml:
description:
Get an equipment by code
Here, in description fields I write what the current call performs. However, I would like to add a description for the parameter passed in the URI itself (id or code). Is there a way to achieve it?
You are missing uriParameters sections to describe the equipmentId and code parameters. In such section, you can specify the usual: type, description...
See section Template URIs and URI Parameters in the spec: https://github.com/raml-org/raml-spec/blob/master/versions/raml-08/raml-08.md#template-uris-and-uri-parameters
Related
I have this api documentation written in OpenAPI 3.0.3
openapi: 3.0.3
info:
version: '1.0'
title: 'MyTitle'
description: Specification for Bear Store
servers:
- url: https://development.example.com/v1
description: Development Server
paths:
'/v1/bears':
get:
description: Requests a lists all the bears
summary: List of bears request
responses:
'200':
description: List of Bears
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
I have a Bear object that has id, and name properties. I want to define that id field is a unique field. How can I define this in OpenAPI 3?
OpenAPI lets you define a field's type and its expected format. But it's not possible for it to ensure its uniqueness.
Uniqueness is a business concern, which might involve non-trivial checks. Therefore, it's outside the scope of OpenAPI/Swagger to formalize such concepts.
However, you can add a description to explain the requirement that the field value must be unique, then implement necessary checks in the API to ensure that the value supplied by the client is actually unique.
I am trying to document the response for an endpoint that accepts multiple mime type requests and returns a different response based on the type. One response type, pdf, returns its own schema separate from the others. The rest all return the same schema and same example. This syntax works. Almost. Except in the UI example, the JSON response is also showing the string "$ref: example-two.json" along with the appropriate response example. Like:
{
"key": "value",
"key2": "value2",
"$$ref: example-two.json"
}
when it should just be:
{
"key": "value",
"key2": "value2"
}
I've been scouring the docs and stack and google and I don't see any examples of making something like this work. Or rather, I'm not seeing why this one isn't working, but I haven't seen any examples that include $refs for each example.
responses:
200:
content:
application/pdf:
schema:
$ref: ../app.yaml#/components/schemas/ModelOne
application/json:
schema:
$ref: ../app.yaml#/components/schemas/ModelTwo
examples:
Example:
value:
$ref: example-two.json
text/html:
schema:
$ref: ../app.yaml#/components/schemas/ModelTwo
examples:
Example:
value:
$ref: example-two.json
For context - I cannot change the endpoint behavior and I do need to show an example for each mime type even if they are the same. Because the one is different. Thank you in advance!
There are two ways to $ref an example in OpenAPI 3.0:
1) Define the example in the components/examples section. In this case the $ref is used inside the examples.<name> key (not inside value).
examples:
Example:
$ref: '#/components/examples/MyExample'
...
components:
examples:
MyExample:
summary: Optional short description of this example
value:
key: value
key2: value2
2) If the example-two.json file contains just the example value (in this case - sample JSON), you can use externalValue to link to that file:
examples:
Example:
externalValue: example-two.json
Notes:
Relative URLs in externalValue are resolved against the API server URL (servers[*].url) and not the location of the OpenAPI definition file. You may need to use an absolute URL.
Examples with externalValue are currently (as of December 2019) not displayed in Swagger UI - see issue #5433.
Is there a way to exclude one or more properties from a request body when you use a type and writing your API using RAML 1.0
I'll explain. I have a type: 'Order' with a set of properties. I have a resource /orders and a method post which allows users to create a new order.
The request body is an order struct json and a response is an order struct as well.
But I don't want users to specify order id while they are submitting their request. But that id (and a couple more 'response only' fields) will be returned at the response. I don't want to create an extra type, like OrderRequest and then inherit it with an Order type, maybe there is a more elegant solution?
So I want to have a way to exclude some properties from a request body and keep others in order to use their description and examples.
Thanks and sorry for my English :)
Use two types. The second will be child of the first. Example:
#%RAML 1.0
title: GitHub API
version: v3
baseUri: https://api.github.com
mediaType: application/json
types:
OrderCreating:
type: object
properties:
products:
description: List of product ids with amount.
required: true
type: object
properties:
[]:
type: number
coupon?: string
Order:
type: OrderCreating
properties:
id: integer
price: number
...
/orders:
post:
body:
application/json:
type: OrderCreating
/{orderId}:
get:
responses:
200:
body:
application/json:
type: Order
Also you can include Library with declaration of your types.
As you don't want to create an extra type with inheritance you can still mark the field as optional and document that it is present in the response.
Is it generally a bad idea to optionally extend a resource endpoint with additional data pertaining to the requested resource?
Example
GET /post/:id/ - retrieve a single post
Example Response
{
id : 1
title : 'Hello world',
body : 'Testing'
}
GET /post/:id/?includeMeta=1 - retrive a single post with additional meta data
Example Response
{
id : 1
title : 'Hello world',
body : 'Testing',
meta : {
url : 'http://google.com',
customMetaKey : 'some value'
}
}
It depends on whether these extra values belong to the main resource or not. In your case, if they belong to the resource named "Post" then it's perfectly acceptable. In fact, you can use an approach named "Partial Responses", that was first used by Google. In this case, you have to add a special QueryString attribute named "fields" like the example below.
GET /post/:id/?fields=metadata,field2,field3,association(field1,field2)
In this queryString you can add all fields you want returned in the response, including the associations. Take a look at the article below to learn more about Partial Responses:
http://googlecode.blogspot.com.br/2010/03/making-apis-faster-introducing-partial.html
In the other hand, if these extra values don't belong to the main resource then I think it doesn't make any sense. If a client wants those values then it has to ask it to the resource that owns it.
Suppose my model is:
User:
id
nickname
I have a collection /users/
I want the Users to be retrieved by /users/{id} and not /users/${nickname}, because in some more complex cases, there could be no "logical unique constraint".
So the basic JSON payload I could use is for exemple:
{
id: 123,
nickname: 'someUserName'
}
Nothing fancy here.
POST on /users/
As far as I know, an user as an identifier. It is part of the resource representation, so it should be in the payload (?).
Put what if I want to generate the ID myself on the backend, using a DB sequence for exemple?
Then my payload becomes:
{
nickname: 'someUserName'
}
Is this appropriate?
What is supposed to be the output of this POST? Nothing? Just a header referencing the resource location, including the ID?
GET on /users/id
When we get the resource, we load its content as JSON:
{
id: 123,
nickname: 'someUserName'
}
PUT on /users/id
As far as I know, the payload used on this method is supposed to "override" the resource content. If we wanted partial updates, we would have used PATCH.
But what if I do:
PUT /users/123
{
id: 456,
nickname: 'someUserName'
}
Does this mean that we want to update the id of a resource?
Isn't it kind of redundant to use the id in both the URI and the payload?
Actually I don't really know how to handle the id.
I don't know if I am supposed to use the same resource representation in all POST / PUT / DELETE operations.
I don't know if the id should be part of the unique(?) resource representation.
But if the id is not part of the representation, then when I list the users, using GET /users/, if the ids are not returned, then I don't know how the client can get the user ids...
Can someone help me? :)
First of all
It is not REST if you don't use HATEOAS
I hope you understand this, I'll come back to that at the very end.
POST on /users/
It perfectly ok to not use an ID in the POST payload. If an ID is present react with an error message, so developers understand they are doing wrong.
Therefore only the nickname as a payload is perfectly valid if you don't have anything else in your user resource
The output of your server should include three important things:
HEADER: A status code indicating success or failure (usually 201 Created)
HEADER: The location of the newly created resource (just Location: /path/to/resource)
BODY: A representation of the created resource. Give back a complete payload like on a GET!
GET
perfectly valid
PUT
your analysis regarding PUT/PATCH matchs the spec, the new resource should be identical to the payload meaning the user wishes to change the id if it differs. if a payload contains values which shouldn't be changed (like the ID) you have two possibilities:
Ignore the ID in the payload
Return an error
In both cases inform the user about what you did and what went wrong. I prefer to send/get a 400 Bad Request. If a privileged user could change the ID but the particular user can't an 403 Forbidden may be more appropriate.
Also make sure to document your APIs behaviour. You may allow the ID to be omitted in your API. Don't forget to treat IDs given in a POST payload in a consistent way!
Overall questions
REST operates over Resources.
/users/ is an example for an collection of resources
/users/{id} is an example for a single resource
You should always use the exact same representation in each and every response. If for some reason it is more appropriate to give only a snippet of the information add metadata (link) pointing to the full resource representation.
The ID is always present except in the first POST request of an user.
POST implies that the future location of the resource is not known and has to be provided by the server.
This also means that GET /users/ should return the IDs for each resource.
As always in APIs return strict and be forgiving in requests. document your behaviour so users can learn.
HATEOAS
The true beauty of REST comes to daylight if you implement HATEOAS (Hypermedia As The Engine Of Application State). Part of this means that you should sugar your representations with useful tag/link combinations. This way clients never have to construct an url anymore.
An Example using HAL for your user representation would be:
{
"_links:" {
"self": { "href": "http://yourrest/users/123" }
},
"id": "123"
"nickname": "someUserName"
}
A nice wrapup of using HAL was written by Matthew Weier O'Phinney in his blog when he developed a ZF2 REST Module (first entry is completly zf free, only explaining HAL).
I'm interpreting your descriptions as saying that the id is not part of the resource, it's a unique identifier of the resource. In that case, it should not be part of the payload for any operation.
POST /users with payload {"nickname": "somebody"} would create a new resource with a URL returned in the Location header. That URL would presumably look like /users/123 but from the client's point of view there's no reason to expect that. It could look like /something/else/entirely.
GET /users/123 would (assuming that URL was returned by an earlier POST) return the payload {"nickname": "somebody"}.
PUT /users/123 would (with the same assumption as above) replace the resource with the payload you send with the PUT, say {"nickname": "somebody else"}.
If you want the client to be able to name a resource, then you'd also let PUT /users/123 create a new resource with that URL.
I know of no common RESTful way to rename a resource. I suppose a POST with the old URL as part of the query part or the body would make sense.
Now, suppose I'm wrong and you do want id to be part of the resource itself. Then every payload would include it. But from the client's point of view, there should be no assumption that "id": 123 implies that the URL would be /users/123.
Finally, all of this is from a fairly purist point of view. There is value to thinking of URLs as the only real identifier of a resource, but it's not awful to break that rule and have the client use logic to create the URLs.