Does the HTTP spec allow returning different Content-Types for similar/identical requests? - http

Is it okay according to the HTTP spec to have a request that (for example) does the following:
GET https://www.example.com/api/images/1 -> 200 OK, Content Type "image/png"
GET https://www.example.com/api/images/2 -> 404 NOT FOUND, Content Type "application/json"
We're having trouble with this in Swagger since you have to specify the Content-Type of the response before making the request, so I figured I'd ask whether what we want to do is even acceptable according to the HTTP spec before we continue digging into how it can be solved with Swagger

Yes, it's perfectly fine for an URL to return different HTTP status codes depending on the result of the request. It's also OK to return different media types, e.g. based on the Accept header (aka content negotiation) or other conditions.
In OpenAPI/Swagger 2.0, your example can be described like this:
paths:
/something:
get:
produces:
- image/png
- application/json
responses:
'200':
description: A PNG file
schema:
type: file
'404':
description: Not Found
schema:
type: object
# properties:
# ...
OpenAPI 3.0 improves response definitions and lets you specify the media types for specific status codes:
responses:
'200':
description: A PNG image
content:
image/png:
schema:
type: string
format: binary
'404':
description: Not found
content:
application/json:
schema:
type: object
# properties:
# ...

Related

Validating query parameters in RAML

I need to create an API that has four possible HTTP query parameters. Either parameter one or parameter two is required. The others are optional. From the official RAML version 1.0 specification on Github, I found an almost exact scenario in the RAML queryString example.
I loaded it into Mulesoft Design Center to test it out. The RAML produces no errors in Design Center, and everything looks okay. According to the first example in the RAML, the following URL should produce a success (200 OK):
GET https://(mocking URL)/locations?start=2&lat=12&long=13
When I send it via Postman, it reaches the mocking service, but I get the following error:
{
"code": "REQUEST_VALIDATION_ERROR",
"message": "Error validating query string: expected type: JSONObject, found: Null"
}
I'm not sure if this is a Design Center limitation or if there's something off in my URL. Does anyone know what I'm doing wrong?
Here's the RAML sample from the official spec:
#%RAML 1.0
title: Illustrate query parameter variations
types:
lat-long: # lat & long required; mutually exclusive with location
properties:
lat: number
long: number
loc: # location required; mutually exclusive with lat & long
properties:
location:
paging: # each is optional, not exclusive with anything
properties:
start?: number
page-size?: number
/locations:
get:
queryString:
type: [paging, lat-long | loc ]
examples:
first:
value:
start: 2
lat: 12
long: 13
second:
value:
start: 2
page-size: 20
location: 1,2
third: # not valid
value:
lat: 12
location: 2
strict: false # because it's not valid
The RAML specification explicitly does not define validation for object types:
RAML does not define validation when a query parameter declaration
specifies any of the following types for the value of the query
parameter: an object type, a union of non-scalar types, or an array
type if the underlying type of the array is an object type or union of
non-scalar types. Processors MAY default to treating the format of the
query parameter value as JSON in applying the type to instances of
that query parameter, or they MAY allow other treatments based on
annotations.
Even if the Mocking Service implements the validation eventually, it might be better to use simple types for query parameters, like strings and numbers. It makes sense because usually query parameters are just used that way.
This looks like a bug in the MuleSoft Anypoit mocking tool.
The RAML spec is correct.
You may wish to raise a defect with MuleSoft support.

Does a HTTP 200 response imply that there must be a response body?

I'm attempting to decipher a Swagger specification document and use it to generate code. It contains the following endpoint definition:
/feature:
get:
summary: Returns all features
operationId: getAllFeatures
tags:
- feature
responses:
'200':
description: 'Features retrieved successfully'
'400':
$ref: '#/responses/BadRequest'
Based on the endpoint summary and the 200 response description, it's pretty clear to me that this endpoint was intended to return a response body that contains an array or collection of "feature", even though the response is not defined in the spec.
Let's suppose that I'm right, and the spec author just forgot to add it. What then should I make of this endpoint:
/features:
put:
summary: Updates an existing feature
operationId: updateFeature
parameters:
- name: body
in: body
description: 'Feature to be updated'
required: true
schema:
$ref: '#/definitions/Feature'
tags:
- feature
responses:
'200':
description: 'Feature updated'
This one is ambiguous to me. I've seen some implementations of update endpoints that return the updated object. Others I've seen return nothing in the body.
My questions are this:
Does a HTTP 200 response imply there must be a response body? I can't tell whether the HTTP specification (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) requires this or if it just states that it could be there.
Would it be less confusing in this scenario for the spec author to have used HTTP 204 to expressly indicate that there is no response body? (I can answer this - yes - but are there reasons to use HTTP 200 instead of 204 in this case? Or was this just that the author didn't know about success response codes other than HTTP 200?)
If the answer to #1 is no, and the answer to #2 is yes: why was HTTP defined in this manner?
200 OK can return an empty body with Content-Length: 0.
204 No Content has a more specific purpose than many people realize. Quote from the current spec:
The 204 response allows a server to indicate that the action has been
successfully applied to the target resource, while implying that the
user agent does not need to traverse away from its current "document
view" (if any). The server assumes that the user agent will provide
some indication of the success to its user, in accord with its own
interface, and apply any new or updated metadata in the response to
its active representation.
Basically this is saying, if for example a HTML form is submitted, and the server responds with 204, it can signal a browser to not refresh the current page to the new location, or redirect anywhere else. It can for example facilitate a 'save' action without forcing the browser to redirect/switch to a new url. Also see 205 for a similar action, but with different behavior.
Browsers (as far as I know) don't actually implement this behavior. But a REST/Hypermedia/HATEOAS client could.
The current spec also states the more common use, which is 200 without a response body, but if you go all the way back to the HTTP/1.0 spec, this is the entire section. Notice that it only mentions this behavior, and says nothing about 204 being just a substitute for 200 minus body:
The server has fulfilled the request but there is no new information to send back. If the client is a user agent, it should not change its document view from that which caused the request to be generated. This response is primarily intended to allow input for scripts or other actions to take place without causing a change to the user agent's active document view. The response may include new metainformation in the form of entity headers, which should apply to the document currently in the user agent's active view.
So the key here that this signals about how a hypermedia client should behave. removing that, I would agree there's not a lot of reasons to use 204. It's become a convention that I don't think has a strong purpose.
Sidenote: don't refer to RFC2616 unless you're into internet archeology.
See #2

Configure Firebase Function to accept HAL+JSON as request body

When using HTTP-triggered Functions in Firebase, I'm unable to access a HAL+JSON payload from the HTTP request.
The request looks like:
POST /endpoint
Content-Type: application/hal+json
{ /* some payload */ }
In my function I'm accessing the payload using request.body, like this:
...
var myPayload = request.body;
...
The value of myPayload is:
{}
Instead, when the HTTP request contains Content-Type: application/json, the value of myPayload is the correct one:
{ /* some payload */ }
I believe it's related to the following: express.json()
Is there a way to configure express in Firebase to include application/hal+json? For example:
express.json({
type: [ 'application/json', 'application/hal+json' ]
});
Or to access the raw body myself?
Note: I don't want to create an express app within the function.
Please refer to the documentation for understanding how Cloud Functions automatically processes incoming requests.
Cloud Functions parses request body content types of application/json
and application/x-www-form-urlencoded according to the rules described
above. Plain text content types (text/plain) are passed through as
strings using UTF-8 as a default encoding (or a custom encoding
provided in the content-type header).
For other content types, the rawBody property contains the unparsed
bytes of the request body as a Buffer object.
Your "other content type" here probably means that your raw request body will be available from the Request object in the rawBody property.

RAML retrieve baseUri value

I would like to avoid hardcoding everytime base uri in specification and use defined one in the root is there any way to achieve it, for example:
#%RAML 1.0
title: Some Service
version: v1
baseUri: https://example.com
/test:
post:
responses:
201:
headers:
Location:
type: string
example: https://example.com/v1/test/291 # here i would like to retrieve https://example.com/v1/ from root where I've already defined it.
Short answer: Yes.
You can specify the baseUri at the root of the document. It then applies to all resources.
See:
https://github.com/raml-org/raml-spec/blob/master/versions/raml-10/raml-10.md/#the-root-of-the-document

How to send HTTP POST requests using only Rebol3

What is the simplest way of sending HTTP POST requests and getting response (in XML format for example) using only Rebol3?
Is there an equivalent of using read/custom in Rebol2, as it is done in this question?
How to send an HTTP post with a custom header using REBOL
And where should I be donwnloading my Rebol3 binaries from? I've not found a lot of documentation on that...
The documentation at on Ports: Synchronous and Asynchronous Operations shows how to use both GET and POST. To summarize:
The default behavior is to assume the post data should be considered as application/x-www-form-urlencoded. (If you want to encode a block of ordinary Rebol data into that format, see %altwebform.r)
result: write http://www.rebol.com/cgi-bin/updata.r data
If you need a custom header, then instead of passing a string you need to pass a block. Start it with the WORD! post followed by a block of Rebol-formatted key/value pairs, and then your data:
result: write http://www.rebol.com/cgi-bin/updata.r compose [
post [
Content-type: "text/x-rebol"
;-- other fields here
]
(data)
]
The result will be in binary! and can be converted to string! to parse out any XML or whatever.
where should I be downloading my Rebol3 binaries from?
You should download binaries from http://www.rebolsource.net/

Resources