Request body not showing in Nest.js + Swagger - swagger

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.

Related

How to handle API callbacks in ASP.NET MVC (Helloworks API in my case)

As per their documentation from link https://docs.helloworks.com/v3/reference#callbacks
"With the HelloWorks API you can use callbacks to be notified about certain events. Currently we support a callback to be registered when a step is started, the cancellation of a workflow, and the completion of a workflow.
The callback URL will be called according to the following:
curl -X POST https://your.domain.com/some/path
-H "X-HelloWorks-Signature: {signature}"
-H "Content-Type: application/json"
-d "{payload}
I am not able to figure out how can I handle the callback in ASP.NET MVC 4.0. The callback returns data on JSON format. Once I receive the data, I can format it as per my need and can save to database. But how can I get the data in my controller? Guidance from experts on APIs are highly appreciated. Thanks in advance.
I am not able to figure out how can I handle the callback in ASP.NET MVC 4.0.
You need to have an api controller that accepts POST requests. That api endpoint is then called by the HelloWorks api. The fancy word to describe this mechanism is a Webhook. A nice introduction can be found here.
The very basic would be a controller like
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace MyWebAPI.Controllers
{
public class WebHookController : ApiController
{
// POST: api/webhook
public void Post([FromBody]string value)
{
}
}
}
You will need to register the url https://yourwebsite.domain/api/webhook at the HelloWorks api so it knows where to send the data to.
You probably want to secure this endpoint so others cannot abuse this api. See the docs for some guidance.
For example, in your case you should check that a header named "X-HelloWorks-Signature" is send in the request to the endpoint. The value of that header is a hash that should match the value of a hash of the content you received. To calculate the hash code to match create a hash using the SHA-256 algorithm and base16-encode the result.
There is also documentation from Microsoft on how to create web apis
Peter your guidance worked. I appreciate that. It was straight forward, only the technical jargon are making it intimidating :). Below are the code that worked. I am still to secure it using signature.
[HttpPost]
public ActionResult Callback()
{
string rawBody = GetDocumentContents(Request);
dynamic eventObj = JsonConvert.DeserializeObject(rawBody);
Test newTest = new Test();
newTest.Response = "Bikram-1" + (string)eventObj.type;
var test = db.Tests.Add(newTest);
db.SaveChanges();
return Content("Success!");
}
private string GetDocumentContents(HttpRequestBase Request)
{
string documentContents;
using (Stream receiveStream = Request.InputStream)
{
using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
{
documentContents = readStream.ReadToEnd();
}
}
return documentContents;
}

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.

How will Swagger 2.0 handle generics in parameters or return types?

I am using Swagger 2.0 for documentation generation. In my controller class, I have some operations like:
public Page<Employee> getEmployees(Pageable pageable) {....}
Swagger document generated for response of the operation above:
"responses" : {
"200" : {
"schema" : {
"$ref" : "#/definitions/Page"
}
}
}
Here, Swagger documentation failed to say that response is Page<Employee>. How do I get generics data in documentation in Swagger?
And what if I have the following return types?
Page<String,Employee>
Page<Employee,List<Department>>
Page<Employee,Tuple.Two<String,User>>
Same is true for Swagger Operation parameters and Model properties.
This is a known issue with Swagger, please check the following issue: https://github.com/OAI/OpenAPI-Specification/issues/957. Point being, you'll need to create your own extensions to describe generics.

Using the Json.NET serializer in an MVC4 project

I'm starting to learn Json.NET, but I'm having trouble using its serializer. I have a new MVC4 project with a Web.API service:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
// GET /api/PTE_Tests/5
public HttpResponseMessage<string> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage<string>(JsonConvert.SerializeObject(test));
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
JsonConvert.SerializeObject() works as expected and returns a string. My Web.API controller returns that as part of an HttpResponseMessage. The end result, when viewed in Fiddler, is not JSON data, but JSON data being serialized again (I think):
"{\"ID\":1,\"Name\":\"Talar Tilt\",\"TagID\":1,\"PracticeID\":1,
\"SpecificAreaID\":1,\"TypeID\":1,\"VideoID\":1,\"PicID\":1}"
Does someone know how to turn off the default serializer so I can use Json.NET directly? By the way, I'm not using the default serializer because I can't figure out how to make it work with complex objects (PTE_Test will eventually contain members of type List).
Alternately, it will also solve my problem if someone can explain how to use the default serializer with complex objects. MSDN's explanation didn't help me.
Rick Strahl has a blog on that here with a code that works.
As others have pointed out, you need to create a formatter and replace the DataContractSerializer with the JSON.NET serializer. Although, if you're not in a rush for JSON.NET specifically, rumor has it that next beta/rc is going to have support for JSON.NET built in.
Conceptually, however, you're missing part of the magic of WebAPI. With WebAPI you return your object in it's native state (or IQueryable if you want OData support). After your function call finishes the Formatter's take over and convert it into the proper shape based on the client request.
So in your original code, you converted PTE_Test into a JSON string and returned it, at which point the JSON Formatter kicked in and serialized the string. I modified your code as follows:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
public HttpResponseMessage<PTE_Test> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage(test);
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
Notice how your function returns PTE_Test instead of string. Assuming the request came in with a request header of Accept = application/json then the JSON formatter will be invoked. If the request had a header of : Accept = text/xml the XML formatter is invoked.
There's a decent article on the topic here. If you're a visual learner, Scott Gu shows some examples using fiddler in this video, starting around 37 minutes. Pedro Reys digs a little deeper into content negotiation here.
The way to do this is to use formatters.
Check out: https://github.com/WebApiContrib/WebAPIContrib/tree/master/src/WebApiContrib.Formatting.JsonNet.
Json.NET support will be in the RC release of Web API.

Resources