Anyone know a way that you can provide some sample data to show on the metadata page in ServiceStack for your response models?
For this response model
public class GetIncidentResponse
{
public IEnumerable<Incident> Incidents { get; set; }
}
I'm getting this on the metadata page
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: length
{}
When I'd like to be able to display something like
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: length
{ "Filter example 1", "Filter example 2"}
#mythz comment fixed my problem. Changing the IEnemerable interfaces to IList worked.
Related
Using Micronaut Security, I would like the application to respond to a unauthorized request with a WWW-Authenticate header field for basic authentication, like this:
WWW-Authenticate: Basic realm="User Visible Realm"
Is it possible to do this inside the configuration file (ie. application.yaml)?
If not, how would you recommend doing this with minimum boilerplate?
My current security configuration:
security:
intercept-url-map:
- pattern: /**/*
access:
- isAuthenticated()
redirect:
forbidden:
enabled: false
unauthorized:
enabled: false
Thanks!
I don't know that this is possible via configuration.
One way to achieve this is a server filter. The code below is groovy.
#Filter("/**")
class AuthenticateHeaderFilter extends OncePerRequestHttpServerFilter {
#Override
protected Publisher<MutableHttpResponse<?>> doFilterOnce(HttpRequest<?> request, ServerFilterChain chain) {
return Publishers.map(chain.proceed(request)) { response ->
if (response.status() == HttpStatus.UNAUTHORIZED) {
response.header(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"my realm\"")
}
return response
}
}
#Override
int getOrder() {
return Integer.MIN_VALUE
}
}
I'm using the Google OAuth 2.0 Playground and attempting to send an email. The autentication is working fine. Here is the very simple message I'm trying to send (email address changed to prevent spam):
to: 'Michael To' <FakeMichael#gmail.com>
from: 'John From' <JohnF#mydomain.com>
subject: 'Test Message'
htmlBody: '<b>HI!</b><br>Test Message'
I convert that to Base64 RFC 822 using VBA which gets me this (I've tried swapping the "+" and the "-" per other StackOverflow posts but to no avail):
dG86ICdNaWNoYWVsIFRvJyA8RmFrZU1pY2hhZWxAZ21haWwuY29tPg1mcm9tOiAnSm9obiBGcm9tJyA8Sm9obkZAbXlkb21haW4uY29tPg1zdWJqZWN0OiAnVGVzdCBNZXNzYWdlJw1odG1sQm9keTogJzxiPkhJITwvYj48YnI-VGVzdCBNZXNzYWdlJw==
In the Playground my method is POST and I've added 2 headers:
raw: and the Base64 string above (no quotes or anything)
Content-Type: message/rfc822 <I added this because I kept getting an a different error. Putting this prevetned that error>
Request URI (removed the https cause SO won't let me post more than 2 links)://www.googleapis.com/upload/gmail/v1/users/me/messages/send
I click "send the request" and get an OK response:
Here is my request:
POST /upload/gmail/v1/users/me/messages/send HTTP/1.1
Host: www.googleapis.com
Raw: <string above>
Content-length: 0
Content-type: message/rfc822
Authorization: Bearer <my token>
Response:
HTTP/1.1 200 OK
Alternate-protocol: 443:quic,p=1
Content-length: 91
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Vary: Origin, X-Origin
Server: UploadServer ("Built on Jun 6 2015 11:14:45 (1433614485)")
Etag: "YAnoF_dHYOakPARISZQhTvRsqto/nwevNUuzaUU_lB19L-UhrwaaUSM"
Pragma: no-cache
Cache-control: no-cache, no-store, max-age=0, must-revalidate
Date: Wed, 10 Jun 2015 15:59:36 GMT
Content-type: application/json; charset=UTF-8
{
"labelIds": [
"SENT"
],
"id": "14dde32bc92c9XYZ",
"threadId": "14dde32bc92c9XYZ"
}
However, when I go to my Gmail sent mail folder, the message is there but nothing is in the To, Subject, or Body is field: See Screenshot
I have to imagine this is something simple, but as I'm new to the Google Gmail API, MIME, and dealing with Raw Base64 stuff, I'm not having much luck.
Thanks in advance for any assistance.
--- EDIT PER THOLLE'S Response ---
That helps! I removed the raw base64 string header and put:
From: 'John From' <JohnF#mydomain.com>
Subject: Test Message
To: 'Michael To' <FakeMichael#gmail.com>
Test Message
into the "Enter request body" and it sends, which is great!
Three Follow up questions:
Are there any security risks or limitations (max length? I see there might be a 2mb limitation but that would be a lot of text.) sending it this way (in the body) opposed to a raw Base64 string in the header?
(I'll dig more on this) How do I make the message body HTML? Does the content type of "Content-Type: message/rfc822" prevent me from being able to send it HTML? Sending it HTML is a requirement for this application and I can't have two content types, is there an HTML parameter I can use or am I out of luck?
(I'll do homework on this as well) How do I include an attachment, say a PDF file, with the email?
Thanks again!
I think you are violating a few minor details of the RFC 822 standard:
It is recommended
that, if present, headers be sent in the order "Return-
Path", "Received", "Date", "From", "Subject", "Sender",
"To", "cc", etc.
I can't find it for the life of me, but I also think that the headers has to have their first character capitalized. Try this:
From: John From <JohnF#mydomain.com>
Subject: Test Subject
To: Michael To <FakeMichael#gmail.com>
Test Message
You also don't want to send the base64-encoded mail if you choose message/rfc822 as your Content-Type. Just supply the example mail above as is.
POST /upload/gmail/v1/users/me/messages/send HTTP/1.1
Host: www.googleapis.com
Content-length: 108
Content-type: message/rfc822
Authorization: Bearer {YOUR_ACCESS_TOKEN}
From: John From <JohnF#mydomain.com>
Subject: Test Subject
To: Michael To <FakeMichael#gmail.com>
Test Message
If you want HTML, just modify your message to this:
From: John From <JohnF#mydomain.com>
Subject: Test Subject
To: Michael To <FakeMichael#gmail.com>
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
<b>Test Message</b>
I am uploading an image to documentDb. I assign filename to slug property. I retrieve the attachement using media link obtained during upload.
My expectation is that when I retrieve attachment I would get my filename back. But in contrary Azure returned slug as null. I have double checked content of the retrieved attachement is correct.
Two questions:
Am I misusing slug property?
Where should I assign custom properties?
Here is my Code:
public async Task<string> UploadAttachment(string selfLinkId, Stream mediaStream, string contentType, string fileName)
{
Document foundDocument = (await _client.ReadDocumentAsync(selfLinkId)).Resource;
ResourceResponse<Attachment> resp = await _client.CreateAttachmentAsync(foundDocument.AttachmentsLink, mediaStream, new MediaOptions { ContentType = contentType, Slug = fileName, });
string mediaLink = resp.Resource.MediaLink;
return mediaLink;
}
public async Task<MediaResponse> GetAttachment(string mediaLink)
{
//Use DocumentClient to read the Media content
MediaResponse content = await _client.ReadMediaAsync(mediaLink);
return content;
}
Are you sure the content type is being set correctly?
As per this documentation, slug and contentype are needed only when uploading raw media, which is your scenario. Also, have you checked the Documents Explorer in the azure portal to see how the document and its attachments are stored? Are the values shown there the ones you are expecting?
As per the same documentation, this is an example of how a POST of raw media should look like:
POST https://contosomarketing.documents.azure.com/dbs/hUwBcw==/colls/hUwBc+gfDX4=/docs/hUwBc+gfDX4DAAAAAAAAAA==/attachments HTTP/1.1
x-ms-date: Thu, 14 Aug 2014 22:40:25 GMT
authorization: type%3dmaster%26ver%3d1.0%26sig%3dza46lCo9nNr0%2fGMjryG8S%2b26ZsFABUYPlW3ebq26nDg%3d
x-ms-version: 2014-08-21
Content-Type: image/png
Slug: brush.png
Content-Length: 244
I have the following Request DTO:
[Route("/processresults")]
public class FindProcessResults : QueryBase<ProcessResult, ProcessResultDto> {}
ProcessResult has a property named Id (Int32). I have two ProcessResults in my database, Id 1 and 2.
When I perform a GET to /processresults?Id=1 I get a single ProcessResult returned. Great.
However when I POST this JSON I get two ProcessResults returned. The query is not executing. When I add the property Id to FindProcessResults the JSON call does work, however I have not set EnableUntypedQueries to false.
PostData: {"Id":"1"}
What could be the issue here?
Bonus points, if I make a POST with Form Data I get the following exception:
{
ResponseStatus: {
ErrorCode: "RequestBindingException",
Message: "Unable to bind request",
StackTrace: " at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq, IRestPath restPath)\ \ at ServiceStack.Host.RestHandler.ProcessRequestAsync(IRequest httpReq, IResponse httpRes, String operationName)"
}
}
However if I do the same (a post) with x-www-form-urlencoded the query works as intended (returns a single result).
Conclusion: Whilst I can resolve this issue by adding the parameter I wish to query by (Id) to the typed request, this defeats the purpose of what I am trying to achieve, a generic query mechanism for my data store. The functionality already exists for the GET version of the request.
I believe it is to do with the implementation of AutoQueryServiceBase:
public virtual object Exec<From>(IQuery<From> dto)
{
SqlExpression<From> q;
using (Profiler.Current.Step("AutoQuery.CreateQuery"))
{
q = AutoQuery.CreateQuery(dto, Request.GetRequestParams());
}
using (Profiler.Current.Step("AutoQuery.Execute"))
{
return AutoQuery.Execute(dto, q);
}
}
This is using Request.GetRequestParams() which will return parameters from the Query String or the Form Parameters, whilst a JSON request is attempting to be deserialized into <From> dto. The From type FindProcessResults has no Id property and so it is not populated and passed to the Query.
Requested HTTP Request/Response:
Request
POST /processresults HTTP/1.1
Host: localocl
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 36d4b37e-0407-a9b3-f2f2-5b024d7faf7f
{"Id":1}
Response
Cache-Control → private
Content-Length → 1580
Content-Type → application/json; charset=utf-8
Date → Mon, 03 Nov 2014 21:20:43 GMT
Server → Microsoft-IIS/8.5
Vary → Accept
X-AspNet-Version → 4.0.30319
X-Powered-By → ServiceStack/4.033 Win32NT/.NET, ASP.NET
{"Offset":0,"Total":2,"Results"....
You should strongly consider using GET requests for consuming AutoQuery services which is more appropriate HTTP Verb to use, that's also more cacheable and introspectable.
If you want to POST and you don't want to use a HTML Form POST (i.e. x-www-form-urlencoded Content-Type) you will need to formalize the parameters by adding them to the Request DTO:
[Route("/processresults")]
public class FindProcessResults : QueryBase<ProcessResult, ProcessResultDto>
{
public int Id { get; set; }
}
Otherwise it will try to deserialize the JSON into an empty DTO where any non-existing properties are ignored.
I am implementing a RESTful service which will be consumed by a Dojo framewwork's RestStore, which will permit binding the service to various widgets like an interactive grid or a type-ahead ajax select.
The RestStore wants to send and receive the HTTP Range and Content-Range headers in order to restrict the results of the queries to particular subrange.
What is the best practice pattern in ServiceStack (new API) for reacting to HTTP headers as part of the service? Normally, the service method like Get doesn't have access to the HTTP headers, unless I have missed an alternate API.
The current way that I see is to implement an attribute like
public class RangeSupporter : Attribute, IHasRequestFilter, IHasResponseFilter
which will parse the headers on request, and write the headers on response. The DTO would then be marked for this filter.
The filter would transfer the values, say 'First' and 'Last' in and out of the DTO. However, to know that the DTO even has such attributes, it would have to have some marker interface like
interface IHasRangeSupport {
int First { set; get; }
int Last { set; get; }
int Total { set; get; }
}
so that the filter can transfer the information into and out of the DTO the with code similar to:
var r = request as IHasRangeSupport;
if (r != null) {
/// Access the DTO attributes for the range parameters
}
This seems like a lot of ceremony, and a very awkward implementation.
Is there a better pattern for accessing the HTTP headers when implementing a REST service?
In my particular use case, supporting non-REST endpoints (like SOAP) are not required. Only the HTTP end-point is important.
What is the best practice pattern in ServiceStack (new API) for reacting to HTTP headers as part of the service?
I believe you can get the headers in your service class...
public class FooService : Service
{
public object Get(Foo reqeust)
{
//get header
var h1 = base.RequestContext.GetHeader("headerName");
//get header differently
var h2 = base.Request.Headers.Get("headerName");
}
}