I'm working on a Vapor 3 app that uses the requesting path as the argument for the method that responds. For instance:
http://localhost:8080/monitor/some/test/path
That can be handled by a single endpoint, the monitor endpoint in this case, which would then ideally give me access to the rest of the URL, /some/test/path.
I've composed a route in Vapor that doesn't work using wildcard variables, and tried the group mechanic as described in the docs, to no avail. My expectation from using other web frameworks is that something like "/monitor/*" should do the job but I can't find anything in the documentation to suggest it.
Any assistance would be appreciated!
If you want to match any single path parameter, use the any path component. If you want to match any number of path parameters, use the all path component.
For example, if I register a route with these path components:
"service", any, "api", "users"
It will match these routes:
/service/v1/api/users
/service/caleb/api/users
But it won't match these:
service/v1/beta/api/users
service/v1
However, if you use the all component, like this:
"service", "api", all
You can match any of the following:
/service/api/v1
/service/api/v1/users/caleb
But not /service/api.
Related
Is there a way to get the resource id given partial url using rest admin api?
Below is the endpoint I call - http://localhost:8180/auth/realms/quickstart-serv-springboot/authz/protection/resource_set?uri=/wb/customer to fetch the resource id.
I want to know if I can pass wild characters in the query string of uri so that it returns the resource id. e.g. - http://localhost:8180/auth/realms/quickstart-serv-springboot/authz/protection/resource_set?uri=/wb/customer/* or http://localhost:8180/auth/realms/quickstart-serv-springboot/authz/protection/resource_set?uri=/wb/cust* or provide a regex pattern to fetch matching resource ids.
Thx
From source code it seems to work next way:
First Keycloak tries to find an exact match
Then if no match is found and there is parameter "matchingUri=true" it will try to find resources by pattern matching.
I didn't check but would recommend adding "matchingUri=true" to your query and try again.
Also pay attention that complex patterns are not supported. Keycloak Documentation says:
Currently a very basic logic for path matching is supported. Examples of valid paths are:
Wildcards: /*
Suffix: /*.html
Sub-paths: /path/*
Path parameters: /resource/{id}
Exact match: /resource
Patterns: /{version}/resource, /api/{version}/resource, /api/{version}/resource/*
When setting up URL Query String Parameters in the Integration Request part of an API method, it looks like I have the following options
reference a value from method.request.{path|querystring|header}.{var-name}
use a fixed single-quoted string
Even though API Gateway allows complex mappings on the body via VTL, it looks like querystring, header, and path variables do not have this option.
The specific use case I have is I want to populate the prefix query parameter for a call to S3's REST API with something like: 'read'+method.request.path.folder, so all GET requests start under a prefix (without the user having to specify that prefix).
Is there a way for me to achieve this goal using API Gateway?
I'm using Azure Service Fabric with stateless services. I have a list of services deployed under an application, and there's a naming convention used with those service names. I'd like to get a list of services that match a filter expression.
Here is a link to a screenshot of my service fabric explorer. I don't have the reputation points to post an image.
Service Fabric Explorer screenshot
In this example, the name of my application is SFApp1, and the name of my service is HelloWorldStateless. I'd like to query the service fabric cluster to locate all services with the name "HelloWorldSt*" (under the SFApp1 application of course).
I know I can query to find all services with the application name "fabric:/SFApp1", and it'll return all services under that application. This overload of GetServiceListAsync takes just an application URI.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1")).Result;
I also know I can query to find a specific service. This overload takes an application URI AND a service URI and will return a single-item list.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1"), new Uri("fabric:/SFApp1/HelloWorldStateless")).Result;
What I'm trying to find out is if there's any way to do something like a wildcard search.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1"), new Uri("fabric:/SFApp1/HelloWorldSt*")).Result;
The name of the parameter where the service name is specified is serviceNameFilter, and the method returns a list. I'm wondering why they would return a list for this overload if the result was always going to be a single-item list. Also, the parameter name "serviceNameFilter" suggests (to me at least) that there's the ability to supply some kind of expression to narrow down your list.
Here's what I've tried already. I've tried the code above, where I chop off a few characters and put an asterisk. I've tried without the asterisk to see if it was a substring match. I've tried SQL-style, with a percent symbol. I've tried a question mark. All of those attempts returned an empty list.
My current workaround is just to ask for all services under that application, and I'll filter them on the client code end with a linq expression. That'll work, but I worry about performance if my list of services gets really big.
Would be nice if I could inspect the source code to answer this myself.
Is there a way to do what I'm trying to do, or am I just misinterpreting what "serviceNameFilter" means, and it just means you have to put the entire service URI that you're looking for?
Thanks for any help you can provide!
Unfortunately that API parameter is terribly named. It's not really a filter at all, it's just the name of the service (since there's no other query that just returns one service, this is how you "filter" from all the services in an application down to just one in particular).
The nearest thing to what you're looking for is EnumerateSubnames. It's not a wildcard search, but you can get all the names that exist "underneath" a given name (for example, all of the service names that exist within an application, or all names with some specific prefix). Depending on the structure of how you create your service names this could work for you.
// System.Fabric.FabricClient.PropertyManagementClient
public Task<NameEnumerationResult> EnumerateSubNamesAsync(Uri name, NameEnumerationResult previousResult, bool recursive)
For example: Presume the following names exist in the cluster:
fabric:/SomeApplication/Zone1/Service1
fabric:/SomeApplication/Zone1/Service2
fabric:/SomeApplication/Zone2/Service1
Note that in this case the application would have been created with the name "fabric:/SomeApplication" and then the services with the detailed names above incorporating the "Zone" segment.
If you now EnumerateSubnames("fabric:/SomeApplication/Zone1", null, true) you'd get back a result that gave you the full names that matched (1 & 2 above).
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 am trying to write 2 Rest GET methods.
Get user by Id
Get user by userName.
I need to know if there is any resource naming convention for this. Both my id and username are strings.
I came up with:
/api/{v}/users/{userid}
/api/{v}/users/username/{username}
However, 2) doesn't seem correct and if I change 2) to /api/{v}/users/{username}, I am mapping to 1) as both id and username are strings. Or is it considered acceptable to use /api/{v}/userbyName/{username}?
How should I name my resource route in case 2) ?
First of all: https://vimeo.com/17785736 (15 minutes which will solve all your questions)
And what is unique? Is the username unique or only the id or both are unique?
There is a simple rule for all that:
/collection/item
However, 2) doesn't seem correct and if I change 2) to /api/{v}/users/{username}, I am mapping to 1) as both id and username are strings.
If your item can be identified with an id and also with an unique username - it doesn't matter if it's the username or the id - simply look for both (of course your backend needs to handle that) and retrieve it.
According to your needs this would be correct:
/api/{v}/users/{userid}
/api/{v}/users/{username}
but I would choose only to use: /api/{v}/users/{userid} and filter by username only with a query parameter (description for that down there below)
Also will I break any rules if I come up with
/api/{v}/userbyName/{username}
Yes - /api/{v}/userbyName/{username} will break the rule about /collection/item because userByName is clearly not a collection it would be a function - but with a real restful thinking api there is no function in the path.
Another way to get the user by name would be using a filter/query paramter - so the ID will be available for the PathParameter and the username only as filter. which than would look like this:
/api/{v}/users/?username={username}
This also don't break any rules - because the query parameter simply filters the whole collection and retrieves only the one where username = username.
How should I name my resource route in case 2) ?
Your 2) will break a rule - so I can't/won't suggest you a way to do it like this.
Have a look at this: https://vimeo.com/17785736 this simple presentation will help you a lot about understanding rest.
Why would you go this way?
Ever had a look at a javascript framework like - let's say ember. (Ember Rest-Adapter). If you follow the idea described up there and maybe also have a look at the json format used by ember and their rest adapter - you can make your frontend developer speed up their process and save a lot of money + time.
By REST you send back links, which can contain URI templates. For example: /api/{v}/users/{userid} in your case, where v and userid are template variables. Since the URI structure does not matter from a client perspective you can use whatever structure you want. Ofc. it is more convenient to use nice and short URIs, because it is easier to write the routing with them.
According to the URI standard the path contains the hierarchical while the query contains the non-hierarchical part of the URI, but this is just a loose constraint, in practice ppl use both one.
/api/{v}/users/name/{username}
/api/{v}/users/name:{username}
/api/{v}/users?name="{username}"
Ofc. you can use a custom convention, for example I use the following:
I don't use plural resource name by collections
I end collection path with slash
I use slash by reducing a collection to sub-collections or individual items
I don't use slash to give the value of a variable in the path, I use colon instead
I use as few variables and as short URI as I can
I use query by reducing a collection to sub-collections especially by defining complex filters with logical operators
So in you case my solution would be
/api/{v}/user/
/api/{v}/user/name:{username}
/api/{v}/user/{userid}
and
/api/{v}/user/?firstName="John"
/api/{v}/user/?firstName="John|Susan"&birthYear="1980-2005"
or
/api/{v}/user/firstName:John/
/api/{v}/user/firstName:John|Susan/birthYear:1980-2005/
etc...
But that's just my own set of constraints.
Each resource should have a unique URI.
GET /users/7
{
"id": 7,
"username": "jsmith",
"country": "USA"
}
Finding the user(s) that satisfy a certain predicate should be done with query parameters.
GET /users?username=jsmith
[
"/users/7"
]