So I have a simple HttpServer like this:
import 'dart:io';
main() {
HttpServer
.bind("127.0.0.1", 80)
.then((server) {
server.listen((request) {
// Add cookie here how?
request.response.write("Howdy Darty cowboy!");
request.response.close();
});
});
}
Is there a way to add cookies to the HttpResponse in Dart?
I can see both HttpResponse and HttpRequest classes have cookies properties and I can access them, but I can't seem to figure out how to add a cookie.
Tried this:
request.response.cookies = ["name", "value"];
But got this error:
Error: The setter 'cookies' isn't defined for the class 'HttpResponse'.
So there are no predefined methods to work with cookies?
Do I have to add my own HTTP Headers to add cookies?
Again, I can see headers properties in both classes, but no setters or getters!
Just started playing around with Dart.
Note: Please don't link me external packages, I would like to do it with Dart's core libraries. Don't want to get into another npm hell! Moved away from Node.js cause of npm, but looks like pub is identical, just uses yaml.
request.response.cookies is a List<Cookie>, so you'll want to add to it (rather than assign it with equals).
Try:
request.response.cookies.add(Cookie('name', 'value'));
Related
I'm rather new to Blazor, but I am currently trying to get access to some classes from within a class library that I've created and deployed as a Nuget package. As background, the Nuget package is an Api library, which allows me to talk to a webservice (I don't know if this is relevant or not). However, every time I go to the page where I'm testing, the page never loads and instead I left looking at the browser loading circle until I navigate away or close the application. During my testing here, it seems like it's the #inject call of my interface into the Blazor component which is causing the issue as when I remove it and try to load the page normally, the page does so.
So to demonstrate what I have setup, here is where I've added the Singletons to the DI:
builder.Services.AddSingleton<IApiConfigHelper, ApiConfigHelper>();
builder.Services.AddSingleton<IApiHelper, ApiHelper>();
builder.Services.AddSingleton<ISystemEndpoint, SystemEndpoint>();
Then on the blazor page, I have the following declarations at the top of my page:
#using Library.Endpoints
#using Library.Models
#page "/"
#inject ISystemEndpoint _systemEndpoint
Now I am leaning towards is this something to do with the Nuget package and using it with DI. I have tested the library away from this project (In a console application) and can confirm it's working as it should.
I have also created a local class library as a test to, to see if I could inject a data access class into the page and I can confirm that this works without an issue, which suggests to me that DI is working, just not with my Nuget package.
I did have a look into CORS, given that the Nuget package is accessing an external domain, and setup the following simple CORS policy in the app:
builder.Services.AddCors(policy =>
{
policy.AddPolicy("OpenCorsPolicy", opt =>
opt.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
});
Which is added to the app after the AddRouting call like so:
app.UseCors("OpenCorsPolicy");
However again, this wasn't the solution so if anyone is able to point me in the right direction with where I may be going wrong with this or offer any advice, I would be most grateful.
EDIT 1 - Provides details #mason queried
Regarding SystemEndpoint, the constructor is being injected with 2 things, as below:
public SystemEndpoint(IApiHelper apiHelper, IOptions<UriConfigModel> uriOptions)
{
_apiHelper = apiHelper;
_uriOptions = uriOptions.Value;
}
My Nuget Library is dependant on the following:
Azure.Identity
Azure.Security.KeyVault.Secrets
Microsoft.AspNet.WebApi.Client
Microsoft.Extensisons.Options.ConfigurationExtensions
EDIT 2 - Doing some further testing with this I have added a simple Endpoint class to my Nuget library, which returns a string with a basic message, as well as returning the values of the 2 UriConfig properties as below. I added this test to 1) sanity check that my DI was working correctly, and 2) check the values that are being assigned from appsettings to my UriConfig Object.
public class TestEndpoint : ITestEndpoint
{
private readonly IOptions<UriConfigModel> _uriConfig;
public TestEndpoint(IOptions<UriConfigModel> uriConfig)
{
_uriConfig = uriConfig;
}
public string TestMethod()
{
return $"You have successfully called the test method\n\n{_uriConfig.Value.Release} / {_uriConfig.Value.Version}";
}
}
However when adding in the dependency of IApiHelper into the Ctor, the method then breaks and fails to load the page. Looking into ApiHeloer, the Ctor has a dependency being injected into it of IApiConfigHelper. Looking at the implementation, the Ctor of ApiConfigHelper is setting up the values and parameters of the HttpClient that should make the REST calls to the external Api.
Now I believe what is breaking the code at this point is a call I'm making to Azure Key Vault, via REST, to pull out the secret values to connect to the Api. The call to KeyVault is being orchestrated via the following method, making use of the Azure.Security.KeyVault.Secrets Nuget Package, however I assume that at the heart of it, it's making a REST call to Azure on my behalf:
private async Task<KeyVaultSecret> GetKeyVaultValue(string secretName = "")
{
try
{
if (_secretClient is not null)
{
var result = await _secretClient.GetSecretAsync(secretName);
return result.Value;
}
}
catch (ArgumentException ae)
{
Console.WriteLine(ae.Message);
}
catch (Azure.RequestFailedException rfe)
{
Console.WriteLine(rfe.Message);
}
return new(secretName, "");
}
So that's where I stand with this at the moment. I still believe it could be down to CORS, as it seems to be falling over when making a call to an external service / domain, but I still can say 100%. As a closing thought, could it be something as simple as when I call call the above method, it's not being awaited????
So after persisting with this it seems like the reason it was failing was down to "awaiting" the call to Azure KeyVault, which was happening indirectly via the constructor of ApiConfigHelper. The resulting method for getting KeyVault value is now:
private KeyVaultSecret GetKeyVaultValue(string secretName = "")
{
try
{
if (_secretClient is not null)
{
var result = _secretClient.GetSecret(secretName);
if (result is not null)
{
return result.Value;
}
}
}
catch (ArgumentException ae)
{
Console.WriteLine(ae.Message);
}
catch (Azure.RequestFailedException rfe)
{
Console.WriteLine(rfe.Message);
}
return new(secretName, "");
}
I am now able to successfully make calls to my library and return values from the Api it interacts with.
I can also confirm that this IS NOT a CORS issue. Once I saw that removing the await was working, I then removed the CORS policy declarations from the service and the app in my Blazor's start-up code and everything continued to work without an issue.
As a final note, I must stress that this is only seems an issue when using the library with Blazor (possibly webApi projects) as I am able to use the library, awaiting the Azure call just fine in a console application.
My controller code is something like this.
#Controller('customer')
export class CustomerController{
constructor(private readonly customerService: CustomerService){}
#Post('lookup')
async someMethod(#Body() body:any){
console.log("BEGIN -- CustomerController.someMethod");
I am expecting to see in Swagger a place where I can input some text as a request body but instead I see this
Add #ApiProperty()
export class User{
#ApiProperty()
name:string
}
So it sounds like there's a few things going on here. The Swagger UI is a helper tool for sending in requests, but to do that it needs to know the shape of the request body. any is not good enough. If you're looking for a tool that allows you to send in anything, curl or postman are you best bets (at least for free).
Nest has a Swagger plugin that will read through your Typescript code and decorate your types and method accordingly, but you have to opt in to enable it. Otherwise, you need to use the decorators from the #nestjs/swagger package to tell Swagger what types are expected in and out of the methods.
So long as the type that corresponds to #Body() has swagger decorators or you enable the swagger plugin and have a valid class, the swagger UI should show up as expected, but with the above and using type any it won't do you any good.
My endpoint accepts unknown key/value data and I was having the same problem (I tried any, unknown, Record<string, any>, object, {}). Finally #Body() data: Map<string, any> worked for me.
try it like this:
#ApiBody({description: "body:any someMethod"})
#Post('lookup')
async someMethod(#Body() body:any){
console.log("BEGIN -- CustomerController.someMethod");
}
I would recommend using dto for body.
Refer to documentation.
Example of a DTO is shown below.
DTO:
import { ApiProperty } from '#nestjs/swagger';
export class CreateCatDto {
#ApiProperty()
name: string;
#ApiProperty()
age: number;
#ApiProperty()
breed: string;
}
Function
#Post()
async create(#Body() createCatDto: CreateCatDto) {
//Do Stuff.
}
#ApiProperty adds properties to swagger request.
It should show something like this:
#Post()
#ApiBody({ type: CreateCatDto })
async create(#Body() createCatDto: CreateCatDto) {
//Do Stuff.
}
The above code is going to give output similar to below where your schema is also going to be documented:
Hope this helps.
Swagger is unable to interpret your code. It is not an issue with your code. If your goal is to test your API for the UI team to use and not a comprehensive swagger documentation, then I found it easiest to just use Postman. Try hitting your API using Postman.
Having moved my mobile app development to Flutter I am now in the process of experimenting with using Dart as my main server side language. The productivity benefits in using a single coding language in both the app and on the server are considerable. To that end I have set up a server with an Nginx front end which proxies all dynamic web requests to an Angel/Dart server.
Angel is a remarkably well written package and I had a working server written up in no time at all. However, in order to have a fully functional backend I need to be able to use both Redis and PostgreSQL from within my server side Dart code. I am using the resp_client package to access Redis. The issue I have run into is with the fact that RespCommand.get is asynchronous. With my newbie knowledge of both Dart and Angel I am unable to find a way to acquire a Redis key value via RespCommand.get in an Angel route handler and then somehow use that value in the response it returns.
My entire Dart backend server code is shown below
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:postgres/postgres.dart';
import 'package:resp_client/resp_client.dart';
import 'package:resp_client/resp_commands.dart';
class DartWeb
{
static Angel angel;
static AngelHttp http;
static RespCommands redis;
static PostgreSQLConnection db;
static init() async
{
angel = Angel();
http = AngelHttp(angel);
angel.get('/',rootRoute);
await prepareRedis();
await http.startServer('localhost',3000);
}
static prepareRedis() async
{
RespServerConnection rsc = await connectSocket('localhost');
RespClient client = RespClient(rsc);
redis = RespCommands(client);
}
static preparePostgres() async
{
db = new PostgreSQLConnection('serverurl',portNo,'database',username:'user',password:'password');
await db.open();
}
static void rootRoute(RequestContext req,ResponseContext res)
{
try
{
await redis.set('test','foobar',expire:Duration(seconds:10));
String testVal = await redis.get('test');
res.write('Done $testVal');
} catch(e) {res.write('++ $e ++');}
}
}
main() async {await DartWeb.init();}
If I start up this server and then access it through my web browser I end up with a 502 Bad Gateway message. Not surprising. dart2native main.dart -o mainCompiled returns the error await can only be used in async... message.
So I tried instead
try
{
res.write('Before');
redis.set('test','foobar',expire:Duration(seconds:10)).then((bool done)
{
res.write('DONE $done');
});
res.write('After');
} catch(e) {res.write('++ $e ++');}
which simply printed out BeforeAfter in my browser with the DONE bit never showing up although a quick test via redis-cli shows that the key test had in fact been created.
My knowledge of both Dart and Angel is still in its infancy so I guess I am doing something incorrectly here. Shorn of all the detail my questions are essentially these -
how do I call and get the result from async methods in an Angel route dispatcher?
given that I am editing my Dart code in VSCode on my local Windows machine which accesses the relevant dart files on my Ubuntu server I loose the benefits of error reporting provided by the VSCode Dart plugin. dart2native, as I have used here, helps out but it would be nicer if I could somehow get a running error report within VSCode as I do when building Flutter apps locally. How can I accomplish this - if at all possible?
It turns out that Dart/Angel does not impose excessively strict constraints on the signature of a route handler. So you can quite safely declare a route handler like this one
static Future<void> rootRoute(RequestContext req,ResponseContext res) async
{
try
{
res.write('!! Before ');
await redis.set('test','foobar',expire:Duration(seconds:10));
String test = await redis.get('test');
res.write('After $test !!');
} catch(e) {res.write('++ $e ++');}
}
With the route simply returning a Future we can now safely do anything we like there - including calling other asynchronous methods: in this instance to fetch a Redis key value.
I am trying to add a grpc protofile to my swagger-ui. I am consuming a grpc webservice which needs a protofile as input. The input to my spring boot restful webservice needs to have that same grpc structure as its interface. I recevied a jar from the individual that made the protofile and imported it to my webserivce. When I try to add the #ResponseBody tag around the object from the protofile jar, my app hangs on this in the console at startup:
s.d.s.w.s.ApiListingReferenceScanner : Scanning for api listing references
Thanks,
Brian
Never return entity objects in controller method.
in my case. my Controller methods takes this parameter.
"#AuthenticationPrincipal UserSession userSession"
when i exlude UserSession object swagger back to normal.
There were 2 way to do that
first is "#ApiIgnore #AuthenticationPrincipal UserSession userSession"
second is in swaggerConfig class
private Class[] clazz = {UserSession.class};
Docket().ignoredParameterTypes(clazz)
Incase someone needs a solution, what I did was as a work around for now.
in my service's code (response is a String)
return JsonFormat.printer().print(myProtoObject);
in my client's code:
Builder b = ProtoObject.newBuilder();
JsonFormat.parser().merge(result.getBody(), b);
ProtoObject protoObject = b.build();
I know Groovy DSL is able to generate a random value.
I have used stub runner server so that I can hit the stubs from the server and get response. however when I refresh the browser I get the same response again. The Groovy DSL is just generating a static stub, and is always returning the same response as I requested.
How can I get a random response without re-generate the stubs in this case?
Also a similar question was asked by someone a year ago, it was written in the answer that it is not possible. Is it still not possible or there is a way now to do it?
You would have to create your own WireMock extension. Check this section of the docs: https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/advanced.html#customization-wiremock
95.5.6 Registering Your Own WireMock Extension WireMock lets you register custom extensions. By default, Spring Cloud Contract
registers the transformer, which lets you reference a request from a
response. If you want to provide your own extensions, you can register
an implementation of the
org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions
interface. Since we use the spring.factories extension approach, you
can create an entry in META-INF/spring.factories file similar to the
following:
org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions=\
org.springframework.cloud.contract.stubrunner.provider.wiremock.TestWireMockExtensions
org.springframework.cloud.contract.spec.ContractConverter=\
org.springframework.cloud.contract.stubrunner.TestCustomYamlContractConverter
The following is an example of a custom extension:
TestWireMockExtensions.groovy.
package org.springframework.cloud.contracthttps://docs.spring.io/spring-cloud-contract/docs/current/reference/html/advanced.html#customization-wiremock.verifier.dsl.wiremock
import com.github.tomakehurst.wiremock.extension.Extension
/** * Extension that registers the default transformer and the custom one */ class TestWireMockExtensions implements WireMockExtensions { #Override List<Extension> extensions() { return [
new DefaultResponseTransformer(),
new CustomExtension() ] } }
class CustomExtension implements Extension {
#Override String getName() { return "foo-transformer" } }
You would have to create an extension that modifies the response and generates a piece of it. That extension needs to be available both on the consumer and the producer sides.