I'm using ServiceStack ServiceClient to write an API wrapper. The API returns HTTP 206 if the number of entities to be returned is too great. Is there a a good way to handle this with ServiceClient, for example for an API endpont that's wrapped like this:
var result = client.Get<IEnumerable<TResource>>("path");
Is this a ServiceStack service that's returning a HTTP 206? as this isn't behavior that's in-built into ServiceStack. If you are using a ServiceStack you may need to increase your IIS/ASP.NET Request limits to allow larger responses.
Otherwise if you're talking to a 3rd Party API, you shouldn't use ServiceStack's Service Clients which are opinionated towards consuming ServiceStack services. You should instead use something like the HTTP Utils built into ServiceStack which would allow you to specify custom HTTP Headers if your service supports it, you can ask for a Partial Content-Range by specifying it in a HTTP Request Filter, e.g:
var json = "http://example.org/users".GetJsonFromUrl(
requestFilter: httpReq => httpReq.AddRange(0, 1000));
Related
I'm evaluating ServiceStack JsonServiceClient and the requests use a generic /json/reply endpoint:
https://techstacks.io/json/reply/GetTechnology?slug=ServiceStack
Is it possible to use the endpoints declared in the services (e.g.: [Route("/hello")])?
The .NET (C#,F#,VB.NET) JsonServiceClient does use the user defined routes as they’re able to access the .NET metadata attributes, other languages can’t as they are unable the access the same runtime metadata so they’re typically emitted in comments for documentation purposes and use ServiceStack’s pre-defined routes which is enabled by default on all ServiceStack Services which allows for a simpler generic implementation that can invoke any API.
All JsonServiceClient in all languages also offer API methods which accept a string path which can be used to call APIs using your user-defined routes, e.g:
client.get<GetTechnologyResponse>("/technology/ServiceStack")
client.get<GetTechnologyResponse>("https://techstacks.io/technology/Redis")
// https://techstacks.io/technology?Slug=ServiceStack
client.get<GetTechnologyResponse>("/technology", { Slug: "ServiceStack" })
as well as POST Request DTOs to Custom URLs:
client.postToUrl("/custom-path", request, { Slug: "ServiceStack" });
client.putToUrl("http://example.org/custom-path", request);
JS lib also contain some additional APIs which can help generate populated query strings for user defined routes, e.g:
combinePaths("path","to","..","join") //= path/join
createPath("path/{foo}", {foo:1,bar:2}) //= path/1
createUrl("http://host/path/{foo}",{foo:1,bar:2}) //= http://host/path/1?bar=2
It might sound like a repeated question at first, but I've gone through all the blogs/ tutorials/ videos I found but none of them actually says how you run that request. Example: for a RESTful request, you code in NodeJs, hit the route(https://localhost/3000/api/getStudent) and get the response. In code you use router.post('/getStudent', async (req,res) => {
// Check response here or manipulate
})
But in soap after coding all the functions like in here-
https://medium.com/metrosystemsro/with-node-js-wrap-backend-soap-webservices-in-a-restful-api-a96887575046
https://dafabulousteach.wpcomstaging.com/2016/05/19/making-a-soap-call-with-node/
https://betterprogramming.pub/how-to-perform-soap-requests-with-node-js-4a9627070eb6
Where do I call the the function and how do I pass parameters and test it? And how do I check the response?
To place this in the context of what you are asking about, a SOAP service is just a server listening on an address for POST requests that have an XML payload. That's it.
So if your SOAP web service address is http://example.com/service_endpoint then you can call the web service by making a POST HTTP request at this address and sending it a SOAP XML message as payload.
Obviously, the XML message in the request must match something that the service expects and you know how to build that XML either by reading documentation or by using the WSDL of the SOAP web service.
So if you know how to make a POST HTTP request to a REST service address and send it a XML payload (although most commonly for REST you use JSON), you already know how to call a SOAP web service.
Now, for convenience, because SOAP is a protocol, the way you call the service and what it expects as XML payload is described by the WSDL, and you can use tools that read the WSDL and create a client API that you can invoke like any other method in your code. The tools handle the details of the HTTP POST request for you, and also the marshalling of any parameters to XML. This is probably what you found confusing.
So let's take an example.
If you have, say, a service that has an operation named savePerson which accepts firstName and lastName as parameters and is described in the WSDL, then your tooling might generate a client that has such a method and accepts a Person object and you can call it like:
var response = client.savePerson({ "firstName": "Kim", "lastName": "Seokjin" });
or some variation of this. You then get a response that you can read just like any other object. You might get a promise instead, or an event, or whatever way the client chooses for how to work. When you use this code, what happens is that the client performs a HTTP POST request behind the scenes for you and marshals the person object to XML, something like this:
POST /service_endpoint
Host: http://example.com
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<savePerson>
<person>
<firstName>Kim</firstName>
<lastName>Seokjin</lastName>
</person>
</savePerson>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
You can obviously send this request yourself with whatever HTTP library you prefer if you don't want to generate a client from the WSDL. But people prefer to use a generated client instead of dealing with these details directly (i.e. making HTTP requests, parsing XML, etc).
At my company we're using graphql for production apps, but only for private ressources.
For now our public APIs are REST APIs with a Cloudfront service for cache. We want to transform them as GraphQL APIs, but the question is : how to handle cache properly with GraphQL ?
We thought using a GET graphql endpoint, and cache on querystring but we are a bit affraid of the size of the URL requested (as we support IE9+ and sell to schools with sometime really dummy proxy and firewalls)
So we would like to use POST graphQL endpoint but...cloudfront cannot cache a request based on its body
Anyone has an idea / best practice to share ?
Thanks
The two best options today are:
Use a specialized caching solution, like FastQL.io
Use persisted queries with GET, where some queries are saved on your server and accessed by name via GET
*Full disclosure: I started FastQL after running into these issues without a good solution.
I am not sure if it has a specific name, but I've seen a pattern in the wild where the graphQL queries themselves are hosted on the backend with a specific id.
It's much less flexible as it required pre-defined queries baked in.
The client would just send arguments/params and ID of said pre-defined query to use and that would be your cache key. Similar to how HTTP caching would work with an authenticated request to /my-profile with CloudFront serving different responses based on auth token in headers.
How the client sends it depends on your backends implementation of graphQL.
You could either pass it as a white listed header or query string.
So if the backend has defined a query that looks like
(Using pseudo code)
const MyQuery = gql`
query HeroNameAndFriends($episode: int) {
hero(episode: $episode) {
name
friends {
name
}
}
}
`
Then your request would be to something like api.app.com/graphQL/MyQuery?episode=3.
That being said, have you actually measured that your queries wouldn't fit in a GET request? I'd say go with GET requests if CDN Caching is what you need and use the approach mentioned above for the requests that don't fit the limits.
Edit: Seems it has a name: Automatic Persisted Queries. https://www.apollographql.com/docs/apollo-server/performance/apq/
Another alternative to remain with POST requests is to use Lambda#Edge on your CloudFront and by using DynamoDB tables to store your caches similar to how CloudFlare workers do it.
async function handleRequest(event) {
let cache = caches.default
let response = await cache.match(event.request)
if (!response){
response = await fetch(event.request)
if (response.ok) {
event.waitUntil(cache.put(event.request, response.clone()))
}
}
return response
}
Some reading material on that
https://aws.amazon.com/blogs/networking-and-content-delivery/lambdaedge-design-best-practices/
https://aws.amazon.com/blogs/networking-and-content-delivery/leveraging-external-data-in-lambdaedge/
An option I've explored on paper but not yet implemented is to use Lambda#Edge in request trigger mode to transform a client POST to a GET, which can then result in a cache hit.
This way clients can still use POST to send GQL requests, and you're working with a small number of controlled services within AWS when trying to work out the max URL length for the converted GET request (and these limits are generally quite high).
There will still be a length limit, but once you have 16kB+ GQL requests, it's probably time to take the other suggestion of using predefined queries on server and just reference them by name.
It does have the disadvantage that request trigger Lambdas run on every request, even a cache hit, so will generate some cost, although the lambda itself should be very fast/simple.
I am returning HttpResult from one of the rest service methods using servicestack's new API. Is there a way to get the HttpResult using the JsonServiceClient?
For ex: JSonServiceClient.Send<HttpResult>("DELETE","person", new { PersonID = 30 });
I want to inspect the header information from the httpresult.
Thanks.
There's no such thing as a HttpResult client response from a ServiceStack web service.
You use a HttpResult to customize the HTTP Response that's returned from your service, e.g. Add additional HTTP Headers. But the response body the client sees is still only the Response DTO (if any).
Use fiddler, wireshark, chome web inspector (if this is an Ajax call) or something like ServiceStack's Request Logger plugin to inspect the HTTP traffic.
Invalid use of ServiceStack's REST Clients
Also consider using the appropriate Clients REST API like client.Delete(), client.Get() etc instead of overloading the T.Send() method (which is usually a POST).
Use Typed DTOs in the ServiceClient instead of anonymous types which are not supported.
Inspecting HTTP Headers using the ServiceStack Service Clients
ServiceStack's Service Clients provide Local and Global WebResponse (and Request) filters that you can use to introspect the WebClient's HttpWebResponse returned for that request, e.g:
client.ResponseFilter = httpRes => {
httpRes.Headers.. //do something with returned headers
};
client.Delete(new Person { Id = 30, ...});
Has anyone had success getting servicestack to work with HttpRequestMessage and HttpResponseMessage?
What is the minimum implementation of IHttpRequest and IHttpResponse that servicestack needs in order to properly handle an http request?
IHttpRequest and IHttpResponse are just normalized lightweight interface wrappers around ASP.NET and HttpListener's server HTTP Request/Response objects. It's purpose is to provide a generic, testable API you can bind against so your services can work in both ASP.NET and HttpListener hosts. They have no connection with HttpRequestMessage / HttpResponseMessage.
Not sure what you're trying to achieve, but you can return a IHttpResult or its de-facto implementation HttpResult to customize the HTTP Headers and body output of your services response.