After some googling I decided to directly ask this:
Is it possible to run REST API endpoint "build tests" based on solely an OpenAPI 3.0 specification file?
I would like to add example request-response pairs to the OpenAPI spec file and have either an existing or self-written library run through all the such defined tests and report any failures.
As far as I understand the standard, it would be easily possible to include examples for requests and test the response in a schematic way (thinking http://json-schema.org/). But I don't yet see a way to incorporate more specific tests, such as testing a number in a specific response field to be an exact value. Also, it would be nice to have a way to sequentially test requests, but I don't expect to achieve that just from the spec file.
An optimal solution would be included in my repository and run the tests on localhost. Thank you all very much in advance.
Is it possible to run REST API endpoint "build tests" based on solely an OpenAPI 3.0 specification file?
Yes. The spec has at least two components that allow automatic tests generation:
Examples. You could specify examples for defined endpoints, which describe concrete data samples you send/receive.
Schemas. They describe data models, which you can use to generate requests to the API.
But I don't yet see a way to incorporate more specific tests, such as testing a number in a specific response field to be an exact value.
It can be done using the "enum" keyword with a single value in a list in the schema for the desired field. Open API doesn't support the "const" keyword in contrast with JSON Schema.
Also, it would be nice to have a way to sequentially test requests, but I don't expect to achieve that just from the spec file.
To achieve that you could use Open API links, which allows you to specify how to construct a request to endpoint B from request or response to endpoint A. For example:
paths:
/users:
post:
summary: Creates a user and returns the user ID
operationId: createUser
responses:
'201':
description: Created
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int64
description: ID of the created user.
links:
GetUserByUserId:
operationId: getUser
parameters:
userId: '$response.body#/id'
/users/{userId}:
get:
summary: Gets a user by ID
operationId: getUser
parameters:
- in: path
name: userId
required: true
schema:
type: integer
format: int64
In this example, the id value returned in the 201 response to the POST /users can be used as the userId parameter in GET /users/{userId}. In this way, you can define sequences of requests to different endpoints.
I want to note two tools that can generate and execute test cases based only on the input Open API spec:
Schemathesis uses both sources and doesn't require configuration by default. It utilizes property-based testing and verifies properties defined in the tested schema - response codes, schemas, and headers. It supports Open API 2 & 3 and stateful testing via Open API links and automatically can generate sequences of API requests based on their definition in the spec file.
Dredd focuses more on examples and provides several automatic expectations. It supports only Open API 2, and the third version is experimental.
Both provide a CLI and could be extended with various hooks to fit the desired workflow.
Related
I'm working on some API service which consume REST queries (CRUD operations) and send appropriate CLI commands to some network equipment.
There is 2 possible ways to design Openapi specification for this service:
Detailed huge API spec. Describe exactly all the endpoints, all the schemas, all the params that exist in the network equipment CLI. I think specification will be about 100K of lines in this way. Specification can be autogenerated based on device CLI parsing (using ? and TAB keys).
Generalized tiny API spec. Hide all device configuration details in a few common parameters. Something like
paths:
/api/{CLI_endpoint}: # we say "CLI_endpoint" instead of describing all the endpoints
...
post:
requestBody:
content:
application/json:
schema:
type: object # we say "object" instead of describing all the params
In this way we simply say that all the endpoint names and param names correspond to network equipment CLI documentation.
Which of the ways will be better?
Is there any way to request Magnolia REST API for list of products
which could be retrieved with equivalent of JCR SQL2
select * from [mgnl:product] where productName like '%Nikon%'
If it's only possible with custom rest end-point could you please point to tutorial.
Update as of Magnolia REST 2.1, using the v2 endpoint definition:
To answer the second question about node-types, here's what it looks like, as a YAML file in a light module, e.g. <module-name>/restEndpoints/delivery/my-products_v1.yaml:
class: info.magnolia.rest.delivery.jcr.v2.JcrDeliveryEndpointDefinition
workspace: products
rootPath: /
includeSystemProperties: false
bypassWorkspaceAcls: true
depth: 2
nodeTypes:
- mgnl:product
childNodeTypes:
- mgnl:contentNode
The Delivery endpoint config takes node-types to include.
nodeTypes specify the primary list of JCR node types to query—in your case mgnl:product;
childNodeTypes specify which child-nodes to include as JSON objects under the primary results, when depth is greater than 0.
With the above configuration, you may run the following requests to query products or get a single product, respectively:
GET <host>/.rest/delivery/my-products/v1?productName[like]=%25Nikon%25
GET <host>/.rest/delivery/my-products/v1/path/to/Nikon-1
This differs from Magnolia's former Nodes endpoint, which is not configurable, but only lets consumers exclude node-types.
Yes, you can use content delivery endpoint to do so. Syntax is like: GET /delivery/{endpoint-prefix}/v1?key1=value1&key2=value2
See https://git.magnolia-cms.com/projects/MODULES/repos/rest/browse/magnolia-rest-content-delivery for more details.
I am designing my first web API, and I'm having difficulties settling on a naming scheme for the URIs.
The API does not address actual resources, instead it is being made to accept a query, run some logic on the query string, accumulate respective results from different other APIs, perhaps run some logic on the accumulated result again, and return the result.
I have started to set up the single GET that exists as follows (returns "result" object in JSON).
api.example.com/query?string=foo&otherparam=bar
However, I'm unsure whether this follows best practices.
Problem 1
I'm starting to think that in order to follow best practices for API design, the endpoint name shouldn't actually be query, it should be result, but as I don't actually have resources, this is a bit counterintuitive.
So question 1 would be: Is api.example.com/result the better endpoint name?
Problem 2
This refers to semantic URLs. Consider the following example from Wikipedia: Semantic URLs.
Non-semantic URL:
http://example.com/products?category=12&pid=25
Semantic URL:
http://example.com/products/12/25
Semantic URL adapted for my case:
http://api.example.com/result/foo/bar
This is very logical and works well if you have actual resources that you look up. In my case, however, the parameter string is the query string, and the parameter otherparam is a boolean describing a property of the query string.
So question 2 is really: If the answer to question 1 is "yes", what should a semanticized URL in my case be:
http://api.example.com/results/foo/bar?
http://api.example.com/results/foo?otherparam=bar?
(results should be plural I guess as it's describing the list of possible results.)
No, I do not think result is a good endpoint name. Besides, result is super generic and doesn't imply anything.
When I design APIs, the endpoints can either be resources or actions on resources
https://api.example.com/accounts/1/authorize - the resource here is accounts and the action is authorize
https://api.example.com/search - the resource here would be the entire platform so any resource could be returned and the action is search
So is there any type of resource you can attach to the query action? Or it sounds like this type of endpoint would suit you better?
https://api.example.com/logic/run
I have a resource which basically represents a number. I have two possible updates for this number: Set the number to a specific value or add a value to it. Now I'm confused if I can use the query string part of the URL to specify the desired behavior.
Something like this:
/resource/{id}/?mode=add
/resource/{id}/?mode=set
Or is there an alternative way two represent to update strategies for a rest resource?
An Alternative would be to extend the request body with this information but this since strange, since the request data should contain the data and not "meta information" for the request itself - as far as I understand REST apis.
The project is an ordinary angularjs (client) and java (server) project.
I am starting a new project and I was trying to figure out if I should follow a RESTful approach or not. By reading different sources on the internet I am getting more and more confused on how a truly RESTful approach should be. Some people say that the REST request (ie, both the URI and the rest of the content of the HTTP request) should never describe an action with something other than the HTTP verbs. Some others say that since the HTTP verbs are limited, the HTTP request body can provide additional info regarding which action need to be applied on the data described by the URI. Which of the two is correct? I will give you a simplified description of the software I am trying to build and how I think it should implemented with REST: The user must be able to upload/delete/edit data on the server. Then, he must be able to perform 10 different kinds of analysis (analysis01-analysis10) on the server in the form of jobs. So, the user will be submitting jobs to the server. When the jobs are finished the user will be able to get the results of the analysis. So here is how I think is the right way of implementing this in REST:
Datasets:
POST /datasets/ - To create/upload a new dataset
GET /datasets/ - To get a list of all the available datasets.
GET /datasets/01 - To get info about dataset 01
DELETE /datasets/01 - To delete dataset 01
Jobs:
POST /analysis01_jobs/ - Submit a new job for analysis01
GET /analysis01_jobs/ - Get a list with all the submitted analysis01 jobs
GET /analysis10_jobs/ - Get a list with all the submitted analysis10 jobs
GET /analysis01_jobs/01 - Get the status of job '01' which performs analysis of type 01
DELETE /analysis10_jobs/01 - Delete/Cancel job '01' which performs analysis of type 10
As you can see each type of analysis has a different REST URL path for the jobs. I was thinking to change this and put all jobs under the same path: "/analysis_jobs/" and specify the type of analysis I want inside the HTTP header. But this will imply the type of action I want the server to perform. Thus this this is not RESTful any more. Right or wrong?
When a job is complete it will produce a "result" resource. So the REST API for this will be something like this:
- There is no POST here because only the job that runs on the server can generate results.
GET /analysis01_results/ - To get a list of all the available results from analysis01 jobs
GET /analysis01_results/01 - To get the results of a job that performed analysis of type 01. The body of the HTTP response will also contain info about the "parent" job and data.
DELETE /analysis01_results/01 - To delete the above results.
Is the above design RESTful?
Thank you in advance!
REST is about machine to machine communication. If you don't have at least 2 different clients I don't think it will worth the effort to implement a REST service.
Some people say that the REST request (ie, both the URI and the rest of the content of the HTTP request) should never describe an action with something other than the HTTP verbs. Some others say that since the HTTP verbs are limited, the HTTP request body can provide additional info regarding which action need to be applied on the data described by the URI. Which of the two is correct?
You should read the Fielding dissertation, it is the only true source of knowledge. :D
Both can be wrong. The second one is closer to the truth. If you need to describe a new action, you can always define a new resource and use it with the existing HTTP verbs. For example ANALYZE /datasets/1 can be described with POST /analysis/ {dataset: {id: 1}}.
Be aware that we are talking here about hyperlinks:
POST /datasets/ - To create/upload a new dataset
This is an action, but this is a hyperlink as well in the representation of the /datasets/, which you can access with GET /datasets/. What you can add to the body is the To create/upload a new dataset part, so the client won't need to know anything about the URI structure to understand what the link does.
{
href: "/datasets/",
method: "POST",
rel: "/docs/datasets/create"
}
You can access the form description with GET /docs/datasets/create. (Currently ppl are working on a standard format, to describe these descriptions, e.g. RDF + Hydra. But that is not production ready currently.)
Ofc. you can expand the description if you want:
{
href: "/datasets/",
method: "POST",
rel: "/docs/datasets/create",
label: "Create a new dataset",
description: "You can create a new dataset by sending this form.",
fields: {
label: {
type: "string",
label: "Title",
description: "You can give a title to the dataset here.",
...
},
records: {
type: "array",
...
}
}
}
but it is easier to generate a documentation if you describe everything in a docs file, probably in JSON-LD for the REST clients and in HTML for the 3rd party developers of the clients.
POST /analysis01_jobs/ - Submit a new job for analysis01
GET /analysis01_results/ - To get a list of all the available results from analysis01 jobs
GET /analysis01_results/01 - To get the results of a job that performed analysis of type 01. The body of the HTTP response will also contain info about the "parent" job and data.
I would rather use
POST /jobs/ {analysis: {id: "01"}}
GET /analysis/01/jobs
GET /jobs/2345/result
You are going in the right direction but still you can moderate it.
1-
Is REST a good solution for my application?
Yes and you can compare it .REST vs SOAP on this question
2-
Use PUT for Creating or Adding a resource or Job instead of POST.
Resources are manipulated using a fixed set of four create, read, update, delete operations: PUT, GET, POST, and DELETE. PUT creates a new resource, which can be then deleted by using DELETE. GET retrieves the current state of a resource in some representation. POST transfers a new state onto a resource. See Responding to HTTP Methods and Requests for more information.
Source Oracle docs