Apigility Error after installation and creation of first service of demo - zend-framework2

i have just installed Apigility and following the tutorials i have an error. When i try with Postman to call my service i get an error like this
Zend\View\Renderer\PhpRenderer::render: Unable to render template "status/v1/rpc/ping/ping/ping"; resolver could not resolve to a file
My call on postman is like this.
http://localhost/demo/api/public/ping
How to solve this problem?

Apigility as part of Zend Framework is now part of the open source Laminas project and is called Laminas API Tools.
Make sure that Zend OPcache is disabled in your PHP configuration before trying to create your API service.
Quick steps to verify:
create a phpconfig.php file that displays php configuration for your development server. Do not put this in production. See for details https://www.php.net/manual/en/function.phpinfo.php
open this file on your server http://localhost:8080/phpconfig.php and look for two things a) ZendOPcache - if it is enabled, then look at b) loaded php.ini something like /etc/php7/cli/php.ini
add opcache.enable=0 to the [opcache] section. Even if it is commented out, it is still loaded, you saw it above right?
restart your PHP server / application to verify that Zend OPcache is off and that's it.

For anyone have this problem, in the example of Apigility change the example code from this:
namespace Status\V1\Rpc\Ping;
use Zend\Mvc\Controller\AbstractActionController;
use ZF\ContentNegotiation\ViewModel;
class PingController extends AbstractActionController
{
public function pingAction()
{
return new ViewModel([
'ack' => time()
]);
}
}
to this
namespace Status\V1\Rpc\Ping;
use Zend\Mvc\Controller\AbstractActionController;
class PingController extends AbstractActionController
{
public function pingAction()
{
return ['ack' => time()];
}
}
Doing this the example is fine.

Related

Async Function Fails when called as part of a Constructor

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.

Slow swagger Scanning - s.d.s.w.s.ApiListingReferenceScanner : Scanning for api listing references

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();

Adding cookies with Dart server?

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'));

How to generate dynamic response from the stubs without re-generating it again?

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.

SpecsFor MVC - Can't get site to build / appear

I am attempting to create some UI tests using SpecsFor MVC, I am coming at this from a new user's point of view in terms of testing so could be easily missing something obvious.
The site I'm testing against already uses it's own test DB so I do not need to create one. when I build and debug normally on this site it also starts up a couple of WCF projects which we use for service layer interactions. Presumably I'll need to start these in the specs config but have not got that far yet.
I've followed the documentation and have created this method:
protected override void AfterConfigurationApplied()
{
var config = new SpecsForMvcConfig();
config.UseIISExpress()
.With(Project.Named("TestSite"))
.UsePort(55555)
.CleanupPublishedFiles()
.UseMSBuildExecutableAt(#"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe");
config.BuildRoutesUsing(MvcApplication.RegisterRoutes);
config.UseBrowser(BrowserDriver.Chrome);
_host = new SpecsForIntegrationHost(config);
_host.Start();
}
The routing of the site is set in the Global.asax hence the setting in the above method.
I also have this very basic test in place to just see if I can get it working:
protected override void When()
{
SUT.NavigateTo<HomeController>(u => u.Index());
SUT.FindLinkTo<HomeController>(u => u.About())
.Click();
}
When I debug the tests it successfully starts Chrome but hangs for ages and eventually fails with this error:
OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://localhost:49924/session/bd15d6a15395b4ca204437c340639501/element timed out after 60 seconds.
I'm not sure where that port number or session etc are coming from.
If I'm running my web project normally (outside of this whole testing project) I see a URL like this:
https://localhost:55555
I would have thought I'd see something similar for these tests cases? It doesn't really matter in any case because they're not working.
Am I missing some element of the config? Do I need to set up the WCF layer to run as well?

Resources