Skip to content

Commit

Permalink
implement basic error response and metadata. #188
Browse files Browse the repository at this point in the history
  • Loading branch information
shubhendumadhukar committed Nov 21, 2022
1 parent 3f6baf2 commit e789bfe
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 7 deletions.
26 changes: 26 additions & 0 deletions docs/mocking-gRPC.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,32 @@ You can also add delays in your grpc mock services, by adding a delay key with t

You don't need to modify your proto file to accommodate the additional key, since Camouflage will delete the "delay" key from the response before sending it to the client.

## Sending GRPC Error responses

Camouflage provides an experimental support to send error responses starting v0.11.0 onwards, for unary and client side streaming calls. To send an error response, append a json error object with `code` and optional `message` to your mock content.

```json
{
"error": {
"code": 16,
"message": "User is unauthenticted."
}
}
```

## Sending GRPC Error responses

Camouflage provides an experimental support to send metadata/trailers with responses starting v0.11.0 onwards, for unary and client side streaming calls. To send metadata, append a json metadata object with relevant keys and values to your mock content.

```json
{
"metadata": {
"key1": "value1",
"key2": "value2"
}
}
```

!!!caution

Since the Camouflage gRPC server needs to register the new services, everytime you add a new protofile, you'd need to restart the Camouflage server. Good news is, you can do so easily by making a get request to /restart endpoint. Though the downtime is minimal (less than a second, we do not recommend restarting the server during a performance test. Note that restart is required only if you add a new protofile. If you have added a new mock file or updated an existing one, a restart is not required.
Expand Down
10 changes: 9 additions & 1 deletion grpc/mocks/blogPackage/BlogService/createBlog.mock
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
{
"id": {{num_between lower=500 upper=600}},
"title": "something"
"title": "something",
"error": {
"code": 16,
"message": "User is unauthenticated."
},
"metadata": {
"key1": "value1",
"key2": "value2"
}
}
33 changes: 27 additions & 6 deletions src/parser/GrpcParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getHandlebars } from '../handlebar'
import { getLoaderInstance } from "../ConfigLoader";
import { CamouflageConfig } from "../ConfigLoader/LoaderInterface";
const Handlebars = getHandlebars()
import * as grpc from "@grpc/grpc-js";
/**
* Parser class for GRPC Protocol mocks to define handlers for:
* - Unary calls
Expand Down Expand Up @@ -42,16 +43,26 @@ export default class GrpcParser {
const response = JSON.parse(fileContent);
const delay: number = response.delay || 0;
delete response.delay;
const error = response.error || null
delete response.error;
const metadata = response.metadata || null;
delete response.metadata;
const trailers = new grpc.Metadata();
if (metadata) {
for (const key in metadata) {
trailers.add(key, metadata[key])
}
}
setTimeout(() => {
callback(null, response);
callback(error, response, trailers);
}, delay);
} else {
logger.error(`No suitable mock file was found for ${mockFilePath}`);
callback(null, { error: `No suitable mock file was found for ${mockFilePath}` });
callback({ code: 5, message: `No suitable mock file was found for ${mockFilePath}` }, {});
}
} catch (error) {
logger.error(error);
callback(null, { error: error });
callback({ code: 10, message: error }, {});
}
};
/**
Expand Down Expand Up @@ -137,16 +148,26 @@ export default class GrpcParser {
const response = JSON.parse(fileContent);
const delay: number = response.delay || 0;
delete response.delay;
const error = response.error || null;
delete response.error
const metadata = response.metadata || null;
delete response.metadata;
const trailers = new grpc.Metadata();
if (metadata) {
for (const key in metadata) {
trailers.add(key, metadata[key])
}
}
setTimeout(() => {
callback(null, response);
callback(error, response, trailers);
}, delay);
} else {
logger.error(`No suitable mock file was found for ${mockFilePath}`);
callback(null, { error: `No suitable mock file was found for ${mockFilePath}` });
callback({ code: 5, error: `No suitable mock file was found for ${mockFilePath}` }, {});
}
} catch (error) {
logger.error(error);
callback(null, { error: error });
callback({ code: 10, message: error }, {});
}
});
};
Expand Down

0 comments on commit e789bfe

Please sign in to comment.