I have an API that either returns the following response on success:
{
"result": "success",
"filename": "my-filename.txt"
}
or something like below upon failure:
{
"result": "error",
"message": "You must specify the xxx parameter."
}
The filename property is only specified if the request was a success, but a message is provided if there was an error. This means the message and the filename properties are "optional" but the result property is required.
I tried defining this response object in a definition as shown below:
"my_response_object": {
"type": "object",
"properties": {
"result": {
"type": "string",
"description": "value of 'success' or 'error', indicated whether was successful",
"required": true
},
"message": {
"type": "string",
"description": "an error message if there was an issue",
"required": false
},
"filename": {
"type": "string",
"description": "the filename to return if the request was successful",
"required": false
}
}
}
But it appears that swagger does not like the "required" attribute and will show the following error message:
When I look at an example from swagger, they have the following layout where there are two different response definitions instead of one.
"responses": {
"200": {
"description": "Profile information for a user",
"schema": {
"$ref": "#/definitions/Profile"
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
I could do this, but it appears that one cannot have multiple responses for the 200 error code. Does this mean that one has to use "default" for all error responses, and one can only have a single structure for all erroneous responses, or is there a way to specify that certain attributes are optional in definitions?
You're getting the error in the model, because that's not the way to define required properties.
The correct form would be:
"my_response_object": {
"type": "object",
"required": [ "result" ],
"properties": {
"result": {
"type": "string",
"description": "value of 'success' or 'error', indicated whether was successful"
},
"message": {
"type": "string",
"description": "an error message if there was an issue"
},
"filename": {
"type": "string",
"description": "the filename to return if the request was successful"
}
}
}
Anything not in the required property is assumed to be optional. Keep in mind that this implies that it's possible to get both message and filename.
You can then use this model for your 200 response.
However - when it comes to REST API design, this breaks one of the more common standards. The status codes, taken from the HTTP protocol are meant to convey the outcome of the operation. 2XX are used for successful responses, 4XX are for errors due to bad user input, 5XX are for problems on the server side (3XX are for redirects). What you're doing here, is tell the client - the operation was successful, but in fact, it can be an error.
If you can still modify the API, I'd highly recommend making that distinction using the status codes, even using the fine tuned distinctions such as 200 for a successful GET operation, 201 for successful POST (or creation) operation and so on, based on the definitions here - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
Related
I know this may sound odd, but we have an API where we return back out generated HTML content depending on payloads passed in.
I'm just wondering what is the formal definition of a Open API call for such a api, specifically the responses section below.
Is it as simple as this?
"paths": {
"/instance/UI/{instanceCode}/{identifier}": {
"get": {
"summary": "Returns the UI which allow the instances answer to be managed by a user",
"operationId": "instanceUIGet",
"parameters": [
{
"name": "instanceCode",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "identifier",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Returns the HTML page for a UI to manage the instance.",
"content": {
"text/html": {
}
}
}
}
}
},
It would be either
"responses": {
"200": {
"description": "Returns the HTML page for a UI to manage the instance.",
"content": {
"text/html": {} // no schema needed
}
}
}
(as in your example)
or
"responses": {
"200": {
"description": "Returns the HTML page for a UI to manage the instance.",
"content": {
"text/html": {
"schema": {
"type": "string"
}
}
}
}
}
Some comments by the OpenAPI Specification maintainers suggest that the text/* media types don't need a schema because their semantics is fully defined by the media type itself. However, if you search for text/ in the specification itself, you'll notice the use of schema in some of the examples with the text/* media types. Looks like there's no official stance on that (or maybe the examples in the spec are not quite correct).
I get the following error when creating API in Postman: "Invalid data type. Must be either, array, boolean, integer, number, object or string"
The error is fixed when converting the line "type": "file" to "type": "object", but I am not sure if there is a proper way for this situation. Because with this update, the request may not be passed when sending request in Postman.
"parameters": [
{
"in": "body",
"name": "file",
"description": "file",
"required": false,
"schema": {
"type": "array",
"items": {
"type": "file"
}
}
},
...
]
So, how can I fix the problem in Postman?
The problem is not with Postman, but with the API definition. "type": "file" is not a valid type value for use in schemas and body parameters, this type can only be used in in: formData parameters.
On the other hand, I do not add file while trying to test my app via Postman. For this reason, I just want to suppress the errors
In this case you could change "type": "file" to "type": "string" to suppress import errors. Or remove the entire problematic operation from the API definition.
How to properly define file uploads in OpenAPI
The API definition is trying to describe uploading of a file array - but this is not supported in OpenAPI 2.0 (swagger: '2.0'). OAS2 only supports upload of individual named files via multipart/form-data, in which case the API definition would look like this:
{
"swagger: "2.0",
...
"paths": {
"/something": {
"post": {
"consumes": [
"multipart/form-data"
],
"parameters": [
{
"in": "formData",
"name": "file1",
"type": "file" // A single file sent via form field "file1"
},
{
"in": "formData",
"name": "file2",
"type": "file" // Another file sent via form field "file2"
}
]
...
}
Uploading an array of files is supported in OpenAPI 3 though:
{
"openapi": "3.0.0",
...
"paths": {
"/something": {
"post": {
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"file": {
"type": "array",
"items": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
...
}
}
}
}
The new way to upload images as hosted content through the Send Message endpoint is great! However, is there a way to upload text/plain as hosted content in order to post a Code Snippet Card in a message?
I have tried uploading text but the response gives me an error that says that the only content types allowed are 'image/jpg,image/jpeg,image/png'.
Example request:
{
"body": {
"contentType": "html",
"content": "<attachment id=\"4d92eb51ab9c48ebb5b364794a2fa569\"></attachment>"
},
"attachments": [
{
"id": "4d92eb51ab9c48ebb5b364794a2fa569",
"contentType": "application/vnd.microsoft.card.codesnippet",
"contentUrl": null,
"content": "{\"name\":\"\",\"language\":\"CSharp\",\"lines\":1,\"wrap\":false,\"codeSnippetUrl\":\"../hostedContents/1/$value\"}",
"name": null,
"thumbnailUrl": null
}
],
"hostedContents":[
{
"#microsoft.graph.temporaryId": "1",
"contentBytes": "VGVzdA==",
"contentType": "text/plain"
}
]
}
Response:
{
"error": {
"code": "BadRequest",
"message": "Unsupported content type in hostedContent with Id '1'. Allowed values are 'image/jpg,image/jpeg,image/png'",
"innerError": {
"date": "2020-10-07T12:17:15",
"request-id": "ed24f5df-3e1f-4871-b430-e4c1c9f30348",
"client-request-id": "ed24f5df-3e1f-4871-b430-e4c1c9f30348"
}
}
}
I received an answer in the Documentation GitHub: https://github.com/microsoftgraph/microsoft-graph-docs/issues/10210#issuecomment-705050649
Code snippets are not supported at the moment. They are on list of things to support, but there is no timeline to share yet.
swagger 2.0.
.netcore 2.1
swashbuckle as in the image.
I have this attribute on an api endpoint:
[SwaggerResponse(statusCode: 200, type: typeof(List<Cat>), description: "successful operation")]
When I run the API and navigate to https://localhost:44394/swagger/v1/swagger.json the json is there but the SwaggerResponse seems to be being ignored.
This is an example of what I receive:
"/api/data/cats": {
"get": {
"tags": [
"CatApi"
],
"operationId": "GetCatsById",
"consumes": [],
"produces": [],
"parameters": [
{
"name": "catIds",
"in": "query",
"required": true,
"type": "array",
"items": {
"type": "integer",
"format": "int32"
},
"collectionFormat": "multi",
"uniqueItems": false
}
],
"responses": {
"200": {
"description": "Success"
}
}
}
},
You can see that the response just show a 200 and I'm not exactly sure where it's getting that description from - as you can see in the attribute it should be successful operation and my XML comment is <response code="200">successful operation</response>.
I'm very confused. How can I get Swashbuckle it use the SwaggerResponse attribute when it generates the json?
More info:
If I use [ProducesResponseType(statusCode: 200, type: typeof(List<Cat>))] then I get what I want:
"/api/data/cats": {
"get": {
"tags": [
"CatsApi"
],
"operationId": "GetCatsById",
"consumes": [],
"produces": [
"text/plain",
"application/json",
"text/json"
],
"parameters": [
{
"name": "catIds",
"in": "query",
"required": true,
"type": "array",
"items": {
"type": "integer",
"format": "int32"
},
"collectionFormat": "multi",
"uniqueItems": false
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"uniqueItems": false,
"type": "array",
"items": {
"$ref": "#/definitions/Cat"
}
}
}
}
}
},
You can see the additional data in the produces field and the schema in the responses field.
I could change to use ProducesResponseType everywhere but it isn't a standard field as far as Swagger is concerned - if I ever regenerate the code from the swagger file then I'll have to always make these changes so I'd like to get it working with SwaggerResponse.
Step 1: Double check if your are missing the Swagger Decorator Attributes, follow this below and replace the attributes with your specific Types / MyModel
Since you didn't put up your actual code, to see how it works, use the default samples for e.g. you can Install my Swashbuckle.Examples NuGet package. Decorate your methods with the new SwaggerResponseExample attributes below and you will see it work just fine!
// These attributes will help with your nested objects
[SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable<Country>))]
[SwaggerResponseExample(HttpStatusCode.OK, typeof(CountryExamples))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(IEnumerable<ErrorResource>))]
public async Task<HttpResponseMessage> Get(string lang)
Ste 2: Also ensure you have it configured like so
configuration
.EnableSwagger(c =>
{
c.OperationFilter<ExamplesOperationFilter>();
})
.EnableSwaggerUi();
Also make sure you have the right using for the annotations. I searched and searched because the SwaggerResponse were missing and i couldn't get my head behind it.
I somehow managed to use Nswag Annotations, but needed Swashbucke using:
using Swashbuckle.AspNetCore.Annotations;
I think it came because as i didn't have a nuget for SwaggerResponse installed and the first suggestion for a nuget package that has this type was nswag.
I am using Swagger Editor to work on a JSON Swagger 2.0 API definition. I have reduced my definition to a minimum example of the problem I am experiencing. The problem occurs when I use a reference object to define a path parameter that is shared between multiple endpoints.
Example endpoints:
/my-api/{id}/some-thing
/my-api/{id}/some-other-thing
Since these id parameters are defined the same way, I abstracted them to the parameters section of the JSON file, and included them with "$ref": "#/parameters/testObjectId".
The Swagger reduced definition shows this:
{
"swagger": "2.0",
"info": {
"title": "Test Service",
"description": "REST API for TestObjects",
"version": "1.0.0"
},
"host": "api.not-a-real-url.com",
"schemes": [
"https"
],
"basePath": "/api/test-objects",
"produces": [
"application/hal+json"
],
"consumes": [
"application/json"
],
"paths": {
"/{id}": {
"get": {
"operationId": "getTestObject",
"summary": "Get a TestObject resource referenced by slug string ID",
"security": [],
"parameters": [
{
"$ref": "#/parameters/testObjectId"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {}
}
},
"default": {
"description": "Error",
"schema": {
"type": "object",
"properties": {}
}
}
}
}
}
},
"parameters": {
"testObjectId": {
"name": "id",
"in": "path",
"required": true,
"type": "string",
"format": "slug",
"description": "Immutable, unique identifier of a TestObject"
}
},
"definitions": {
}
}
But when this is rendered in Swagger, I get the following error:
Errors
Semantic error at paths./{id}
Declared path parameter "id" needs to be defined as a path parameter at either the path or operation level
The problem is that id is actually defined, only it appears that the check which throws this error is occurring before the $ref is included. The Swagger output looks correct.
Further, I have used this approach for about 6 months (as long as I have used Swagger) and I am just now running into the problem for the first time. Is there something I should be doing differently to prevent this error? Am I misusing Swagger by doing it this way?
Your spec is valid. It was a bug introduced in Swagger Editor v.3.2.2, it was fixed in v.3.2.3 (released on January 6, 2018).