Skip to content

Commit

Permalink
Merge pull request #61 from notonthehighstreet/prefer-status
Browse files Browse the repository at this point in the history
support preferred status code as response
  • Loading branch information
yakovkhalinsky committed Jun 30, 2015
2 parents c23a70d + 3f9eec9 commit c2c85ad
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 13 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Due to protagonist parsing being async, we need to setup the middleware with an

**Q:** If I have multiple requests/responses on the same API endpoint, which response will I get?

**A:** Drakov will respond first with any responses that have a JSON schema with the first response matching the request body for that API endpoint.
**A:** Drakov will respond first with any responses that have a JSON schema with the first response matching the request body for that API endpoint. You can request a specific response by adding a `Prefer` header to the request in the form `Prefer:status=XXX` where `XXX` is the status code of the desired response.


**Q:** If I have multiple responses on a single request, which response will I get?
Expand Down
51 changes: 42 additions & 9 deletions lib/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,29 @@ function getMediaTypeFromSpecReq( specReq ) {
}

function getMediaTypeFromHttpReq( httpReq ) {
if( 'content-type' in httpReq.headers ) {
return getMediaType( httpReq.headers['content-type'] );
var contentTypeHeader = getHeaderFromHttpReq( httpReq, 'content-type' );
if( contentTypeHeader ) {
return getMediaType( contentTypeHeader );
}
return null;
}

function getPreferHeaderFromHttpReq( httpReq, preference ) {
var preferHeader = getHeaderFromHttpReq( httpReq, 'prefer' );
var preferenceRegExp = new RegExp(preference + '=(.*)', 'i');
var matchedStatus;
if ( preferHeader ) {
matchedStatus = preferHeader.match(preferenceRegExp);
if (matchedStatus) {
return matchedStatus[1];
}
}
return null;
}

function getHeaderFromHttpReq( httpReq, header ) {
if ( header in httpReq.headers ) {
return httpReq.headers[header];
}
return null;
}
Expand Down Expand Up @@ -123,16 +144,28 @@ function areContentTypesSame(httpMediaType, specMediaType) {
return false;
}

exports.matches = function( httpReq, specReq ) {
function isPreferredStatus(spec, preferredStatus) {
return spec.response.name === preferredStatus;
}

exports.matches = function( httpReq, spec ) {
var specReq = spec.request;
var httpMediaType = getMediaTypeFromHttpReq( httpReq );
var specMediaType = getMediaTypeFromSpecReq( specReq );
if ( areContentTypesSame(httpMediaType, specMediaType) ) {
if ( !hasHeaders( httpReq, specReq ) ){
return false;
}
var preferredStatus = getPreferHeaderFromHttpReq( httpReq, 'status' );

if ( !preferredStatus || isPreferredStatus(spec, preferredStatus) ) {
if (areContentTypesSame(httpMediaType, specMediaType)) {
if (!hasHeaders(httpReq, specReq)) {
return false;
}

if (isBodyEqual(httpReq, specReq, httpMediaType)) {
return true;
} else {
return false;
}

if ( isBodyEqual( httpReq, specReq, httpMediaType ) ) {
return true;
} else {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ exports.getRouteHandlers = function (method, parsedUrl, action) {
};

var matchRequests= function (specPair){
if (content.matches(req, specPair.request)) {
if (content.matches(req, specPair)) {
logger.log('[DRAKOV]'.red, action.method.green, parsedUrl.uriTemplate.yellow, (specPair.request && specPair.request.description ? specPair.request.description : action.name).blue);

specPair.response.headers.forEach(function (header) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "drakov",
"version": "0.1.7",
"version": "0.1.8",
"description": "Mock server that implements the API Blueprint specification",
"main": "./lib/drakov.js",
"bin": {
Expand Down
9 changes: 9 additions & 0 deletions test/api/multiple-examples-api-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ describe('/api/multiple', function(){
.expect({'second': 'response'})
.end(helper.endCb(done));
});

it('should respond with preferred status code', function(done) {
request.get('/api/multiple')
.set('Prefer', 'status=400')
.expect(400)
.expect('Content-type', 'application/json;charset=UTF-8')
.expect({'error': 'Bad request'})
.end(helper.endCb(done));
});
});

describe('POST', function(){
Expand Down
10 changes: 9 additions & 1 deletion test/example/md/multiple-examples-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ Second GET example with header
+ Body

{"second": "response"}

### Retrieve from GET [GET]
Get examples with a specific status code (eg. 400)

+ Response 400 (application/json;charset=UTF-8)

+ Body

{"error": "Bad request"}

### Post to the first example [POST]

Expand Down

0 comments on commit c2c85ad

Please sign in to comment.