We have a service that provides 2 separate Rest API. One is a simple API that our customers use and the other one is an internal API used by a web application.
Our customers are not able to access the web API so I would like to be able to provide 2 separate OpenApi specifications, one for our customers and one for our web developers.
I found a pretty straightforward way to achieve what I want by creating an endpoint, retrieve the OpenApi document and filter out the tags belonging to the customer API.
#Inject
OpenApiDocument document;
#Operation(hidden = true)
#GET
#Produces("application/yaml")
public Response customer() throws IOException {
OpenAPI model = FilterUtil.applyFilter(new MyTagFilter("mytag"), document.get());
String result = OpenApiSerializer.serialize(model, Format.YAML);
return Response.ok(result).build();
}
One problem is that the injected OpenApiDocument instance is null in development mode. The OpenApiDocumentProducer seems to be missing some classloader magic that is present in the OpenApiHandler class. Another minor problem is that the filter “MyTagFilter” also needs to filter out Schemas not used by any tagged PathItems and the code becomes somewhat dodgy.
Is there a better way to solve my problem?
Would it be possible to fix OpenApiDocumentProducer to provide a non null and up to date OpenApiDocument in developer mode?
Similar question: Quarkus: Provide multiple OpenApi/Swagger-UI endpoints
Related
I think that my problem is a common one, and I'm weighing the costs and benefits of GraphQL as a solution.
I work on a product whose data is stored by a monolithic CRUD-based REST API. We have components of our application expose a search interface for data, and of course need some kind of server-side support for making requests for that data. This could include sorting, filtering, choosing fields, etc. There are, of course, more traditional ways of providing these functions in a REST context, like query parameter add-ons for endpoints, but it would be cool to try out GraphQL in this context to build a foundation for expanding its use for querying a bit.
GraphQL exposes a really nice query language for searching on data, and ultimately allows me to tailor the language of search specifically to my domain. However, I'm not sure if there is a great way to leverage the IDL without managing a separate server altogether.
Take the following Java Jersey API Proof-of-Concept example:
#GET
#Path("/api/v1/search")
public Response search(QueryIDL query) throws IOException {
final SchemaParser schemaParser = new SchemaParser();
TypeDefinitionRegistry typeDefinitionRegistry = // load schema
RuntimeWiring runtimeWiring = // wire up data-fetching classes
SchemaGenerator schemaGenerator = new SchemaGenerator();
GraphQLSchema graphQLSchema =
schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);
GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();
ExecutionResult executionResult = build.execute(query.toString());
return Response.ok(executionResult.getData()).build();
}
I am just planning to take a request body into my Jersey server that looks exactly like the request that would be sent to a GraphQL server. I'm then leveraging some library support to interpret and execute the request for data.
Without really thinking too much about everything that could go wrong, it looks like a client would be able to use this API similar to the way they would use a GraphQL server, except that I don't need to necessarily manage a separate server just to facilitate my search requirements.
Does it seem valuable, or silly, to use the GraphQL IDL in an endpoint-based context like this?
Apart from not needing to rebuild the schema or the GraphQL instance on each request (there are cases where you may want to rebuild the GraphQL instance, but your case is not the one), this is pretty much the canonical way of using it.
It is rather uncommon to keep a separate server for GraphQL, and it usually gets introduced exactly the way you described - as just another endpoint next to your usual REST endpoints. So your usage is legit - not silly at all :)
Btw, I'm not sure what would QueryIDL be... the query is just a string. No need for a special class.
I am developing a rest-api.
My api maps a query string like: email=xyz#gmail.com&gender=MALE in a sql statement: where email = xyz#gmail.com.br and gender = MALE
So why not pass the SQL statament using just a POST method instead of a GET?
Is there any best practices?
Because that would not be REST, it would be something like SOAP.
REST is about resources and operations on them. If you implement REST using HTTP, there are HTTP verbs that should be used for specifict actions:
GET is for getting a resource
POST is for creating a new resource in a collection (plus some special cases
PUT is for changing an existing resource
DELETE is for deleting an existing resource
These verbs must follow a specific behaviour. One of these is that GET must not change the resource while POST usually does change it.
Using POST instead of GET is against REST and all established standards.
why not pass the SQL statament using just a POST
Because this would expose details about your implementation to the user. This can open security holes. REST is about resources, an abstraction, not about the easies way to expose a database.
I want to place facet requests to (some) indexed fields. In order to place a facet request, I need to know the name of the corresponding field.
Is there a way to programmatically get a list of field names annotated with #Field?
The answer to your question will depend on the version of Search you are using. If you are using a pre Search 5 release where it was possible to facet on any #Field (with the documented restrictions), then you can use the public metadata API to get all configured fields.
The entry point into the public metadata API is via SearchFactory.getIndexedTypeDescriptor(Class<?> entityType) which returns an IndexedTypeDescriptor for the specified entity type. You can then iterate the configured properties and for each properties get the list of configured fields.
As of Search 5, however, facet fields needs to be marked at configuration time using #Facet(s). Only properties with this annotation can be faceted upon. Obviously the public metadata API should expose this as well. Unfortunately, this is not yet implemented - HSEARCH-1853.
There is a workaround if you are happy to use some internal APIs which might change in the future. You would only need this until HSEARCH-1853 is implemented at which stage you could switch to this public (and supported) API.
Search also maintains something which is called an internal metadata API which it uses for all its inner workings. It is basically just a richer model of the public API which is more restrictive on what's exposed. Bottom lines, you want to get hold of the org.hibernate.search.engine.metadata.impl.FacetMetadata. To do so you need to get hold of the DocumentBuilderIndexedEntity which gives you access to the internal org.hibernate.search.engine.metadata.impl.TypeMetadata. Via this type metadata you can get access to PropertyMetadata, then DocumentFieldMetadata and finally FacetMetadata.
To get hold of the DocumentBuilderIndexedEntity, you could do something like this:
ExtendedSearchIntegrator integrator = ContextHelper.getSearchintegratorBySFI( sessionFactory );
IndexManager[] indexManagers = integrator.getIndexBinding( clazz ).getIndexManagers();
DirectoryBasedIndexManager indexManager = (DirectoryBasedIndexManager) indexManagers[0];
EntityIndexBinding indexBinding = indexManager.getIndexBinding(clazz);
DocumentBuilderIndexedEntity documentBuilder = indexBinding.getDocumentBuilder();
Note, the internal API might change at any stage. No guarantees regarding backwards compatibility and evolution of the API are given.
I am currently creating Restful API through ASP.Net WebAPI technology. I have 2 questions related to WebAPI
I had done below:
Created below method in Controller class:
public HttpResponseMessage PostOrderData(OrderParam OrderInfo)
Based on Parameter OrderInfo, Query the SQL Server and get list of orders.
Set the Response.Content with the collection object:
List<Orders> ordList = new List<Orders>();
//filled the ordList from SQL query result
var response = Request.CreateResponse<List<Orders>>(HttpStatusCode.OK, ordList);
On Client side,
OrderParam ordparam = new OrderParam();
response = client.PostAsJsonAsync("api/order", ordparam).Result;
if (response.IsSuccessStatusCode)
{
List<Orders> mydata = response.Content.ReadAsAsync<List<Orders>>().Result;
}
So question: is it fine to Post the data to server to Get the data i.e. usage of Post data insted of Get is correct? Is there any disadvantage in approach? (One disadvantage is: I will not able to query directly from browser) I have used Post here because parameter "OrderParam" might extend in future and there might be problem due to increase in Length of URL due to that.
2nd Question is: I have used classes for parameter and for returning objects i.e. OrderParam and Orders. Now consumer (clients) of this web api are different customers and they will consume API through .Net (C#) or through Jquery/JS. So do we need to pass this class file containing defination of OrderParam and Orders classes manually to each client? and send each time to client when there will be any change in above classes?
Thanks in advance
Shah
Typically no.
POST is not safe nor idempotent - as such cannot be cached. It is meant to be used for cases where you are changing the state on the server.
If you have a big critieria, you need to redesign but in most cases, URL fragments or querystring params work. Have a look at OData which uses querystring for very complex queries and uses GET.
With regard to second question, also no. Server can expose schema (similar to WSDL) or docs but should not know about the client.
Yes you can, RESTFUL is nothing to do with Security, it is just a Convention and for Web API you can use it because you do not need any caching for web api.
I've come across a problem at work where I can't find information on the usual standard or practice for performing CRUD operations in a RESTful web service against a resource whose primary key is a composite of other resource ids. We are using MVC WebApi to create the controllers. For example, we have three tables:
Product: PK=ProductId
Part: PK=PartId
ProductPartAssoc: PK=(ProductId, PartId)
A product can have many parts and a part can be a component of many products. The association table also contains additional information relevant to the association itself than needs to be editable.
We have ProductsController and PartsController classes that handle the usual GET/PUT/POST/DELETE operations using route templates defined as: {controller}/{id}/{action} such that the following IRIs work:
GET,POST /api/Products - returns all products, creates a new product
GET,PUT,DELETE /api/Products/1 - retrieves/updates/deletes product 1
GET,POST /api/Parts - returns all parts, creates a new part
GET,PUT,DELETE /api/Parts/2 - retrieves/updates/deletes part 2
GET /api/Products/1/Parts - get all parts for product 1
GET /api/Parts/2/Products - get all products for which part 2 is a component
Where I am having trouble is in how to define the route template for ProductPartAssoc resources. What should the route template and IRI look like for getting the association data?
Adhering to convention, I would expect something like:
GET,POST /api/ProductPartAssoc - returns all associations, creates an association
GET,PUT,DELETE /api/ProductPartAssoc/[1,2] - retrieves/updates/deletes association between product 1 and part 2
My coworkers find this aesthetically displeasing though and seem to think it would be better to not have a ProductPartAssocController class at all, but rather, add additional methods to the ProductsController to manage the association data:
GET,PUT,DELETE /api/Products/1/Parts/2 - get data for the association between product 1 and part 2 rather than data for part 2 as a member of part 1, which would conventionally be the case based on other examples such as /Book/5/Chapter/3 that I have seen elsewhere.
POST No clue here what they expect the IRI to look like. Unfortunately, they're the decision makers.
At the end of the day, I guess what I am seeking is either validation, or direction that I can point to and say "See, this is what other people do."
What is the typical practice for dealing with resources identified by composite keys?
I too like the aesthetics of /api/Products/1/Parts/2. You could also have multiple routes go to the same action, so you could double up and also offer /api/Parts/2/Products/1 as an alternate URL for the same resource.
As for POST, you already know the composite key. So why not eliminate the need for POST and just use PUT for both creation and updates? POST to a collection resource URL is great if your system generates the primary key, but in cases where you have a composite of already known primary keys, why do you need POST?
That said, I also like the idea of having a separate ProductPartAssocController to contain the actions for these URL's. You would have to do a custom route mapping, but if you're using something like AttributeRouting.NET that is very easy to do.
For example we do this for managing users in roles:
PUT, GET, DELETE /api/users/1/roles/2
PUT, GET, DELETE /api/roles/2/users/1
6 URL's, but only 3 actions, all in the GrantsController (we call the gerund between users and roles a "Grant"). Class ends up looking something like this, using AttributeRouting.NET:
[RoutePrefix("api")]
[Authorize(Roles = RoleName.RoleGrantors)]
public class GrantsController : ApiController
{
[PUT("users/{userId}/roles/{roleId}", ActionPrecedence = 1)]
[PUT("roles/{roleId}/users/{userId}", ActionPrecedence = 2)]
public HttpResponseMessage PutInRole(int userId, int roleId)
{
...
}
[DELETE("users/{userId}/roles/{roleId}", ActionPrecedence = 1)]
[DELETE("roles/{roleId}/users/{userId}", ActionPrecedence = 2)]
public HttpResponseMessage DeleteFromRole(int userId, int roleId)
{
...
}
...etc
}
This seems a fairly intuitive approach to me. Keeping the actions in a separate controller also makes for leaner controllers.
I suggest:
POST /api/PartsProductsAssoc: Create link between part and product. Include part and product ids in POST data.
GET, PUT, DELETE /api/PartsProductsAssoc/<assoc_id>: read/update/delete link with <assoc_id> (not part or product id, yes, this means creating a new column in your PartsProductsAssoc table).
GET /api/PartsProductsAssoc/Parts/<part_id>/Products: get list of products associated with the given part.
GET /api/PartsProductsAssoc/Products/<product_id>/Parts: get list of parts associated with the given product.
Reasons to take this approach:
Single, fully-qualified URI for each link.
Modifying a link modifies a single REST resource.
For more info, see https://www.youtube.com/watch?v=hdSrT4yjS1g at 56:30.