RESTful URL for RPC-like operation - c#

I'm implementing a RESTful API for a DVD rental website using ASP.NET Web API. The domain model (simplified) consists of Customer and Subscription entities. A customer has an associated subscription.
Most of the operations exposed by the API are simple CRUD operations, which are easy enough to model according to RESTful principles. E.g.
GET /api/subscriptions/1 - get subscription with id 1
POST /api/subscriptions - add a new subscription
PUT /api/customers/2 - update customer with id 2 with contents of PUT body
There is a requirement to periodically check for expired subscriptions, by comparing the EndDate field on each Subscription entity read from our database with the current date. For each subscription that has expired, the CustomerStatus field of the associated customer should be set to Archived and an email sent to the customer. The operation will be exposed through our REST API and invoked daily from an external service.
What URL scheme should I use to expose this operation according to RESTful principles? My first thought is that it's a PUT operation on api/customers/{SomeResource} as it potentially involves updating the CustomerStatus field of zero or more customers and is also an idempotent operation.
For example:
PUT /api/customers/expired
Does this sound reasonable?
Note that there is no body sent in this request, as the customers whose statues are being updated are queried from a database rather than being supplied by the end user. My understanding is that a PUT request doesn't have to include a body.

This is almost certainly a POST operation.
However, I question the design of your service. Why does the behaviour you describe need to be externally-controlled by way of a RESTful API? If the exact timing and nature of the operation is known beforehand, why not use some other means of scheduling the job...a means that is more straightforward and wouldn't raise these kinds of questions?
Ref: Stack Overflow
Edit: note that the operation described by the OP is not idempotent and thus not a qualifying PUT operation.
Additional edit: note that the .Net framework uses the POST method by default for service endpoints marked with the WebInvoke attribute. Per the documentation for this attribute, it represents an endpoint that "is logically an invoke operation". To me, this reads like a remote procedure call (i.e. RPC).

Related

REST api - Updating a specific resource with PATCH without including the specific resource ID in the request

I'm developing a REST API for managing company cars, where employees take cars, and go on rides.
Rides have a property called isActive.
When they finish a ride, the isActive property needs to be set to false.
How my API currently works is that the endpoint for finishing (
PATCH HTTP request) the rides is /api/v1/rides.
The user sends the PATCH request with the JWT token, and the API determines from the HTTP context which user it is, finds the individual ride associated with the user, updates the isActive property to false, and updates a short comment of type string that the user inputs.
Is this acceptable?
Every source that I found states that the endpoint should look something like /api/v1/rides/{rideId}, but I don't understand why it would be necessary in this context, because it would require more work on the front-end side.
Is this acceptable?
Probably not
PATCH /api/v1/rides
is a request to change the /api/v1/rides resource; which is to say the same resource that you are asking for when you send a GET /api/v1/rides request. If you are intending to modify some other resource instead, then the resource you intend to modify should be the target URI.
The potential problem is this: general purpose HTTP components think all resources understand requests the same way. This is the REST "self descriptive messages" interface constraint at work. When you advertise that your resource supports PATCH, my third party browser/spider/cache/proxy is allowed to assume that PATCH means the same thing for your resource that it does for every other resource on the web.
When something goes expensively wrong because your resource was using different semantics from what is standard, that's on you, not the client.
PATCH means "apply these changes to the resource identified by the target URI". If you are intending the edits to be applied to some other resource, then you should be specifying that identifier instead.
If you are doing something non-standard, then you should probably use POST, rather than PATCH, as the method token in the request. See Fielding 2009:
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”

Maintaining Operation Id Through a Request in Web API

It is not uncommon in a RESTful setting for the client to sent an operation id (typically a GUID) so that the request logs can be traced.
My question is, in Web API, is there a way native to .NET Web API to track the id per request?
log4net has LogicalContext that could track that. The problem with LogicalContext is that it is specific to log4net and cannot be used with NLog. There is no way in LogicalContext to get the list of all keys. I have to know the key before hand, which cases a problem if one API calls it "operation id" and another API calls it "activity id".
Maybe use the Guid 'Trace.CorrelationManager.ActivityId' for CorrelationId ?
It can be configured per request in your application-class (inherits from System.Web.HttpApplication) using the method Application_BeginRequest.
https://github.com/NLog/NLog/wiki/Trace-Activity-Id-Layout-Renderer

Authentication via headers in WCF REST service

I am new to WCF services and currently testing out things.
I have got a little REST API, which has several methods. Some of them require a user context (session), some others don't. At login, each user gets a session token. The client should supply this token and his user ID on every request via HTTP headers.
At the moment, I wrote a method for getting those two headers and validate the session, calling it on every method which will need a user context. This seems kinda nasty if the API gets bigger.
Is there a better approach for doing this?
You can leverage of following solutions:
Custom class deriving IClientMessageInspector/IDispatchMessageInspector for client and service respectively. Then you add its instance to MessageInspectors. Advantage of having messageInspector is that it's applied to single endpoint so regardless of having many endpoints exposed (both SOAP and REST), messageInspector can be associated only with single one. Whenever message is either received or sent, AfterReceive or BeforeSent method is invoked respectively. There you retrieve headers and if token does not match any expected you can throw an exception. Such a way out provides separation between exposed contract and background checks such as token validation.
Custom class deriving IOperationInvoker. Within custom operation invoker you explicitly call method and thanks to it you can examine headers (OperationContext.Current.IncomingMessage) before any method gets invoced.
I brought up only concepts, extensive information and examples can be looked up on Internet.

WCF REST-service: passing country code

I have a WCF REST-service that is used by a mobile application used in different countries. It's accepting and returning JSON, and I use StructureMap.
The idea is to create one service instance for all countries, but I need to know what country is calling the service and do some logic on that in the service (for example, determine the connection string to be used).
however, I want to avoid that country code has to be passed with each service request. What are my options here?
Can I, for example, have one endpoint for each country? But in that case, how can I know what endpoint/country code was used to call the service?
Maybe other possibilities?
Multiple endpoints could be a solution, but you need a reliant way of determining which endpoint was actually used. Given the "disconnected" nature of WCF REST services (by that I mean the usage of non WCF types to do the communication and just using the WCF attributes), this would require you to write a WebHostFactory that specifies the country on creation of the service for a given endpoint. What you could to is inspect the WebOperationCurrent.Current instance to get access to information hidden from your method signature. For example:
Uri requestRoot = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri;
if (requestRoot.PathAndQuery.Contains("en-us")) {
// use english locale
}
else if (requestRoot.PathAndQuery.Contains("de-de")) {
// use german locale
}
You would need a better strategy to determine the actual country/language, but the basic idea is to re-host the same service under multiple paths and inspect those paths within the request using the current WebOperationContext instance.
Edit
From the comments above, I would like to add that you have access to the UserAgent string for the current request using the WebOperationContext. So you could also inspect those information looking for a clue about the requested language. But keep in mind that those "implicit" information are only clues but never clear indications about what the user wants.

Web Services. Get input data, process it at background thread

I've got several web-services: asmx,wcf. At couple of them there are some methods, which take a lot of time for processing, but size of input data for these methods are small and it takes not much time to transfer on the wire. I want move to not sync model. Client passes data to service, service answers that data transfer was correct and process it at background thread witout connection with client. So agter transfering connection should be closed. IS it possible? Can u help me with articles or may be just google request.
John is right - Once you close an http connection, it is done. You can't get back to the same process.
So if you can use another technology that allows duplex on one connection (e.g. WCF), do it!
However,
if you have no choice but to use webservices,
here are three ways to make it work. You may get timeouts on any of them.
Option 1:
Forget the part about 'client answers data was correct.' Just have each thread make its request and wait for the data.
Option 2:
Now, assuming that won't work and you must do the validation, this way requires the client to make 2 requests.
First request: returns valid/invalid.
Second request: returns the long-running results.
Variation of option 2:
If you have timeout problems, you could have the first request generate a GUID or unique database key and start another process, passing it this key, and return the key to the client. (if you can get the server to allow you to start a process - depends on security settings/needs - if not you may be able to start an async thread and have it keep running after the websvc one ends?) The process will do the long task, update the row in the database w/ the unique id when finished, revealing the results plus a 'done' flag. The second request by the client could always return immediately and if the processing is not done, return that, if it is, return the results. The client will repeat this every 5 sec or so until done.
Hacks, I know, but we don't always have a choice for the technology we use.
Don't do this with ASMX web services. They weren't designed for that. If you must do it with ASMX, then have the ASMX pass the data off to a Windows Service that will do the actual work, in the background.
This is more practical with WCF.
We have been writing stuff to interact with the UK gov website and the way they handle something similar is that you send your request and data to the server and it responds saying, roughly, "thanks very much - we're processing it now, please call back later using this id" - all in an XML message. You then, at some point later, send a new http request to the service saying, essentially, "I'm enquiring about the status of this particular request id" and the server returns a result that says either it has processed OK, or processed with errors, or is still processing, please try again in xx seconds.
Similar to option 2 described previously.
It's a polling solution rather than a callback or 2 way conversation but it seems to work.
The server will need to keep, or have access to, some form of persistent table or log for each request state - it can contain eg, the id, the original request, current stage through the workflow, any error messages so far, the result (if any) etc. And the web service should probably have passed the bulk of the request off to a separate Windows service as already mentioned.

Categories