As per http://perfect.org/feature-requests.html
I would like to request that RAML functionality be included out of the box.
I would like to see something like the following on the server for serving RAML documentation:
server.addRamlDocs(path: "/raml.raml", versionRaml: 1.0, versionApi: "v1", title: "Test API title")
This would add a route that when matched creates a full RAML file for all RAML routes.
RAML routes should probably be created in a similar fashion to MustachePageHandler but split into RamlDescriptionHandler, RamlValidateRequestHandler, RamlRequestHandler and RamlResponseHandler.
RamlDescriptionHandler
This should be responsible for:
Describing the request / response
Automatically creating documentation for the request (when server docs matched)
RamlValidateRequestHandler
Validating and type casting the request
This should then inject HTTPRequest.ramlRequestData and HTTPRequest.ramlRequestIsValid. This should require no action from the application developer.
RamlRequestHandler
Application logic to be coded by the developer, should check and use HTTPRequest.ramlRequestData and HTTPRequest.ramlRequestIsValid
Should set HTTPResponse.ramlStatus (HTTP Status Code) and HTTPResponse.ramlData
RamlResponseHandler
Should validate the response and send matching against RamlDescriptionHandler, no action from the application developer.
Related
I have the following resources in my system 1. Services 2. Features where a feature has the following JSON structure,
{
id: "featureName",
state: "active",
allowList: [serviceID1, serviceID2],
denyList: [serviceID3, serviceID4]
}
I am trying to update the allowList or denyList which consists of serviceIDs and thinking of using PATCH method to do it like below,
/features/{featureId}/allowlist
/features/{featureId}/denylist
/features/{featureName}/state/{state}
My first question is should I even include allowlist, state, denylist in the url as my resources are services and features, not the allowlist or denylist.
How should the rest endpoint look like?
After reading thread mentioned below I was thinking about restructuring urls as below,
/features/{featureId}
[
{ "op": "add", "path": "/allowList", "value": [ "serviceA", "serviceB"]},
{ "op": "update", "path": "/state", "value": false}
]
Lastly, the use of PATCH even justified here? or there is any better way to design the api.
Note: I have got some help from the thread REST design for update/add/delete item from a list of subresources but have not used patch often.
How should the rest endpoint look like?
The URI that you use to edit (PUT, PATCH) a resource should look the same as the URI that you use to read (GET) the resource. The motivation for this design is cache-invalidation; your successful writes automatically invalidate previously cached reads of the same resource (same URI).
Lastly, the use of PATCH even justified here? or there is any better way to design the api.
In this example, the representation of the document is small compared to the HTTP headers, and the size of your patch document is close to the size of the resource representation. If that's the typical case, I'd be inclined to use PUT rather than PATCH. PUT has idempotent semantics, which general purpose components can take advantage of (for example, automatically resending requests when the response to an earlier request has been lost on the network).
GET /features/1 by user1
PUT /features/1 //done by user 2
PUT /features/1 //done by user1
the PUT by user2 will not be visible for user1 and user1 will make an update on the old object's state (with id=1) what can be done in this situation?
Conditional Requests.
You arrange things such that (a) the GET request from the server includes validators that identify the representation (b) the server responds 428 Precondition Required when the request lacks conditional headers (c) the clients know to read the validators from the resource metadata, and use the correct condition headers when submitting the PUT request (d) the server knows to compare the validator to the current representation before accepting the new representation.
We have a FastApi application that is hosted behind a reverse proxy.
The proxy authenticates the user using Kerberos and adds a X-Remote-User HTTP header to the request.
This header is required by the FastApi application. Here is an example route:
#app.get("/user/me")
async def get_user_me(x_remote_user: str = Header(...)):
return {"User": x_remote_user}
The X-Remote-User header is required for the request which is expected behavior.
When we now open the Swagger Ui, the header is documented and when clicking on "Try it out", we can provide the header value.
This behavior is great for development, but in all other cases it is undesired, because that header is provided by the reverse proxy. For instance, we generate clients using OpenAPI Generator and the clients then all require the X-Remote-User parameter in their requests.
Hence, it would be useful to have a configuration that distinguishes between the environments. If we are behind a reverse proxy, then the generated OpenAPI Schema by FastApi should not include the X-Remote-Header, otherwise if we are in development, it should be included.
What I did so far:
I checked the documentation about security and also some source code of these modules, but I was not able to find a solution.
In the documentation, I read the section Behind a Proxy, but nothing there points me to a potential solution.
I also read about Middleware, but again, no solution.
We could change the generated OpenApi schema. I sketched this in my answer below, but this is not a very elegant solution
Does anyone have a good solution to this problem?
We can use APIKeyHeader to remove the X-Remote-User header from the API signature, but still enforcing the header to be present.
from fastapi.security import APIKeyHeader
apiKey = APIKeyHeader(name="X-Remote-User")
#app.get("/user/me")
async def get_user_me(x_remote_user: str = Depends(apiKey)):
return {"User": x_remote_user}
When the header is not present, we get a "403 Forbidden". If it is present, we retrieve the header value.
The Swagger UI now has a button "Authorize" where we can fill-in the value of the X-Remote-User for testing purposes.
One approach is to generate the OpenApi schema as described in the documentation Extending OpenAPI. After the generation, remove the X-Remote-User from the schema. In the configuration could be a flag that the application it is behind a reverse proxy to execute the code conditionally:
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from MyConfig import Config
app = FastAPI()
#app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
if Config.reverse_proxy:
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
// remove X-Remote-User here
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
However this is not a very elegant solution, as we need to parse the Json string and remove the different deeply-nested occurrences of the X-Remote-User header everywhere. This is prone to bugs resulting in an invalid schema. Furthermore it could break if new Rest endpoints are added.
A new param will be soon available for Header, Query and other to exclude elements from the openAPI output: include_in_schema=False
Example:
def test(x_forwarded_for: str = Header(None, include_in_schema=False)):
...
Here the patch state: https://github.com/tiangolo/fastapi/pull/3144
I commence in REST and I have some questions:
What type must the controller return? Typically, I'm asking if my Rest #Controller must return Item object as it is or encapsulate it in ResponseEntity in order to specify http-status-code.
What http status code to use in a GET method on a particular item ("/items/2") if the given item does not exists: HttpMediaStatus.OK(200) and null return or HttpStatus.NO_CONTENT(204) and null return ?
Second part: I saw it was possible to specify #Produces and #Consumes on WS method but what the use of that? My application and my methods work so, why specify MediaType.APPLICATION_JSON_VALUE? Doesn't Spring/SpringBoot automatically convert Item or ResponseEntity into json?
Context: using Spring Boot, hibernate, REST webservice.
Thank you.
Many questions in one, I'll provide short answers with a bunch of link to relevant articles and the reference documentation.
What type must the controller return?
Depends on your annotation and the RESTful-ness of your service. There are three annotations you can use for controllers: #Controller, #RestController and #RepositoryRestController.
Controller is the base annotation to mark your class as a controller. The return type of the controller endpoint methods can be many things, I invite you to read this dedicated post to get a grasp of it.
When developing a pure-REST service, you will focus on using RestController and RepositoryRestController.
RestControlleris Controller + ResponseBody. It binds the return value of the endpoint method to the web response body:
#RestController
public ItemController {
#RequestMapping("/items/{id}")
public Item getItem(#PathVariable("id") String id) {
Item item = ...
return item;
}
}
With this, when you hit http:/.../api/items/foo, Spring does its magic, automatically converting the item to a ResponseEntity with a relevant 40X status code and some default HTTP headers.
At some point, you will need more control over the status code and headers, while still benefiting from Spring Data REST's settings. That's when you will use RepositoryRestController with a ResponseEntity<Item> as return type, see the example the Spring Data REST reference.
What http status code to use in a GET method on a particular item if the given item does not exists?
Bluntly said: use HttpStatus.NOT_FOUND. You're looking for a resource that does not exist, there's something wrong.
That being said, it is completely up to you to decide how to handle missing resources in your project. If your workflow justifies it, a missing resource could be something completely acceptable that indeed returns a 20X response, though you may expect users of your API to get confused if you haven't warned them or provided some documentation (we are creatures of habits and conventions). But I'd still start with a 404 status code.
(...) #Produces and #Consumes on WS method but what the use of that? My application and my methods work so, why specify MediaType.APPLICATION_JSON_VALUE? Doesn't Spring/SpringBoot automatically convert Item or ResponseEntity into json?
#Consumes and #Produces are respectively matched against content-type and accept headers from the request. It's a mean of restricting the input accepted and the output provided by your endpoint method.
Since we're talking about a REST service, communications between clients of the API and the service are expected to be JSON-formatted. Thanks to Spring HATEOAS, the answer are actually formatted with the application/hal+json content-type.
In that scenario, you can indeed not bother with those two annotations. You will need them if you develop a service that accepts different content-types (application/text, application/json, application/xml...) and provides, for instance, HTML views to users of your website and JSON or XML response to automated clients of your service.
For real life examples:
Facebook provides the Graph API for applications to read to/write from its graph, while users happily (?) surf on web pages
Google does the same with the Google Maps API
I am struggling with a design aspect of my restful api for templating collections of resources.
The endpoint calls for a json with the name to a particular template and a collections of tokens. The API will then create entries into numerous tables and use the tokens where appropriate.
A very simple example is:
*{
'template': 'DeviceTemplate'
'tokens': [
'customer': 1234,
'serial_number': '12312RF3242a',
'ip_address': '1.1.1.1'
]
}*
This creates a new device for the customer with that ip address along with several other objects, for instance interfaces, device users etc etc. I use the tokens in various places where needed.
I'm not sure how to make this endpoint restful.
The endpoint for /device is already taken if you want to create this resource individually. The endpoint I need is for creating everything via the template.
I want to reserve the POST /template endpoint for creating the actual template itself and not for implementing it with the tokens to create the various objects.
I want to know how to call the endpoint without using a verbs.
I also want to know if its a good idea to structure a POST with a nested JSON.
I'd suggest that you create an action on the template object itself. So right now if you do /templates/<id> you are given an object. You should include in that object a url endpoint for instantiating an instance of that template. Github follows a scheme that I like a lot [1] where within an object there will be a key pointing to another url with a suffix _url. So for instance, your response could be something like:
{
"template": "DeviceTemplate",
"id": "127",
...
"create_url": "https://yourdomain.com/templates/127/create",
...
}
Then this way you treat a POST to that endpoint the same as if this template (DeviceTemplate) was its own resource.
The way to conceptualize this is you're calling a method on an object instead of calling a function.
[1] - For example https://developer.github.com/v3/#failed-login-limit
I'm currently working on a REST API, trying to design it with most best practices as possible.
I work with Symfony2 PHP framework but some of my questions are valid for any REST API i guess.
Starting from the base design for a particular resource :
GET /resource - Get all resources
POST /resource - Create resource
GET /resource/{id} - Get resource with id={id}
PUT|PATCH /resource/{id} - Edit the resource with id={id}
DELETE /resource/{id} - Delete the resource with id={id}
Supposing my resource has complex rules while updating.
It has a "status" field, (a float for example), that can be updated only by following a particular scheme
It has a "schedule" field (a datetime), with different choices available that are not always the same
How am I supposed to expose those rules to the API consumer ? For the schedule field, how am I supposed to provide the different choices available at the current time ?
About the Symfony server-side part, I followed most of the recommandations of this walkthrough : http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/
My POST, PUT & PATCH actions are handled with Symfony Forms, so most of the rules are processed by Symfony constraints/validations features.
But form binding is quite limited, let's supposed I want to trigger a particular event if the user change the status field from 2 to 3? What is the best way to do that ?
Thanks in advance.
HTTP has another verb you aren't using: OPTIONS. You can use this to list the schedule options.
Here's a blog article about it: http://zacstewart.com/2012/04/14/http-options-method.html
As for updating the status, I would reuse POST and include an action in the field. Example:
POST
{
"type": "update",
"status": 3
}
Modified REST:
GET /resource - Get all resources
POST /resource - Create resource
GET /resource/{id} - Get resource with id={id}
PUT|PATCH /resource/{id} - Edit the resource with id={id}
DELETE /resource/{id} - Delete the resource with id={id}
OPTIONS /resource/{id} - Retrieve options of resource with id={id}
Keep in mind that you can pass params along in the body for everything but GET and you can pass any params in the URL for GET.
I have zero knowledge on Symfony2, so I'll just concentrate on your more generic REST how-to qustion about exposing rules.
Give the consumers of your REST API a documentation. It's the first thing they will hit before actually playing with your API. Use tools for that, from auto-generated help pages to 3'rd party providers like Apiary.io or alike.
Create meaningful responses when consumers send "wrong" requests: use correct http response status codes (Bad request, Conflict, etc.) when request parameters are missing or invalid.
If your REST api is relaxed, it can also include information about what went wrong and how to resolve the problem in the response body.
What worked well for me in the past was to have a generic ErrorMessage entity that was returned upon each non-successful request, containing a title, an error description, and a dedicated more technical "dev-description" which can be enabled/disabled for test/production on the server side.
In my case, my consumers all know that they can get either the expected response entity in case of success, or that generic ErrorMessage entity in the response in case of failure.
If you can desribe your rules, why not provide those as meta information for your service? Eg. in my case I know I have a set of parameters, each having a set of available options. Think of the parameters as the key in a query string, and the options as the values for that key. In a complex world, parameter options depend on other parameter options, eg. in my case the available options for parameter B are dependent of what option(s) are "selected" for parameter A. I can expose those dependencies by providing a "metadata" resource in my REST api, eg. a JSON stucture listing all parameters and all options for those parameters, and for each option adding a "requires" section desribing that that option is only "available" if parameter xy has selected option p and q.
This allows my consumers to - with a single request to that meta data resource - create a "state-machine" on the client side. I hope you get the picture.
Here is my understanding of REST-full way to handle updates and advertise update operations to API client.
This is based on this wonderful book and Fowler's article about REST with some additions of File Levels of Media Type and article about Restfull CQRS. Basically you use PUT for update and pass the operation via content type and advertise content type via mediaType in hypermedia controls.
All operations which are available for current state of your resource are listed among hypermedia controls which are passed with representation of resource like this:
<myresource>
<status>ACTIVE</status>
<some-field with-attribute="value"/>
<some-other-field/>
<!-- other fields representing state of resource -->
<link rel = "self"
uri = "/resource/1234"/>
<link rel = "/linkrels/resource/changeStatus"
uri = "/resource/1234"
mediaType = "application/vnd.myapp+xml;domain-model=ChangeStatusCommand"/>
<link rel = "/linkrels/resource/changeSchedule"
uri = "/resource/1234"
mediaType = "application/vnd.myapp+xml;domain-model=ChangeScheduleCommand"/>
<link rel = "/linkrels/help"
uri = "/help/resource"/>
</myresource>
Links together with mediaType gives enough information what command is allowed. In many cases this should be something very specific to current state of resource. For example if you can move it from status ACTIVE to TRASHED than command should be named not StatusChange but TrashCommand and so on.