What do these arguments mean in swagger_auto_schema (Django)? - django

The project uses a swagger.
There is the following code.
#swagger_auto_schema(
manual_parameters=[
Parameter('download', IN_QUERY,
'Set `Content-Disposition=attachment` to make browser to download file'
'instead of showing it.',
type='bool'),
Parameter('share_id', IN_PATH, type='uuid')
],
security=[],
responses={'400': 'Validation Error (e.g. base64 is wrong)',
'200': VideoSerializer}
)
Please explain what each argument is responsible for.
I read the documentation, but understood little ...
Particularly interested in '200': VideoSerializer

responses
The responses argument is a dictionary of possible responses that this endpoint can return.
400 and 200 are HTTP response codes, Bad Request and OK respectively.
In this case, this means that this endpoint can generate two types of responses:
Bad request which will also return (as described) a Validation Error which means that something in the request was incorrect, which means it could not be handled correctly.
OK, which means the request is correct, and everything was handled correctly. VideoSerializer means that a response will be given with accordance to the structure of the VideoSerializer, which defines a collection of fields.
The other two arguments:
manual_parameters
This a custom list of parameters that can be added to the request to customize the response.
In this case, two parameters are defined:
download : A query parameter of type bool. Query parameters are passed like this : `example.com?query_parameter=true
share_id, a path parameter of type 'uuid'. Path parameters are passed like this : example.com/path_parameter
security
A list of security schemes that the request must adhere to. Used for instance for Basic authentication.

Related

How to add custom parameter to Camel's Spring web service component

My application uses versions 2.19.0 of camel-core and camel-spring-ws. I need it to send a response message to a Client's service using Camel's SpringWebserviceComponent.
It's all pretty standard apart from the client's url, it contains a parameter at the end with no value e.g. https://client-service.com/path/index.php?protocol+web_service
I have never seen a URL like this before but the client states that the parameter on the end (after the question mark and with no value) maps to a controller in their application.
When I try to feed this into my application, I get a org.apache.camel.ResolveEndpointFailedException.
I've looked through the source code of the SpringWebserviceComponent and line 129 of org.apache.camel.impl.DefaultComponent (of which SpringWebServiceComponent extends) validates the URL parameters and throws the ResolveEndpointFailedException if any of the parameters are not valid parameters for the Spring web service component, as listed here: https://camel.apache.org/spring-web-services.html. Ofcourse, protocol+web_service is not a valid parameter for the SpringWebserviceComponent and so the exception is thrown.
This validation is only conducted if the SpringWebServiceEndpoint's isLenientProperties() method returns false, which it is hard-coded to do.
Can anyone suggest any other ways to make the SpringWebServiceComponent accept this url including its non-standard parameter?
Sorry this is not support out of the box, you can try to extend the spring-ws component and override some of the methods that setup the endpoint and whatnot, and then add your hack for this "invalid" url that your client uses.

AWS API GATEWAY configuration to return binary pdf file from lambda

I want to return a pdf from a AWS Lambda function, and I use API Gateway for calling it from a any browser.
I have a aws lambda function in c# that returns an API Gateway Response which body is a pdf in base64 encoded string.
So far the endpoint returns a file with .pdf extension but not in binary. Instead, is a text file with the base64 string.
The headers i'm returning from the c# code are:
var headersDic = new Dictionary<string, string>();
headersDic.Add("Content-type", "application/pdf");
headersDic.Add("Content-disposition", "attachment; filename=file.pdf");
I converted manually the base64 string to binary file and opened it as a pdf, and it works, I mean, the base64 string is correct so I assume the problem is being the API Gateway.
In the integration response console of the API Gateway, I got this:
But i'm not able to make it work.
I also have binary media types enabled.
Actually, you do not have to disable Lambda Proxy Integration, nor do you have to specify "*/*" as a Binary Media Type, nor do you have to have your Lambda code convert the output to Base64, nor do you have to modify LambdaEntryPoint in order to get this to work.
Although some sources indicate that the "*/*" entry is necessary, the answer lies in the comment accompanying the Binary Media Types setting:
"API Gateway will look at the Content-Type and Accept HTTP headers to
decide how to handle the body."
In other words, for some odd reason, rather than just paying attention to the returned Content-Type in applying the Binary Media Types list, the gateway also takes into account the requesting client's Accept header. Most clients default to Accept:*/*, thus the origin of the workaround, and the most common explanation as to why this list doesn't seem to work. Not only does the client's Accept header seem to be given more credence than the returned Content-Type value here, there is no semantic assessment of "*/*". It is not evaluated as a wildcard, which should match any content type. Thus, an exact match of said value, literally "*/*", winds up being needed in the Binary Media Types list.
A simple solution (one which works for me) is to:
Have the client, instead of specifying "*/*" in its Accept header, specify the actual expected MIME type. (Do not specify multiple Accept types, as only the first listed type is evaluated.)
Include the same MIME type in the Binary Media Types list. Do not specify "*/*".
Have the Lambda function return a non-Base64-encoded binary file, specifying its actual MIME type in the Content-Type header.
For instance, in C#, by returning a FileContentResult from the ControllerBase.File() method, specifying the appropriate MIME content type, as in:
return File(pdfContents, "application/pdf"); //pdfContents contains raw binary data
API Gateway will match the data type to its Binary Media Types list and regard the returned data as binary. So far, I have not needed to insert RegisterResponseContentEncodingForContentType() in LambdaEntryPoint.Init().
I don't know exactly what I did, but I deleted the 'ALL' method, and created the 'GET' method with this config and now it works.
You also need to declare the content type like the following in your LambdaEntryPoint.cs
See this documentation: https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.AspNetCoreServer/README.md
You have to tell Lambda you're going to return something besides strings.
public class LambdaEntryPoint : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{
protected override void Init(IWebHostBuilder builder)
{
builder
.UseStartup<Startup>();
****IMPORTANT PART HERE****
RegisterResponseContentEncodingForContentType("application/pdf",
ResponseContentEncoding.Base64);
}
}
Response Headers
'Content-Type': 'application/pdf'
'Content-disposition', 'attachment; filename=fileName.pdf'
Response to Client
{
statusCode: 200
headers: responseHeader,
body: pdfContent.toString(base64),
isBase64Encoded: true,
}
API Gateway Binary Media Types
Hope it will help

API design - passing same request parameter multiple times in a request

I am designing an API, and was wondering what the best practice is for handling request that may contain the same request parameter multiple times. (e.g. /resource?paramA=XYZ&paramA=ABC&paramB=DEF) Should the values be taken as a single list, or if this should not be a valid request, or the last one wins, etc? Any help would be highly appreciated. Thanks.
I think the answer depends on context heavily.
For example, if a user wants to GET:
/photo?member=John&member=Alice
it might be considered as a valid request, i.e. the user tries to get a group photo with John and Alice.
But if a user wants to GET:
/photo?type=monochrome&type=mulitcolor
it should be considered as an invalid request, because a photo can't be monochrome and multicolor at the same time.
Typically the style you describe is used to submit multiple values under the same query parameter, which I think you're describing as "a single list". I don't see why you wouldn't accept it as-is. If multiple values aren't allowed for that query parameter, your API should response with a 4xx indicating the problem.

Zero-length URL Segments

Using the latest versions of Flask and Flask-RESTful, I have some very basic routes defined as such:
def build_uri_rules(uri_map):
for cls, uri in uri_map.iteritems():
api.add_resource(cls, uri)
uris = {
SampleController: '/samples/<string:hash_or_id>',
SampleFamilyController: '/samples/<string:hash_or_id>/family',
}
build_uri_rules(uris)
This works for uris requested 'properly', but what if the /samples/ endpoint is hit without a parameter, or the sample*family endpoint is hit with an empty sample id? Currently, this results in a 404 error. This works well enough, but I believe the proper thing here would be to throw a 400 error, as they found a proper URL but their data is improperly structured. Is there a way that I can force this behavior?
As a side note:
Looking through the Werkzeug docs, I see that werkzeug.routing allows a minimum length for certain url parameters, but I also see that it's got a minimum of 1. Admittedly, I've not look for why this is the case, but would this be the right tree to bark up? or should I rather simply create a global 404 handler that checks for the length of the parameter and raise the proper error from there?
Thanks!
EDITED: For code correctness.
I would say that hitting /samples/ or /samples/family (or even /samples//family) should result in a 404 as there is nothing at that endpoint.
If, however, you want to do otherwise, the simplest way to handle it would be create a 404 handler for just /samples/ and /samples/family that returns a note with more information about what the consumers of your API are most likely doing wrong.
uris = {
Explanitory400Controller: '/samples/',
SampleController: '/samples/<string:hash_or_id>',
Explanitory400Controller: '/samples/family',
SampleFamilyController: '/samples/<string:hash_or_id>/family',
}

REST Architecture - How the Url of a complex method would look like?

I have the following Url which returns me the list of resources:
http://example.com/resources/
I also implemented a method which returns a specific resource (in this case, the resource 142).
http://example.com/resources/142
I would like to add a method which is outside the typical HTTP method: List, Create, Retrieve, Replace, Update. What is the pattern to follow? In my specific case, I need to check the availability of resource. How would the Url look like (http://example.com/resources/checkavailability/142)?
I though about simply using the GET method and retrieve that information as part of the object returned. However, some of my colleagues argue that this would not be efficient (the data to transfer would be much bigger than just returning true/false).
Thanks for the help!
There is no need for a resource to check the availability of another resource, and there is no need for a GET request, a HEAD request should be enough, this is the same as a GET request but without transferring the body. You can then look at the return codes, and via those determine if the resource is available. This is assuming you have properly implemented return codes.
Restful over HTTP gives you uniform interface, you often don't need to encode the actions inside your URL
Regarding your mentioned /checkavailability using GET returning payload inefficiency is a valid reason, so use HEAD (it only gives you back the response headers).
request:
HEAD /resources/123
response status:
404 Not Found: equals to /checkavailability == false
200 OK: equals to /checkavailability == true
Other suggestions uniform interface replacements:
/resources/list : GET /resources
/resources/replace/123: PUT /resources/123
/resources/update/123: PUT /resources/123
/resources/create: POST /resources