Skip to content

How do I add different responses based on request GET parameters? #285

Closed

Description

@AndrewSad

So is there a way to make different responses for different parameters?
Im using Swifter to mock server responses and it would be great to response differently based on request’ GET parameters, but I can’t really figure how to add such responses

Activity

  1. basmaessen commented on Aug 20, 2018

    @basmaessen

    @AndrewSad Did you find any solution for this problem?

  2. AndrewSad commented on Aug 20, 2018

    @AndrewSad
    Author

    @basmaessen yes, turned out it was quite easy

  3. basmaessen commented on Aug 20, 2018

    @basmaessen

    @AndrewSad How did you do it?

  4. AndrewSad commented on Aug 21, 2018

    @AndrewSad
    Author

    I've added this method to HTTPDynamicStubs class:

    typealias DynamicStubParameterTuple = (name: String, value: String)?
    
    func mapStub(url: String, filename: String, method: HTTPMethod = .GET, to parameter: DynamicStubParameterTuple = nil) {
            
            let response: ((HttpRequest) -> HttpResponse) = { [weak self] request in
                guard parameter != nil, request.queryParams.contains(where: { $0 == parameter! }) else {
                    return HttpResponse.notFound
                }
                let testBundle = Bundle(for: type(of: self!))
                let filePath = testBundle.path(forResource: filename, ofType: "json")
                let fileUrl = URL(fileURLWithPath: filePath!)
                let data = try! Data(contentsOf: fileUrl, options: .uncached)
                let json = self?.dataToJSON(data: data)
                return HttpResponse.ok(.json(json as AnyObject))
            }
            
            switch method  {
            case .GET : server.GET[url] = response
            case .POST: server.POST[url] = response
            }
        }

    Usage:

    self.dynamicStubs.mapStub(url: "<your url goes here>", filename: "<here goes filename>", method: .GET, to: (<parameter name>, <parameter value>))
  5. andynovak12 commented on Feb 25, 2019

    @andynovak12

    @AndrewSad were you able to add 2 of the same urls that return different reponses based on the request parameters? I tried the above, and the second stub I setup overrides the previous one, and results in return HttpResponse.notFound when executing the first stub.

  6. AndrewSad commented on Feb 25, 2019

    @AndrewSad
    Author

    @andynovak12, actually I rewrote that piece since the time of my previous answer, will post solution in a bit

  7. andynovak12 commented on Feb 25, 2019

    @andynovak12

    Thank you @AndrewSad ! I am looking forward to seeing it.

  8. AndrewSad commented on Feb 26, 2019

    @AndrewSad
    Author

    So, method now goes like this:

    func mapStub(url: String, to mappedData: MappedFilenameToParameter, method: HTTPMethod = .GET) {
            
            let response: ((HttpRequest) -> HttpResponse) = { [weak self] request in
                
                guard let filename = self?.findFile(for: request, in: mappedData) else {
                    return HttpResponse.notFound
                }
                
                let testBundle = Bundle(for: type(of: self!))
                let filePath = testBundle.path(forResource: filename, ofType: "json")
                let fileUrl = URL(fileURLWithPath: filePath!)
                let data = try! Data(contentsOf: fileUrl, options: .uncached)
                let json = self?.dataToJSON(data: data)
                return HttpResponse.ok(.json(json as AnyObject))
            }
            switch method  {
            case .GET : server.GET[url] = response
            case .POST: server.POST[url] = response
            }
        }

    New 'magic' inside this function:

    private func findFile(for request: HttpRequest, in map: MappedFilenameToParameter) -> String? {
            for param in request.queryParams {
                if let filename = map[DynamicStubParameter(name: param.0, value: param.1)]  {
                    return filename
                }
            }
            return nil
        }

    New typealias:

    struct DynamicStubParameter: Hashable {
        var name = ""
        var value = ""
    }
    
    typealias MappedFilenameToParameter = [DynamicStubParameter:String]

    And usage:

    let someValues = [
                DynamicStubParameter(name:"<Field here>", value: "<Value>" ) : "<filename first JSON>",
                DynamicStubParameter(name:"<Same field>", value: "<Another value>" ) : "<filename second JSON>",
            ]
            self.dynamicStubs.mapStub(url: "<your URL here>", to: someValues, method: .GET)

    Notice: someValues is the name for our array of DynamicStubParameter values.

  9. andynovak12 commented on Feb 27, 2019

    @andynovak12

    Thanks so much for sharing @AndrewSad !
    This works for a request's body parameters as well, by replacing request.queryParams with String(bytes: request.body, encoding: .utf8)!, and handling if that String contains your required parameters.

  10. AndrewSad commented on Feb 27, 2019

    @AndrewSad
    Author

    You are welcome ;) Got through a lot of pain back in the day to solve this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions